编译官方原版的openwrt并加入第三方软件包

最近又重新编译了最新的官方原版openwrt-2305(2024.3.22),此处记录一下以待日后参考。

目录

1.源码下载

1.1 通过官网直接下载

1.2 映射github加速下载

1.2.1 使用github账号fork源码

1.2.2 创建gitee账号映射github openwrt

2.编译准备

2.1 编译环境依赖准备

2.2 make加速的准备

2.2.1 修改openwrt镜像源

2.2.2 提前下载依赖库到dl

2.2.3 提前安装镜像生成工具

2.2.4 下载feeds依赖

3.make menuconfig配置

3.1 选中目标CPU类型

3.2 选中镜像文件格式

4.make编译

4.1 编译错误解决

4.1.1 you should not run configure as root...

4.1.2 But that file is already provided by package...

5.加入第三方软件包

5.1 了解openwrt编译框架

5.1.1 包的引入

5.1.2 编写软件包的基本信息

5.1.3 定义编译操作

1.基本信息定义

2.编译选项TARGET_CFLAGS

3.编译选项TARGET_LDFLAGS

4.操作配置

Package/$(PKG_NAME)/description

Build/Prepare #自行开发或非直接下载包

Build/Configure

Build/Compile

Package/$(PKG_NAME)/install

5.2 引入第三方开源mstpd

5.2.1 下载软件包整理

5.2.2 编写Makefile

5.2.3 make menuconfig 使能 mstpd

5.2.4 单独编译mstpd

5.3 加入自己编写的软件包

5.3.1 按照openwrt规范路径

5.3.2 编写内部Makefile

5.3.3 编写外部Makefile

5.3.4 make menuconfig 使能tsmsq

5.3.5 单独编译tsmsq

6.编译openwrt镜像源VDI加载到virtualBox


1.源码下载

1.1 通过官网直接下载

[OpenWrt Wiki] Welcome to the OpenWrt Projecticon-default.png?t=N7T8https://openwrt.org/从上述官网地址进入,点击左侧 Downloads:点击【More】

点击进入,如下【Browse Source】

以上就是下载官方源码的git 地址,使用git clone即可下载

	git clone https://git.openwrt.org/openwrt/openwrt.git

1.2 映射github加速下载

由于官网下载太慢,参考了网上的方法,使用将github映射到gitee 的方式进行下载,速度能达10M/s,不过这只是下载编译框架的速度,编译过程中还会大量下载。

1.2.1 使用github账号fork源码

https://github.com/openwrt

首先注册账号,将openwrt项目fork到自己的repository,具体步骤此处不再赘述;

另外,为了在编译下载的时候主要package及其他组件下载能更快,建议同时将openwrt官方的 packages,luci,routing,telephony几个源码全部Fock过来。

1.2.2 创建gitee账号映射github openwrt

https://gitee.com/

使用上述地址注册账号,并从github导入仓库

导入后,即可通过git clone,通过【查看仓库】,选择HTTPS/【下载】,即可看到下载地址

如果在获取时出现错误,查看一下是不是仓库的权限是私有的。

2.编译准备

2.1 编译环境依赖准备

在Debian或Ubuntu系统,使用如下命令,准备编译环境依赖。

sudo apt-get update
sudo apt-get install subversion g++ zlib1g-dev build-essential git \
python python3 python3-distutils libncurses5-dev gawk gettext unzip \
file libssl-dev wget libelf-dev ecj fastjar java-propose-classpath

2.2 make加速的准备

2.2.1 修改openwrt镜像源

经过前面的步骤,把openwrt,packages,luci,routing,telephony的源码导入到自己的gitee仓库,现在把openwrt的镜像下载源给改成自己的gitee仓库地址。

修改feeds.conf.default文件,将里面的相关git地址改成gitee仓库地址。

src-git packages https://git.openwrt.org/feed/packages.git
src-git luci https://git.openwrt.org/project/luci.git
src-git routing https://git.openwrt.org/feed/routing.git
src-git telephony https://git.openwrt.org/feed/telephony.git
#src-git video https://github.com/openwrt/video.git
#src-git targets https://github.com/openwrt/targets.git
#src-git oldpackages http://git.openwrt.org/packages.git
#src-link custom /usr/src/openwrt/custom-feed

替换上述4个对应地址即可。

2.2.2 提前下载依赖库到dl

在menuconfig时,会选择自己目标的构架和cpu等信息,此时openwrt就会根据选择生成所需要的相对应的依赖库的文件信息,这个文件信息就放在openwrt目录下的tools目录里。tools目录里的每个目录就是所需要的依赖库文件下载信息。

每个目录下都有一个Makefile文件,这个文件里多数就写明了需要的文件名,文件版本,下载地址等信息,PKG_NAME就是文件名称,PKG_VERSION是文件版本,在后面会组合成一个.tar.xz或是tar.bz2的压缩包完整文件名。

我们可以通过在tools目录下grep 来查看软件包名,如下图所示,软件包名为组合后的地址。

其实除了tools依赖库,还有其他开源软件下载后也在此目录。

大多数依赖库包及第三方开源软件包都可以在如下地址找到

http://sources.cdn.openwrt.org/  --应该是国内镜像源,下载很快
http://sources.openwrt.org/    -- 全,但慢

针对openwrt 2305,我整理了依赖的tools库文件下载地址,部分地址无法访问,也从阿里云或其他第三方地址找到了替代。也可以自行从tools目录分析每个Makefile的下载地址及文件名。

可以直接到dl目录执行即可下载

wget https://fedorapeople.org/~acme/dwarves/dwarves-1.26.tar.bz2
wget http://sources.cdn.openwrt.org/patch-2.7.6.tar.gz
wget http://sources.cdn.openwrt.org/xz-5.4.6.tar.bz2
wget http://sources.cdn.openwrt.org/cmake-3.29.0.tar.gz
wget https://libisl.sourceforge.io/isl-0.26.tar.gz
wget http://sources.cdn.openwrt.org/lzop-1.04.tar.gz
wget http://sources.cdn.openwrt.org/m4-1.4.19.tar.gz
wget http://sources.cdn.openwrt.org/mtools-4.0.43.tar.bz2
wget http://sources.cdn.openwrt.org/lz4-1.9.4.tar.gz
wget http://sources.cdn.openwrt.org/mpc-1.3.1.tar.gz
wget http://sources.cdn.openwrt.org/ELFkickers-3.2.tar.gz
wget http://sources.cdn.openwrt.org/dosfstools-4.2.tar.gz
wget http://sources.cdn.openwrt.org/libressl-3.7.3.tar.gz
wget http://sources.cdn.openwrt.org/fakeroot_1.29.orig.tar.gz
wget http://sources.cdn.openwrt.org/quilt-0.67.tar.gz
wget http://sources.cdn.openwrt.org/zip30.tar.gz
wget http://sources.cdn.openwrt.org/elfutils-0.191.tar.bz2
wget https://mirrors.edge.kernel.org/pub/software/devel/sparse/dist/sparse-0.6.4.tar.gz
wget http://sources.cdn.openwrt.org/cpio-2.15.tar.bz2
wget https://mirrors.aliyun.com/gnu/coreutils/coreutils-9.5.tar.gz
wget http://sources.cdn.openwrt.org/ccache-4.9.1.tar.gz
wget http://sources.cdn.openwrt.org/flex-2.6.4.tar.gz
wget http://sources.cdn.openwrt.org/genext2fs-1.5.0.tar.gz
wget http://sources.cdn.openwrt.org/patchelf-0.18.0.tar.bz2
wget http://sources.cdn.openwrt.org/squashfs3.0.tar.gz
wget http://sources.cdn.openwrt.org/gmp-6.3.0.tar.gz
wget http://sources.cdn.openwrt.org/gengetopt-2.23.tar.xz
wget http://sources.cdn.openwrt.org/gnulib-c99c8d491850dc3a6e0b8604a2729d8bc5c0eff1.tar.gz
wget http://sources.cdn.openwrt.org/sed-4.9.tar.gz
wget http://sources.cdn.openwrt.org/automake-1.16.5.tar.gz
wget http://sources.cdn.openwrt.org/lzma-old-4.32.tar.bz2
wget http://sources.cdn.openwrt.org/mtd-utils-2.1.6.tar.bz2
wget http://sources.cdn.openwrt.org/zstd-1.5.6.tar.gz
wget http://sources.cdn.openwrt.org/libtool-2.4.7.tar.gz
wget http://sources.cdn.openwrt.org/tar-1.34.tar.gz
wget http://sources.cdn.openwrt.org/bc-1.07.1.tar.gz
wget http://sources.cdn.openwrt.org/u-boot-2024.01.tar.bz2
wget https://github.com/rui314/mold/archive/refs/tags/v2.30.0.tar.gz
wget http://sources.cdn.openwrt.org/expat-2.6.2.tar.gz
wget http://sources.cdn.openwrt.org/ninja-1.11.1.tar.gz
wget http://sources.cdn.openwrt.org/meson-1.3.2.tar.gz
wget http://sources.cdn.openwrt.org/bison-3.8.2.tar.gz
wget http://sources.cdn.openwrt.org/bash-5.2.21.tar.gz
wget http://sources.cdn.openwrt.org/mklibs_0.1.45.tar.xz
wget http://sources.cdn.openwrt.org/squashfs4-4.6.1.tar.xz
wget http://www.oberhumer.com/opensource/lzo/download/lzo-2.10.tar.gz
wget http://sources.cdn.openwrt.org/lzma-4.65.tar.bz2
wget http://sources.cdn.openwrt.org/elftosb-10.12.01.tar.gz
wget http://sources.cdn.openwrt.org/util-linux-2.39.3.tar.gz
wget http://sources.cdn.openwrt.org/zlib-1.3.1.tar.gz
wget http://sources.cdn.openwrt.org/mpfr-4.2.1.tar.gz
wget http://sources.cdn.openwrt.org/libdeflate-1.20.tar.gz
wget http://sources.cdn.openwrt.org/autoconf-archive-2023.02.20.tar.xz
wget http://sources.cdn.openwrt.org/bzip2-1.0.8.tar.gz
wget http://sources.cdn.openwrt.org/autoconf-2.71.tar.gz
wget http://sources.cdn.openwrt.org/findutils-4.9.0.tar.xz
wget http://sources.cdn.openwrt.org/e2fsprogs-1.47.0.tar.gz
wget http://sources.cdn.openwrt.org/pkgconf-2.1.1.tar.gz
wget http://sources.cdn.openwrt.org/imx-uuc-2018-11-18-c6536ac5.tar.xz 
wget http://sources.cdn.openwrt.org/cbootimage-1.8.tar.xz
wget https://github.com/llvm/llvm-project/releases/download/llvmorg-15.0.7/llvm-project-15.0.7.src.tar.xz
wget http://sources.cdn.openwrt.org/kernel2minor-0.25.tar.xz
wget http://sources.cdn.openwrt.org/make-ext4fs-2020-01-05-5c201be7.tar.xz
wget http://sources.cdn.openwrt.org/7z2301-src.tar.xz

通过提前下载依赖包,能减少在编译时一些默认地址下载的时间,默认地址下载有的不可用,有的为官方地址,下载很慢。

2.2.3 提前安装镜像生成工具

打包的时候,会用到qemu-img,如不提前安装,编译到最后会报如下错误,并终止。

WARNING: Install qemu-img to create VDI/VMDK images

下载安装

apt search qemu-img   --- 查找文件名
apt install qemu-utils   -- 得到文件名,install

2.2.4 下载feeds依赖

./scripts/feeds update -a
./scripts/feeds install -a

如果报错,解决报错,举例如下,此为编译构建环境错误

Build dependency: Please install the Python3 distutils module

使用如下安装,其余类似

apt-get install python3-distutils
apt-get install rsync

解决报错后,重复指向 update 和install,直至无报错。

3.make menuconfig配置

编译准备工作完成后,接下来就可以配置进行编译了。

只需简单的几步,就可以开始编译。

此处,我们使用x86虚拟机进行测试,因此,编译目标系统选择x86 64

3.1 选中目标CPU类型

3.2 选中镜像文件格式

目标镜像文件输出,我们选VDI,方便在virtualBox虚拟机创建。

此外,如无需http服务,那么Luci选项可以使用默认,无需勾选。如需勾选,可以在menuconfig界面输入"/"来进行uhttp依赖关系查找。

4.make编译

为了加快编译速度,我们使用-j参数指定线程数。如:

make -j8

即便我们提前准备了软件包,依赖库,真正编译的时候,还是会下载很多东西,等待很长时间,完整编译结束,整个openwrt大小超过12GB

4.1 编译错误解决

4.1.1 you should not run configure as root...

 “you should not run configure as root (set FORCE_UNSAFE_CONFIGURE=1 in environment)

在编译buildroot的时候出现了此错误,表示不能使用root权限编译

根据提示,在网上查,说是export set FORCE_UNSAFE_CONFIGURE=1能够解决问题

但我在终端上输入还是报错,后来才知道是要添加到/etc/profile文件中设置全局才有效

执行:

echo "export set FORCE_UNSAFE_CONFIGURE=1"  >> /etc/profile
source /etc/profile

最好重启终端

如果还是不行,看看是否存在~/profile文件,如果存在,在~/profile中也添加相应内容

4.1.2 But that file is already provided by package...

Configuring urngd.
Configuring ppp-mod-pppoe.
Collected errors:* check_data_file_clashes: Package libustream-openssl20201210 wants to install file /home/openwrt/build_dir/target-i386_pentium4_musl/root-x86/lib/libustream-ssl.soBut that file is already provided by package  * libustream-wolfssl20201210* opkg_install_cmd: Cannot install package libustream-openssl20201210.* check_data_file_clashes: Package libustream-openssl20201210 wants to install file /home/openwrt/build_dir/target-i386_pentium4_musl/root-x86/lib/libustream-ssl.so

以上报错,是表示libustream-openssl 与libustream-wolfss冲突

查看.config 发现两个都开启了,通过make menuconfig  将libustream-wolfssl 去除选中即可。

注意,去除libustream-wolfss 时需要将依赖的其他包去除,如果想知道被哪些包依赖,通过help 查看,被luci-ssl依赖。

5.加入第三方软件包

openwrt 是一个编译工具,帮助自定义编译内核和应用(是否可以这么理解理解)。所以如果有定制自己需要的内核,并基于这个定制化内核编译一些应用的话,可以使用openwrt,openwrt 还是很成熟,很方便的。

openwrt是一个比较完善的嵌入式Linux开发平台,在无线路由器应用上已有100多个软件包。人们可以在其基础上增加软件包,以扩大其应用范围。OpenWrt在增加软件方面使用极其方便,按照OpenWrt的约定就可以很简单完成。
加入的软件包可以是网上可下载的开源软件或自行开发的软件。为加入软件包需要在package目录下创建一个目录,以包含软件包的各种信息和与OpenWrt建立联系的文件。然后创建一个Makefile与OpenWrt建立联系,Makefile需要遵循OpenWrt的约定。另外可以创建一个patchs目录保存patch文件,对下载的源代码进行适量修改。

5.1 了解openwrt编译框架

在加入第三方开源软件包之前,我们先了解openwrt的编译框架。这里不做编译框架介绍,实际也不需要了解过深,除非需要调整框架内容。因此我们只需了解如何使得openwrt能够识别我们加入的软件包并调提供的Makefile编译出我们所需的软件即可。

需要编译第三方的软件(驱动、库等),只需要按照openwrt 的规则,安排好源码的路径结构,稍微改下 makefile 等文件,使openwrt 能够识别你的软件,就可以了,其实还是很简单的。

        一般是这样:

                在package/libs(对于库)、package/kernel/(对于驱动)、package/utils(应用软件) 路径下,创建一个文件夹,里面放你的代码,结构如下:

                Makefile 和 src/ 

                Makefile 我在后面会根据软件类型不同贴出来。

                src里面就放你的源码。

                src 有些会自带Makefile ,没关系,不需要对它进行修改。比如src/Makefile 里面指定了编译器:CC=gcc,没事啊,外面的Makefile 也会指定openwrt 的编译器,并覆盖内层Makefile 中的配置。

        这些填好后,去make menuconfig 里面勾选上这个软件,就可以开始编译了

5.1.1 包的引入

OpenWrt软件包规则中使用三个makefile的子文件,分别为:

include $(TOPDIR)/rules.mk      #一般在Makefile的开头
include $(INCLUDE_DIR)/kernel.mk    # 对于软件包为内核时不可缺少
include $(INCLUDE_DIR)/package.mk  # 一般软件包

软件包加入OpenWrt的方式就由这些makefile所决定,一般软件包使用package.mk

5.1.2 编写软件包的基本信息

以下为软件包定义的一些关键字,软件包可以自己下载整理目录结构后加入openwrt,也可以在Makefile中定义软件包的下载方式和,但下载时一般需要核对MD5,需要提前计算MD5填入。建议自己下载整理路径后加入。

PKG_NAME     表示软件包名称,将在menuconfig和ipkg可以看到。
PKG_VERSION      表示软件版本号。
PKG_RELEASE      表示Makefile的版本号
PKG_SOURCE       表示源代码的文件名。
PKG_SOURCE_URL     表示源代码的下载网站位置。@SF表示在sourceforge网站,@GNU表示在GNU网站,还有@GNOME、@KERNEL。获取方式可以为:git、svn、cvs、hg、bzr等。下载规则定义在:$(INCLUDE_DIR)/download.mk和$(SCRIPT_DIR)/download.pl中
PKG_MD5SUM     表示源代码文件的效验码。用于核对软件包是否正确下载。
PKG_CAT     表示源代码文件的解压方法。包括zcat, bzcat, unzip等。
PKG_BUILD_DIR     表示软件包编译目录。它的父目录为$(BUILD_DIR)。如果不指定,默认为$(BUILD_DIR)/$( PKG_NAME)$( PKG_VERSION)。
PKG_INSTALL     Setting it to ‘1’ will call the package’s original  ‘make install’  with prefix set to ‘PKG_INSTALL_DIR’
PKG_INSTALL_DIR    Where ‘make install’ copies the compiled files
PKG_FIXUP    关于autotools的选项。软件源码中的makefile使用makefile工具自动生成

5.1.3 定义编译操作

用户程序和内核模块的定义不一样。用户态软件包使用Package,内核模块使用KernelPackage。

这里只说明用户模块程序定义。

用户程序的编译包以Package/开头,然后接着软件名,在Package定义中的软件名可以与软件包名不一样,而且可以多个定义。

以下介绍主要的定义:

1.基本信息定义
Package/$(PKG_NAME)
SECTION    表示包的类型,预留。
CATEGORY    表示分类,在menuconfig的菜单下将可以找到。
TITLE    用于软件包的简短描述
DESCRIPTION    用于软件包的详细描述,已放弃使用。如果使用DESCRIPTION将会提示“error DESCRIPTION:= is obsolete, use Package/PKG_NAME/description”。
URL    表示软件包的下载网址。
MAINTAINER    表示维护者,选项。
DEPENDS    表示与其他库文件的依赖。即如编译或安装需要其他软件时需要说明。如果存在多个依赖,则每个依赖需用空格分开。依赖前使用+号表示默认显示,即对象没有选中时也会显示,使用@则默认为不显示,即当依赖对象选中后才显示。
2.编译选项TARGET_CFLAGS

GCC编译选项CFLAGS参数,CFLAGS与LDFLAGS的说明,他们都是是隐含规则的变量,且是一种命令参数变量。

如果在编译时,需要包含特定路径头文件,如:程序包内当前目录include ,可以使用-I./include , 将该目录加入 include路径。

3.编译选项TARGET_LDFLAGS

该选项一般较多使用-I来链接动态库或静态库。

如层序中需要链接libpthread和libc.so,则可使用  LDFLAGS += -pthread -lc

该选项配合基本信息定义中的 DEPENDS 来使用,例如

TARGET_LDFLAGS += -pthread -lc

...

DEPENDS:=+libpthread +libc

4.操作配置
  • Package/$(PKG_NAME)/description

软件包的详细描述,取代前面提到的DESCRIPTION详细描述。

  • Build/Prepare #自行开发或非直接下载包

编译准备方法,对于网上下载的软件包不需要再描述。对于非网上下载或自行开发的软件包必须说明编译准备方法。一般的准备方法为:注意:PKG_BUILD_DIR为openwrt/build_dir/<软件包路径名>/ ,默认情况下,此处的<软件包路径名>为$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)

也可以在Makefile中重新定义,如PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)

(按OpenWrt的习惯,一般把自己设计的程序全部放在src目录下)

define Build/Preparemkdir -p $(PKG_BUILD_DIR)$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
  • Build/Configure

在Automake中需要进行./configure,所以本配置方法主要针对需要配置的软件包而设计,一般自行开发的软件包可以不在这里说明。需要使用本定义的情况,可参考dropbear。

  • Build/Compile

编译方法,没有特别说明的可以不予以定义。如果不定义将使用默认的编译方法Build/Compile/Default

自行开发的软件包可以考虑使用下面的定义,也可以不定义。

define Build/Compile$(MAKE) -C $(PKG_BUILD_DIR) \$(TARGET_CONFIGURE_OPTS) CFLAGS="$(TARGET_CFLAGS) -I$(LINUX_DIR)/include"
endef
  • Package/$(PKG_NAME)/install

软件包的安装方法,包括一系列拷贝编译好的文件到指定位置。调用时会带一个参数,就是嵌入系统的镜像文件系统目录,因此$(1)表示嵌入系统的镜像目录。一般可以采用下面的方法:

define Package/$(PKG_NAME)/install$(INSTALL_DIR) $(1)/usr/bin$(INSTALL_BIN) $(PKG_BUILD_DIR)/ $(PKG_NAME) $(1)/usr/bin/
Endef

    INSTALL_DIR、INSTALL_BIN在 $(TOPDIR)/rules.mk 文件定义,所以本Makefile必须导入 $(TOPDIR)/rules.mk 文件。
    INSTALL_DIR :=install -d -m0755 意思创建所属用户可读写即执行,其他用户可读可执行的目录。
    INSTALL_BIN:=install -m0755意思编译好的文件到镜像文件目录。
    类似的PKG_BUILD_DIR、PKG_INSTALL_DIR 等都在 $(TOPDIR)/rules.mk 、 $(INCLUDE_DIR)/package.mk中可以找到定义.

自启动安装定义

如果用户态软件在boot时要自动运行,则需要在安装方法说明中增加自动运行的脚本文件安装和配置文件安装方法。自启动路径在/etc/init.d。具体编写规则,可参考netifd特性。

举例如下。

define Package/mstpd/install$(INSTALL_DIR) $(1)/usr/sbin $(1)/etc/init.d $(1)/sbin/$(INSTALL_BIN) ./files/mstpd.init $(1)/etc/init.d/mstpd$(INSTALL_BIN) $(PKG_BUILD_DIR)/mstpd $(1)/usr/sbin/$(INSTALL_BIN) $(PKG_BUILD_DIR)/mstpctl $(1)/usr/sbin/$(INSTALL_BIN) $(PKG_BUILD_DIR)/bridge-stp $(1)/sbin/
endef

非程序本身的安装文件建议放在files子目录下,不要与源代码文件目录src混在一起,以提高可读性,使用清晰的文件扩展名,更方便安装识别文件。

5.2 引入第三方开源mstpd

这里以mstpd为例

Mstp为开源的生成树实现,openwrt默认并没有自带,因此,需要从第三方下载软件包并编译。

5.2.1 下载软件包整理

http://sources.cdn.openwrt.org/

从上述地址下载 mstpd-0.1.0.tar.gz 解压,此处我解压并重命名为mstpd.将解压的文件进行重新整理:目的是为了后续在openwrt 的menuconfig中识别。

如下图,创建src目录,将解压的所有文件全部移动到src内(Makefile后续编写,files为自启动文件,如无需可以不管。)

将整理好的mstpd目录放入openwrt\package\utils\下

5.2.2 编写Makefile

在编写Makefile之前,先查看mstpd原有的Makefile。这里发现,没有Makefile,但有Makefile.am,这个像是Makefile但为什么带后缀am呢?automake。

automake 读取 Makefile.am 来产生 Makefile.in,
configure 读取 Makefile.in 来产生 Makefile
configure 脚本通常由 autoconf 读取 configure.in 产生
还有aclocal....
目的就是让程序员只写一个规则:.am文件/或.in文件,
就能生成适合各种配置/平台的Makfiles。

在【编写软件包的基本信息】中,我们了解了automake定义选项 PKG_FIXUP

因此,此处如果不想自己编写依赖关系Makefile包,就需要使用该选项,重新进行Makefile的生成。以下贴出mstpd的Makefile。

