编译官方原版的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.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定制系统。

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

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

cordova build android 下载gradle太慢

一、 在使用cordova run android / cordova build android 的时候 gradle在线下载 对于国内的链接地址下载太慢。 等待了很长时间之后还会报错。 默认第一次编译在线下载 gradle-7.6.1-all.zip 然后解压缩到 C:\Users\Administrator\.gradle 文件夹中,下载慢导致失败。 二…

(论文阅读-优化器)A Cost Model for SPARK SQL

目录 Abstract 1 Introduction 2 Related Work 3 Background and Spark Basics 4 Cost Model Basic Bricks 4.1 Cluster Abastraction and Cost Model Parameters 4.2 Read 4.3 Write 4.4 Shuffle Read 4.5 Broadcast 5 Modeling GPSJ Queries 5.1 Statistics and S…

【论文阅读笔记】Order Matters(AAAI 20)

个人博客地址 注&#xff1a;部分内容参考自GPT生成的内容 论文笔记&#xff1a;Order Matters&#xff08;AAAI 20&#xff09; 用于二进制代码相似性检测的语义感知神经网络 论文:《Order Matters: Semantic-Aware Neural Networks for Binary Code Similarity Detection》…

Spring Boot 整合 socket 实现简单聊天

来看一下实现的界面效果 pom.xml的maven依赖 <!-- 引入 socket --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency><!-- 引入 Fastjson &#x…

【CV-CUDA实战】使用Python+TensorRT+CVCUDA优化YOLOv8

目录 什么是CV-CUDA环境准备准备CV-CUDA静态库解压添加至变量将PyBind静态库复制到env下算子设计前处理算子 TensorRT模型加载后处理函数 完整代码输出演示为什么重新写了&#xff1f;结语 什么是CV-CUDA NVIDIA CV-CUDA™ 是一个开源项目&#xff0c;用于构建云规模人工智能 (…

【数据结构(邓俊辉)学习笔记】列表02——无序列表

文章目录 0.概述1.插入与构造1.1 插入1.1.1 前插入1.1.2后插入1.1.3 复杂度 1.2 基于复制构造1.2.1 copyNodes()1.2.2 基于复制构造1.2.3 复杂度 2.删除与析构2.1 删除2.1.1 实现2.1.2 复杂度 2.2 析构2.2.1 释放资源及清除节点2.2.2 复杂度 3.查找3.1 实现3.2 复杂度 4.唯一化…

每天五分钟深度学习:数学中常见函数中的导数

本文重点 导数是微积分学中的一个核心概念,它描述了函数在某一点附近的变化率。在物理学、工程学、经济学等众多领域中,导数都发挥着极其重要的作用。本文旨在详细介绍数学中常见函数的导数,以期为读者提供一个全面而深入的理解。 数学中常见的导数 常数函数的导数 对于常数…

Raft共识算法笔记,MIT6.824,

处理leader和follow的一个重要思路是多数投票&#xff0c;确保系统中存在奇数个服务器&#xff08;例如3台&#xff09;。进行任何操作都需要来自多数服务器的同意&#xff0c;例如3台服务器中的2台。如果没有多数同意&#xff0c;系统会等待。为什么多数投票有助于避免脑裂问题…

springboot项目 字典/枚举翻译 终极解决方案 AOP+自定义注解+递归实体字段+实体动态三级缓存+责任链+多种转换方式

目录 前言实现思路技术确定 食用方式效果使用样例项目中使用第一步 复制包第二步 实现LoadDictDatabase并将其注入容器第三步 标识需要翻译的字段第四步 标识需要翻译的方法第五步 调用需要翻译的方法 实现细节TODO 前言 字典,即在存储介质中进行存储时,为了避免业务上对其名称…

计数排序,基数排序,桶排序

目录 计数排序: 基数排序&#xff1a; 桶排序: 计数排序: 计数排序是一种非比较型整数排序算法&#xff0c;特别适用于一定范围内的整数排序。它的核心思想是使用一个额外的数组&#xff08;称为计数数组&#xff09;来计算每个值的出现次数&#xff0c;然后根据这些计数信…

