编译官方原版的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.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.4 单独编译mstpd
5.3 加入自己编写的软件包
5.3.1 按照openwrt规范路径
5.3.2 编写内部Makefile
5.3.3 编写外部Makefile
5.3.5 单独编译tsmsq
6.编译openwrt镜像源VDI加载到virtualBox
1.源码下载
1.1 通过官网直接下载
[OpenWrt Wiki] Welcome to the OpenWrt Projecthttps://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博客
相关文章:

编译官方原版的openwrt并加入第三方软件包
最近又重新编译了最新的官方原版openwrt-2305(2024.3.22),此处记录一下以待日后参考。 目录 1.源码下载 1.1 通过官网直接下载 1.2 映射github加速下载 1.2.1 使用github账号fork源码 1.2.2 创建gitee账号映射github openwrt 2.编译准…...

PC适配移动端
**手机端适配** 媒体查询 组件统一样式 媒体查询写四套样式 手机 屏幕宽小于768px 平板 屏幕宽 大于等于768px 小于992px 桌面显示器 屏幕宽大于等于992px 小于1200px 大屏幕 屏幕宽大于等于1200px **页面整体及页面内容** 页面看是需要主PC还是主移动端 主移动端的话…...

springboot+vue+mybatis灵活就业服务平台+PPT+论文+讲解+售后
随着网络科技的不断发展以及人们经济水平的逐步提高,网络技术如今已成为人们生活中不可缺少的一部分,而微信小程序是通过计算机技术,针对用户需求开发与设计,该技术尤其在各行业领域发挥了巨大的作用,有效地促进了灵活…...

Android 13 系统自定义安全水印
效果 源码实现 frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java public final void showSafeModeOverlay() {View v LayoutInflater.from(mContext).inflate(com.android.internal.R.layout.safe_mode, null);WindowManager.Layout…...

C# WCF服务(由于内部错误,服务器无法处理该请求。)
由于内部错误,服务器无法处理该请求。有关该错误的详细信息,请打开服务器上的 IncludeExceptionDetailInFaults (从 ServiceBehaviorAttribute 或从 <serviceDebug> 配置行为)以便将异常信息发送回客户端,或打开对每个 Microsoft .NET …...

利用github pages建立Serverless个人博客
利用github pages建立Serverless个人博客 概述 使用github pages,可以在github上部署静态网站。利用这个功能,可以很方便地实现个人博客的发布托管。 比如我的个人博客:Buttering’s Blog 对应代码仓库:buttering/EasyBlog: 自…...

Spring Boot 集成 sa-token 实践教程
Spring Boot 集成 sa-token 实践教程 sa-token 是一个轻量级且功能强大的权限认证框架,它基于Java语言,专为Java开发者设计,以简化权限管理的复杂性。在Spring Boot项目中集成sa-token,可以快速实现会话管理、权限控制等功能。本文…...

CSS:盒子模型
目录 ▐ box—model概述 ▐ 盒子的组成 ▐ 内容区 ▐ 内边距 ▐ 边框 ▐ 外边距 ▐ 清除浏览器默认样式 ▐ box—model概述 • CSS处理网页时,它认为每个标签都包含在一个不可见的盒子里. • 如果把所有的标签都想象成盒子,那么我们对网…...

django中的cookie与session
获取cookie request.COOKIE.GET 使用cookie response.set-cookie views.py from django.http import HttpResponse from django.shortcuts import render# Create your views here. def cookie_test(request):r HttpResponse("hello world")r.set_cookie(lan, py…...

环形链表(判断链表中是否有环)的讲解
一:题目 二:思路讲解 1:采用快慢指针的方法,一个fast指针一次移动两个节点,一个slow指针一次移动一个节点。 2:两个指针从头指针开始往后遍历,如果fast指针或者fast->next 有一个为空&…...

NLP(14)--文本匹配任务
前言 仅记录学习过程,有问题欢迎讨论 步骤: * 1. 输入问题 * 2. 匹配问题库(基础资源,FAQ) * 3. 返回答案文本匹配算法: 编辑距离算法(缺点) 字符之间没有语义相似度; 受无关词/停用词影响大; 受语序影响大 Jaccar…...

MySQL——系统变量
使用 #最大连接用户数 select MAX_CONNECTIONS; #临时存放构成每次事务的SQL的缓冲区长度 select BINLOG_CACHE_SIZE; #SQL Server的版本信息 select VERSION; 查询结果...

「 网络安全常用术语解读 」漏洞利用预测评分系统EPSS详解
1. 概览 EPSS(Exploit Prediction Scoring System,漏洞利用预测评分系统) 提供了一种全新的高效、数据驱动的漏洞管理功能。EPSS是一项数据驱动的工作,使用来自 CVE 的当前威胁信息和现实世界的漏洞数据。 EPSS 模型产生 0 到 1&…...

理解python中的Iterator 和 Iterable 迭代器和可迭代对象
为什么有些对象可以用for … in 循环 我们先看一段代码: list [1, 2, 3, 4, 5]for i in list:logger.info(i)这代码定义了1个数组object list, 然后用 for … in 来遍历这个list 看起来合理没什么值得注意 但其实 for … in 后面对象还可以是个String for i in …...

C语言实现动态加载.so动态库,使用,错误捕获以及卸载
动态库 概述 动态库的扩展名是.so。 动态库是被加载,调用的时候是根据内存地址去调用,而不是将代码复制到文件中。 动态库可以同时被多个进程使用。 实战案例:构建 libmath.so 动态库 准备源文件 calc.h 定义加法:int add…...

《动手学深度学习》V2(11-18)
文章目录 十一、二 模型选择与过拟合和欠拟合1、模型的选择2、过拟合和欠拟合3、估计模型容量4、线性分类器的VC维5、过拟合欠拟合的代码实现 :fire:①生成数据集②定义评估损失③定义训练函数④三阶多项式函数拟合⑤线性函数拟合(欠拟合)⑤高阶多项式函数拟合(过拟合) 十三、权…...

web前端之excel转pdf、小黄人发送请求、base64、jspdf、xlsx
MENU 前言方案一方案二结束语 前言 在前端将Excel转换为PDF有多种方案,本文介绍两种简单方案。 方案一 使用jspdf库,先将Excel文件转成Base64格式,然后再使用jspdf库将其转换为PDF格式,最后使用saveAs函数下载PDF文件。 步骤一: 安…...

【面试题】音视频流媒体高级开发(2)
面试题6 衡量图像重建好坏的标准有哪些?怎样计算? 参考答案 SNR(信噪比) PSNR10*log10((2n-1)2/MSE) (MSE是原图像与处理图像之间均方误差,所以计算PSNR需要2幅图像的数据!) SSIM…...

数据与结构--堆
堆 堆的概念 堆:如果有一个关键码的集合K{k0,k1,k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足ki<k2i1且ki<k2i2(或满足ki>k2i1且ki>k2i2),其中i0,1,2,…...

Github的使用教程(下载项目、寻找开源项目和上传项目)
根据『教程』一看就懂!Github基础教程_哔哩哔哩_bilibili 整理。 1.项目下载 1)直接登录到源码链接页或者通过如下图的搜索 通过编程语言对搜索结果进一步筛选。 如何去找开源项目:(Github 新手够用指南 | 全程演示&个人找项目技巧放…...

Linux-线程概念
1. 线程概念 线程:轻量级进程,在进程内部执行,是OS调度的基本单位;进程内部线程共用同一个地址空间,同一个页表,以及内存中的代码和数据,这些资源对于线程来说都是共享的资源 进程:…...

js的桶排序
桶排序(Bucket Sort)是一种分布式排序算法,它将元素分散到一系列桶中,然后对每个桶中的元素进行排序,并将所有的桶合并起来得到最终的排序结果。桶排序适用于输入的元素均匀分布在一个范围内的情况,它的时间…...

解决ubuntu无法上网问题
发现是网络配置成了Manual手动模式,现在都改成自动分配DHCP模式 打开后,尝试上网还是不行,ifconfig查看ip地址还是老地址,怀疑更改没生效,于是重启试试。 重启后,ip地址变了,可以打开网页了 …...

使用nvm管理多版本node.js
使用nvm(Node Version Manager)安装Node.js是一个非常方便的方法,因为它允许你在同一台机器上管理多个Node.js版本。以下是使用nvm安装Node.js的基本步骤: Linux 安装nvm 根据你的操作系统,安装命令可能会有所不同。以…...

推导 模型矩阵的逆转置矩阵求运动物体的法向量
一个物体表面的法向量如何随着物体的坐标变换而改变,取决于变换的类型。使用逆转置矩阵,可以安全地解决该问题,而无须陷入过度复杂的计算中。 法向量变化规律 平移变换不会改变法向量,因为平移不会改变物体的方向。 旋转变换会改…...

定时任务的几种实现方式
定时任务实现的几种方式: 1、JDK自带 (1)Timer:这是java自带的java.util.Timer类,这个类允许你调度一个java.util.TimerTask任务。使用这种方式可以让你的程序按照某一个频度执行,但不能在指定时间运行。…...

docker部署springboot+Vue项目
项目介绍:后台springboot项目,该项目环境mysql、redis 。前台Vue:使用nginx反向代理 方法一:docker run 手动逐个启动容器 1.docker配置nginx代理 将vue项目打包上传到服务器上。创建文件夹存储数据卷,html存放打包…...

Llama3-Tutorial(Llama 3 超级课堂)-- 笔记
第1节—Llama 3 本地 Web Demo 部署 端口转发 vscode里面设置端口转发 https://a-aide-20240416-b4c2755-160476.intern-ai.org.cn/proxy/8501/ ssh -CNg -L 8501:127.0.0.1:8501 rootssh.intern-ai.org.cn -p 43681参考 https://github.com/SmartFlowAI/Llama3-Tutorial/b…...

【备战软考(嵌入式系统设计师)】12 - 嵌入式系统总线接口
我们嵌入式系统的总线接口可以分为两类,一类是并行接口,另一类是串行接口。 并行通信就是用多个数据线,每条数据线表示一个位来进行传输数据,串行接口就是一根数据线可以来一位一位地传递数据。 从上图也可以看出,并行…...

【一刷《剑指Offer》】面试题 18:树的子结构
力扣对应题目链接:LCR 143. 子结构判断 - 力扣(LeetCode) 牛客对应题目链接:树的子结构_牛客题霸_牛客网 (nowcoder.com) 核心考点:二叉树理解,二叉树遍历。 一、《剑指Offer》对应内容 二、分析问题 二叉…...