include $(TOPDIR)/rules.mkPKG_NAME:=mstpd
PKG_VERSION:=0.1.0
PKG_RELEASE:=1#PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz 
#PKG_SOURCE_URL:=http://sources.cdn.openwrt.org/
#PKG_MD5SUM:=PKG_INSTALL:=1
PKG_BUILD_PARALLEL:=1
PKG_FIXUP:=autoreconf
#PKG_LICENSE:include $(INCLUDE_DIR)/package.mkdefine Package/mstpd
#SECTION 软件包类型SECTION:=utils
#CATEGORY menuconfig中软件包所属的一级目录,如NetworkCATEGORY:=Utilities
#SUBMENU - menuconfig中软件包所属的二级目录,如dial-in/up
#SUBMENU:=TITLE:=mstpdDEPENDS:=+libpthread 
endefdefine Package/mstpd/descriptionmstpd is added by me
endefTARGET_CFLAGS +=#定义make prepare 动作
define Build/Preparemkdir -p $(PKG_BUILD_DIR)$(CP) ./src/* $(PKG_BUILD_DIR)
#$(CP) ./files/* $(PKG_BUILD_DIR)
endef#define Build/InstallDev
#	$(INSTALL_DIR) $(1)/usr
#	$(CP) $(PKG_INSTALL_DIR)/usr/local/* $(1)/usr/
#endefdefine Package/mstpd/install$(INSTALL_DIR) $(1)/usr/sbin $(1)/etc/init.d $(1)/sbin/$(INSTALL_BIN) ./files/mstpd.init $(1)/etc/init.d/mstpd$(INSTALL_BIN) $(PKG_BUILD_DIR)/mstpd $(1)/usr/sbin/$(INSTALL_BIN) $(PKG_BUILD_DIR)/mstpctl $(1)/usr/sbin/$(INSTALL_BIN) $(PKG_BUILD_DIR)/bridge-stp $(1)/sbin/
endef$(eval $(call BuildPackage,mstpd))

5.2.3 make menuconfig 使能 mstpd

如果目录结构及Makefile定义正确,我们应该能在make menuconfig 中找到mstpd,根据路径使能即可。

我们只需要进入Utilities选中打开即可。

5.2.4 单独编译mstpd

make package/utils/mstpd/compile V=s

等待编译通过。如提示

*** No targets specified and no makefile found.  Stop.

可能是你的目录结构不对,或者Makefile未指定autoreconf参数。

5.3 加入自己编写的软件包

5.3.1 按照openwrt规范路径

此demo(tsmsq)的功能是server端与client端各启一个线程,子线程分别使用消息队列在server与client端进行通信,server端发,client端收。大致结构如下。

软件代码包请到我的资源下载tsmsq

find package/utils/tsmsq/ -type d

package/utils/tsmsq/

package/utils/tsmsq/src

package/utils/tsmsq/src/include -- 公共头文件

package/utils/tsmsq/src/server -- server端源码

package/utils/tsmsq/src/utils -- 公用接口如消息队列,文件操作,字符串操作,时间函数等

package/utils/tsmsq/src/utils/lib -- 用于生成共享库(动态库)

package/utils/tsmsq/src/client -- server 端源码

5.3.2 编写内部Makefile

外部Makefile其实是一套框架,该框架调用了build_dir/tsmsq下的Makefile生成目标文件,并对目标文件进行打包。因此我们主要工作在内部Makefile实现。Makefile对于我来说,仅停留在能简单阅读修改的程度,对于多目录,多文件,动态库的Makefile,编写起来还是有些费劲(其实是我太菜)。好在之前学习过一套简单的CMake,Cmake可以根据不同平台生成对应的Makefile,而且语法相对较简单,因此,我们可以借助Cmake帮我们生成Makefile。我们只需编写CMakeList.txt就可以生成高质量的Makefile。

按照上述目录结构,我们的外层CmakeList.txt如下:

为了能看明白一点,其中有很多注释,关注未注释部分即可。关于cmake的一些语法及关键字,请自行bing。

cmake_minimum_required(VERSION 2.6)PROJECT(tsmsq)SET(CLIEN_NAME tsmsqcl)
SET(SERVER_NAME tsmsqsv)SET(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
#ADD_DEFINITIONS(-l/usr/local/lib/)#引用头文件,对于集中的头文件,CMake提供了一个很方便的函数include_directories ( dir ) 作用是 自动去dir目录下寻找头文件,相当于 gcc中的 gcc -I dir
INCLUDE_DIRECTORIES(/usr/local/include /usr/local/lib ./include)# 添加一个子目录
#add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL] [SYSTEM])
#添加同级及其子目录,可省略binary_dir参数
#添加父级及其子目录,必须指定用于存储输出文件的binary_dir参数。否则报如下错误
#add_subdirectory not given a binary directory but the given source directory "xxx" is not a subdirectory of "xxx".  
#When specifying an out-of-tree source a binary directory must be explicitly specified.# add_subdirectory (source_dir [binary_dir] [EXCLUDE_FROM_ALL]) 添加子目录并构建该子目录
#	source_dir
#必选参数。该参数指定一个子目录,子目录下应该包含CMakeLists.txt文件和代码文件。子目录可以是相对路径也可以是绝对路径,如果是相对路径,则是相对当前目录的一个相对路径。
#	binary_dir
#可选参数。该参数指定一个目录,用于存放输出文件。可以是相对路径也可以是绝对路径,如果是相对路径,则是相对当前输出目录的一个相对路径。如果该参数没有指定,则默认的输出目录使用source_dir。
#	EXCLUDE_FROM_ALL
#可选参数。当指定了该参数,则子目录下的目标不会被父目录下的目标文件包含进去,父目录的CMakeLists.txt不会构建子目录的目标文件,必须在子目录下显式去构建。例外情况:当父目录的目标依赖于子目录的目标,则子目录的目标仍然会被构建出来以满足依赖关系(例如使用了target_link_libraries)。
add_subdirectory(./utils ./utils/lib)#支持gdb
set(CMAKE_BUILD_TYPE "Debug")
set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")
set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")#aux_source_directory(dir var) 作用是把dir目录中的所有源文件都储存在var变量中,然后需要用到源文件的地方用 变量var来取代
AUX_SOURCE_DIRECTORY(./ SRC_MAIN)
AUX_SOURCE_DIRECTORY(./client SRC_CL)
AUX_SOURCE_DIRECTORY(./server SRC_SR)
AUX_SOURCE_DIRECTORY(./utils SRC_UTILS)# add_library(test_utils STATIC/SHARED ${SRC_UTILS})添加lib哭,动态库或者静态库, 不指定第二个参数默认为静态库
#SET(LIBRARY_OUTPUT_PATH ${EXECUTABLE_OUTPUT_PATH})  #LIBRARY_OUTPUT_PATH 是cmake系统变量,项目生成的库文件都放在这个目录下
#add_library(test_utils SHARED ${SRC_UTILS})  # 也可以通过  add_subdirectory(.//utils .//utils/lib)  构建子目录来生成lib# 第一个参数,存储查找到的库文件,第二个参数:要查找的库文件,第三个参数:查找路径
#find_library(UTIL_LIB test_utils ./utils/lib)  #这里是动态库#指定了项目名后,后面可能会有多个地方用到这个项目名,如果更改了这个名字,就要改多个地方,比较麻烦,可以使用 PROJECT_NAME 来表示项目名。
ADD_EXECUTABLE(${SERVER_NAME} ${SRC_MAIN} ${SRC_SR})
TARGET_LINK_LIBRARIES(${SERVER_NAME} pthread test_utils)ADD_EXECUTABLE(${CLIEN_NAME} ${SRC_MAIN} ${SRC_CL})
TARGET_LINK_LIBRARIES(${CLIEN_NAME} pthread test_utils)#add_library(lib_name STATIC/SHARED src) 
# 函数作用:生成库。
# 参数lib_name:是要生成的库名称,
# 参数STATIC/SHARED:指定生成静态库或动态库,
# 参数src:指明库的生成所需要的源文件#install(TARGETS mylibrary DESTINATION lib)   TARGETS 参数指定了要安装的目标(通常是一个已经通过 add_library() 或 add_executable() 定义的目标),DESTINATION 参数指定了目标的安装位置
#安装一个目标库到指定的目录 install(TARGETS mylibrary DESTINATION lib)
#安装目录及其子目录 install(DIRECTORY ${CMAKE_SOURCE_DIR}/mydir DESTINATION share/mydir)
#文件匹配与过滤 install(DIRECTORY ${CMAKE_SOURCE_DIR}/mydir DESTINATION share/mydir FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp")
install(TARGETS ${SERVER_NAME} DESTINATION bin)
install(TARGETS ${CLIEN_NAME} DESTINATION bin)
install(TARGETS test_utils DESTINATION lib)

由于本例子还生成了动态库,因此,这里也是一个cmake学习的良好例子,通过上述外层的CmakeList.txt,指定了内部lib的路径,内部lib依赖的源文件在utils目录下,因此,可以在该路径定义一个内部的CmakeList.txt,指定lib依赖的文件,生成的方式与路径。完整内容如下:

set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../)
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_LIB_SRCS 变量
aux_source_directory(. DIR_LIB_SRCS)# 生成链接库  静态库
#add_library (count ${DIR_LIB_SRCS})
add_library (test_utils SHARED ${DIR_LIB_SRCS})

5.3.3 编写外部Makefile

外部的Makefile按照基本框架填充即可。

由于该例子使用了pthread,因此依赖pthread库,还有libc库。以下Makefile中通过LDFLAGS指定了链接库文件。

另外,因为我们使用的是cmake,因此,为了是openwrt能正确帮助我们生成Makefile,我们在定义基本信息的时候,包含进cmake.mk。

include $(INCLUDE_DIR)/cmake.mk

完整例子如下。

include $(TOPDIR)/rules.mkPKG_NAME:=tsmsq
PKG_VERSION:=1.0
PKG_RELEASE:=1#PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz 
#PKG_SOURCE_URL:=http://sources.cdn.openwrt.org/
#PKG_MD5SUM:=PKG_INSTALL:=1
PKG_BUILD_PARALLEL:=1
#PKG_FIXUP:=autoreconf
#PKG_LICENSE:
#TARGET_CFLAGS +=
TARGET_LDFLAGS += -pthread -lcinclude $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/cmake.mkdefine Package/tsmsq
#SECTION 软件包类型SECTION:=utils
#CATEGORY menuconfig中软件包所属的一级目录,如NetworkCATEGORY:=Utilities
#SUBMENU - menuconfig中软件包所属的二级目录,如dial-in/up
#SUBMENU:=TITLE:=tsmsqDEPENDS:=+libpthread +libc
endefdefine Package/tsmsq/descriptiontsmsq is added by me
endef#定义make prepare 动作
define Build/Preparemkdir -p $(PKG_BUILD_DIR)$(CP) ./src/* $(PKG_BUILD_DIR)/
#cmake $(PKG_BUILD_DIR)/ -B $(PKG_BUILD_DIR)/
#$(CP) ./files/* $(PKG_BUILD_DIR)
endef#define Build/InstallDev
#	$(INSTALL_DIR) $(1)/usr
#	$(CP) $(PKG_INSTALL_DIR)/usr/local/* $(1)/usr/
#endefdefine Package/tsmsq/install$(INSTALL_DIR) $(1)/usr/sbin $(1)/usr/lib$(INSTALL_BIN) $(PKG_BUILD_DIR)/tsmsqcl $(1)/usr/sbin/$(INSTALL_BIN) $(PKG_BUILD_DIR)/tsmsqsv $(1)/usr/sbin/$(INSTALL_BIN) $(PKG_BUILD_DIR)/libtest_utils.so $(1)/usr/lib/
endef$(eval $(call BuildPackage,tsmsq))

5.3.4 make menuconfig 使能tsmsq

在make menuconfig 界面,按下“/” 可输入内容查找tsmsq,如能找到,说明我们的目录及Makefile定义没有问题。选中打开即可。

5.3.5 单独编译tsmsq

make package/utils/tsmsq/compile V=s

如果编译通过,应该会生成目标文件:

至此,我们基本完成了openwrt的整体编译过程。

6.编译openwrt镜像源VDI加载到virtualBox

此处编译的是x86,VDI镜像文件,用于virtualBox加载,目标文件路\openwrt\bin\targets\x86\generic

如果没有virtualBox,先安装virtualBox Oracle VM VirtualBox

以下简单介绍如何在virtualBox虚拟机加载openwrt。

如下,点击【新建】输入名称,选中类型linux。

虚拟硬盘选中使用已有,选择openwrt vdi镜像源。

加载完成后,我们对openwrt_2305进行一些设置。

设置串口,主机管道,可以通过串口访问openwrt系统(默认的窗口终端不好使用)。

串口路径地址格式

\\.\pipe\openwrt_2305

至此,我们完成了openwrt编译,并加入第三方软件包的全部过程,在Makefile中定义的安装目录下,可以找到我们添加的mstpd与tsmsq相关的 可执行文件及lib动态库。

在编译openwrt的过程中,很多东西其实是不求甚解的,理解肯定存在不足与未验证之处。但好在openwrt的框架十分完善,让我们在定制化开发过程中能够通过简单的几步就能构建自己的linux定制系统。

同时也参考了很多优秀的博文,列出如下:

openwrt 编译外部源码 过程与问题解决_openwrt 编译第三方库-CSDN博客

OpenWrt开发 之扩展软件包_openwrt pkg_fixup-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/8684.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ChatGPT DALL-E绘图,制作各种表情包,实现穿衣风格的自由切换

DALL-E绘图功能探索&#xff1a; 1、保持人物形象一致&#xff0c;适配更多的表情、动作 2、改变穿衣风格 3、小女孩的不同年龄段展示 4、不同社交平台的个性头像创作 如果不会写代码&#xff0c;可以问GPT。使用地址&#xff1a;我的GPT4 视频&#xff0c;B站会发&#…

yolov8任务之目标检测

对象检测 对象检测是一项涉及识别图像或视频流中对象的位置和类别的任务。对象检测器的输出是一组包围图像中对象的边界框&#xff0c;以及每个框的类标签和置信度分数。当您需要识别场景中感兴趣的对象&#xff0c;但不需要确切知道对象在哪里或其确切形状时&#xff0c;对象检…

我独自升级崛起账号注册 我独自升级怎么注册账号

近期&#xff0c;《我独自升级》这部动画凭借爆棚的人气&#xff0c;在各大平台上掀起了一阵观看热潮&#xff0c;其影响力不容小觑。借此时机&#xff0c;韩国游戏巨头网石集团敏捷响应&#xff0c;顺势推出了同名游戏《我独自升级&#xff1a;ARISE》&#xff0c;为粉丝们搭建…

关闭vscode保存自动格式化的功能

1 首先打开设置 搜索&#xff1a;editor.formatOnSave 取消勾选框 2 再打开 settings.json 搜索 editor 找到 settings.json 设置&#xff1a; "editor.formatOnSave": false

算法day02

1、202. 快乐数 如上题所述&#xff1a; 在该题意规则下&#xff0c;所有的数字变化会有两种情况&#xff0c;其一最后是有的会变化成恒为1的数&#xff1b;其二是有的数会变化会呈现成有规律的环&#xff0c;分别如下图所示&#xff1a; 可以近似的理解为图一就是一个环&#…

JVM堆内存分析

jmap工具查看堆内存 jmap:全称JVM Memory Map 是一个可以输出所有内存中对象的工具&#xff0c;可以将JVM中的heap&#xff08;堆&#xff09;&#xff0c;以二进制输出成文本&#xff0c;打印出Java进程对应的内存 找到pid jmap -heap 19792 Attaching to process ID 19792…

(十五)Java 之方法

目录 一. 前言 二. Java 方法 2.1. 什么是方法 2.2. 方法的定义 2.3. 方法的调用 2.4. void 关键字 2.5. 通过值传递参数 2.6. 方法的重载 2.7. 变量作用域 2.8. 命令行参数的使用 2.9. 构造方法 2.10. 可变参数 2.11. finalize() 方法 三. 课后习题 一. 前言 方…

[Redis] 使用布隆过滤器和分布式锁实现用户注册

布隆过滤器&#xff08;Bloom Filter&#xff09;是一种数据结构&#xff0c;用于快速判断一个元素是否可能存在于一个集合中。它通过使用多个哈希函数和一个位数组来表示一个集合&#xff0c;当一个元素被加入到集合时&#xff0c;通过哈希函数计算出多个哈希值&#xff0c;并…

怎么清理服务器的C盘?

有时候我们经常会遇到C盘被占满的情况&#xff0c;C盘被占满的原因有很多&#xff0c;下面我们就来分析下有可能导致C盘占满的原因&#xff1a; 第一种情况&#xff1a;中毒 打开服务器任务管理器选择进程&#xff0c;并且勾选显示所有用户的进程&#xff0c;我们可以点击映像…

Fastgpt知识库接入oneapi和自定义大模型

本期教程教大家训练自己的知识库回答chatgpt回答不了的问题 FastGPT 是一个知识库问答系统,可以通过调用大模型和知识库回答特定的问题 可以做成专属 AI 客服集成到现有的APP或者网站内当作智能客服支持网络爬虫学习互联网上的很多知识可以通过flow可视化进行工作流程编排 本期…

【spark】win10 pyspark3.5.1 安装超级简单

下载地址&#xff1a;https://spark.apache.org/downloads.html 下载完成&#xff1a; 复制文件到自己的路径下&#xff0c;路径最好不要有中文、空格&#xff1b; 解压tgz文件&#xff1a; 修改环境变量&#xff1a; 创建SPARK_HOME&#xff1a; D:\software_download\spar…

Facebook之道:探索社交媒体领域的未来

随着科技的不断发展&#xff0c;社交媒体已经成为我们日常生活中不可或缺的一部分。而在这个领域中&#xff0c;Facebook一直是引领者和领头羊。然而&#xff0c;随着时间的推移&#xff0c;社交媒体领域正在发生着翻天覆地的变化&#xff0c;而Facebook又将何去何从&#xff1…

【Python】在Windows Server上部署Flask后端服务器

想要在Windows Server上部署flask应用&#xff0c;当然不能只下一个anaconda配完环境之后直接启动py文件&#xff0c;这样的话后台会有一段警告&#xff1a; * Serving Flask app app* Debug mode: off WARNING: This is a development server. Do not use it in a production …

攻略:ChatGPT3.5~4.0(中文版)国内无限制免费版(附网址)【2024年5月最新更新】

一、什么是ChatGPT&#xff1f; 1、ChatGPT的全名是Chat Generative Pre-trained Transformer&#xff0c;其中"chat"表示聊天。"GPT"则是由三部分组成&#xff1a;生成式&#xff08;generative&#xff09;意味着具有创造力&#xff1b;预训练&#xff0…

跟我学做零售数据分析报表-商品滞销分析

商品滞销的情况很常见&#xff0c;因此商品滞销分析也是基本属于零售数据分析标配内容之一。那么&#xff0c;商品滞销分析报表该怎么做&#xff1f;要做计算哪些指标&#xff0c;怎么分析滞销趋势&#xff1f;别急&#xff0c;奥威BI零售数据分析方案预设了一张BI商品滞销分析…

FreeRTOS(随便写写,项目用到)

FreeRTOS是什么&#xff08;并发&#xff09; RTOS&#xff08;Real Time Operating System&#xff0c;中文就是实时操作系统&#xff09; FreeRTOS是一个迷你的实时操作系统内核。 作为一个轻量级的操作系统&#xff0c;功能包括&#xff1a;任务管理、时间管理、信号…

citylava:城市场景中VLMs的有效微调

citylava:城市场景中VLMs的有效微调 摘要IntroductionRelated WorkVision-Language ModelsVLMs in Driving Methodology CityLLaVA: Efficient Fine-Tuning for VLMs in City Scenario 摘要 在城市广阔且动态的场景中&#xff0c;交通安全描述与分析在从保险检查到事故预防的各…

蓝牙 | 软件:Git管理高通的ChipCode项目

哈喽大家好&#xff0c;最近发现大家在高通chipcode网站上下载不了代码&#xff0c;小编一直使用git的方式获取新版本代码&#xff0c;没有遇到什么阻碍。于是小编到新主机上尝试下载代码的压缩包和git代码&#xff0c;都遇到了问题。由于压缩包是高通自己处理卡住了&#xff0…

您可以使用WordPress创建的19种网站类型

当人们决定为什么他们应该使用WordPress时&#xff0c;我们经常会被问到“WordPress可以做[空白]吗&#xff1f;答案大多是肯定的。在本文中&#xff0c;我们将向您展示您可以使用WordPress创建的19种不同类型的网站&#xff0c;而无需学习任何编程技巧。 目录 隐藏 1 开始使用…

CSS---Emmet(二)

一、Emmet语法 Emmet语法是一种用于快速编写HTML和CSS的缩写技术。它允许开发者通过简洁的表达式快速生成复杂的代码结构&#xff0c;极大地提高了编码效率。使用Emmet&#xff0c;你只需要写出一些简短的缩写符号和操作符&#xff0c;然后通过快捷键&#xff08;通常是Tab键&…