[贪心] 区间选点问题

905. 区间选点 - AcWing题库 思路&#xff1a;就是将所有区间按照右端点排序&#xff0c; 然后选取一些区间的右端点 代码&#xff1a; #include <iostream> #include <algorithm> #include <vector> using namespace std; const int N 100010;typedef p…

Flask与HTTP

一、请求响应循环 “请求-响应循环”&#xff1a;客户端发出请求&#xff0c;服务器处理请求并返回响应。 Flask Web程序的工作流程&#xff1a; 当用户访问一个URL&#xff0c;浏览器便生成对应的HTTP请求&#xff0c;经由互联网发送到对应的Web服务器。Web服务器接收请求&a…

信号,信号列表,信号产生方式,信号处理方式

什么是信号 信号在我们的生活中非常常见&#xff1b;如红绿灯&#xff0c;下课铃&#xff0c;游戏团战信号&#xff0c;这些都是信号&#xff1b;信号用来提示接收信号者行动&#xff0c;但接收信号的人接收到信号会进行一系列的行为&#xff0c;完成某个动作&#xff1b;这就…

基于Java EE平台项目管理系统的设计与实现(论文 + 源码)

【免费】基于javaEE平台的项目管理系统.zip资源-CSDN文库https://download.csdn.net/download/JW_559/89267688 基于Java EE平台项目管理系统的设计与实现 摘 要 随着社会信息化的发展&#xff0c;很多的社会管理问题也一并出现了根本性变化&#xff0c;项目公司的报表及文…

【YOLO】目标检测 YOLO框架之train.py参数含义及配置总结手册(全)

1.一直以来想写下基于YOLO开源框架的系列文章&#xff0c;该框架也是日常项目开发中常用的一款工具&#xff0c;最近刚好挤时间梳理、总结下这块儿的知识体系。 2.熟悉、梳理、总结下YOLO目标检测相关知识体系&#xff0c;之前实战配置时总是临时性检索些注释含义&#xff0c;但…

JVM组成之类加载器

类加载器&#xff08;ClassLoader&#xff09;&#xff1a;是Java虚拟机提供给应用程序去实现获取类和接口字节码数据的技术。 类加载器多数是有Java编写的&#xff0c;也有部分是c编写的&#xff0c;负责接收来自外部的二进制数据&#xff0c;然后执行JNI&#xff08;也就是本…

【Java】山外有山,类外还有类

【Java】山外有山&#xff0c;类外还有类 内部类是Java语言中的一种特性&#xff0c;它允许在另一个类中定义一个类。 内部类可以是静态的&#xff08;不依赖于外部类的实例&#xff09;&#xff0c;也可以是非静态的&#xff08;依赖于外部类的实例&#xff09;。 在本篇博…

在R的 RGui中,使用devtools 安装trajeR

创建于&#xff1a;2024.5.5 文章目录 1. 报错信息2. 尝试使用指定的清华镜像&#xff0c;没有解决3. 找到原因&#xff1a;官网把包删除了4. 尝试从网上下载&#xff0c;然后安装。没有成功5. 使用devtools安装5.1 尝试直接安装&#xff1a;install.packages("devtools&q…

【智能算法应用】混合粒子群算法求解CVRP问题

目录 1.算法原理2.数学模型3.结果展示4.参考文献5.代码获取 1.算法原理 【智能算法】粒子群算法&#xff08;PSO&#xff09;原理及实现 经典PSO算法用于连续空间优化问题&#xff0c;VRP问题为离散组合优化问题&#xff0c;涉及如何有效地分配一组车辆去访问多个客户点&…

OSEK的设计哲学与架构

1 前言 OSEK是为单核分布式嵌入式控制单元量身定制的实时系统&#xff0c;对事件驱动&#xff08;event driven&#xff09;的硬实时控制系统具有良好的适配性。OSEK没有强求不同软件模块间的完全兼容性&#xff0c;而是将重心放到了软件的可移植性上来。简单来说&#xff0c;与…