最近又重新编译了最新的官方原版openwrt-2305(2024.3.22),此处记录一下以待日后参考。
目录
1.2.2 创建gitee账号映射github openwrt
4.1.1 you should not run configure as root...
4.1.2 But that file is already provided by package...
Package/$(PKG_NAME)/description
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.so But 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/Prepare mkdir -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.mk PKG_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.mk define Package/mstpd #SECTION 软件包类型 SECTION:=utils #CATEGORY menuconfig中软件包所属的一级目录,如Network CATEGORY:=Utilities #SUBMENU - menuconfig中软件包所属的二级目录,如dial-in/up #SUBMENU:= TITLE:=mstpd DEPENDS:=+libpthread endef define Package/mstpd/description mstpd is added by me endef TARGET_CFLAGS += #定义make prepare 动作 define Build/Prepare mkdir -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/ #endef 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 $(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.mk PKG_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 -lc include $(INCLUDE_DIR)/package.mk include $(INCLUDE_DIR)/cmake.mk define Package/tsmsq #SECTION 软件包类型 SECTION:=utils #CATEGORY menuconfig中软件包所属的一级目录,如Network CATEGORY:=Utilities #SUBMENU - menuconfig中软件包所属的二级目录,如dial-in/up #SUBMENU:= TITLE:=tsmsq DEPENDS:=+libpthread +libc endef define Package/tsmsq/description tsmsq is added by me endef #定义make prepare 动作 define Build/Prepare mkdir -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/ #endef define 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定制系统。
同时也参考了很多优秀的博文,列出如下: