要把自己的程序加入到openwrt中,有两个方法: 1)在package目录下添加自定义源码包,自己编译; 2)用openwrt的编译工具链,将自己的程序编译成可运行在openwrt的可执行程序。 本文主要讲前者。

OpenWRT新增package和feeds

编写测试程序hello world.c:

#include <stdio.h>

int main(void)
{
    printf("\nHello, world!\n\n");
    return 0;
}

编写Makefile文件:

include $(TOPDIR)/rules.mk

# Name, version and release number
# The name and version of your package are used to define the variable to point to the build directory of your package: $(PKG_BUILD_DIR)

PKG_NAME:=helloworld
PKG_VERSION:=1.0
PKG_RELEASE:=1

# Source settings (i.e. where to find the source codes)
# This is a custom variable, used below

SOURCE_DIR:=/home/al/openwrt/openwrt/mypackages/examples/helloworld

include $(INCLUDE_DIR)/package.mk

# Package definition; instructs on how and where our package will appear in the overall 

configuration menu ('make menuconfig')
define Package/helloworld
  SECTION:=examples
  CATEGORY:=Examples
  TITLE:=Hello, World!
endef

# Package description; a more verbose description on what our package does

define Package/helloworld/description
  A simple "Hello, world!" -application.
endef

# Package preparation instructions; create the build directory and copy the source code. 
# The last command is necessary to ensure our preparation instructions remain compatible with the patching system.

define Build/Prepare
        mkdir -p $(PKG_BUILD_DIR)
        cp $(SOURCE_DIR)/* $(PKG_BUILD_DIR)
        $(Build/Patch)
endef

# Package build instructions; invoke the target-specific compiler to first compile the source file, and then to link the file into the final executable

define Build/Compile
        $(TARGET_CC) $(TARGET_CFLAGS) -o $(PKG_BUILD_DIR)/helloworld.o -c $(PKG_BUILD_DIR)/helloworld.c
        $(TARGET_CC) $(TARGET_LDFLAGS) -o $(PKG_BUILD_DIR)/$1 $(PKG_BUILD_DIR)/helloworld.o
endef

# Package install instructions; create a directory inside the package to hold our executable, and then copy the executable we built previously into the folder

define Package/helloworld/install
        $(INSTALL_DIR) $(1)/usr/bin
        $(INSTALL_BIN) $(PKG_BUILD_DIR)/helloworld $(1)/usr/bin
endef

# This command is always the last, it uses the definitions and variables we give above in order to get the job done

$(eval $(call BuildPackage,helloworld))

创建feeds并安装

#为helloworld package创建feeds目录,并将hello world.c和Makefile放入其中:

mypackages/
└── examples
    └── helloworld
        ├── helloworld.c
        └── Makefile
#修改feeds.conf.default文件:
src-git-full packages https://git.openwrt.org/feed/packages.git;openwrt-22.03
src-git-full luci https://git.openwrt.org/project/luci.git;openwrt-22.03
src-git-full routing https://git.openwrt.org/feed/routing.git;openwrt-22.03
src-git-full telephony https://git.openwrt.org/feed/telephony.git;openwrt-22.03

src-link mypackages /home/al/openwrt/openwrt/mypackages

#单独更新mypackages feed:
./scripts/feeds update mypackage

# 在feeds下创建mypackages feed相关信息:
feeds
├── mypackages -> /home/al/openwrt/openwrt/mypackages
├── mypackages.index -> mypackages.tmp/.packageinfo
├── mypackages.targetindex -> mypackages.tmp/.targetinfo
├── mypackages.tmp
│   ├── info
│   └── location

#将mypackages feed的package安装到OpenWRT系统中:
./scripts/feeds install -a -p mypackages

#安装结果如下:
package/feeds/mypackages/
└── helloworld -> ../../../feeds/mypackages/examples/helloworld

配置并编译package

make menuconfig选择helloworld,并保存配置 编译helloworld: make package/feeds/mypackages/helloworld/compile

#在./build_dir/target-aarch64_cortex-a53_musl/helloworld-1.0目录存放编译过程文件:

./build_dir/target-aarch64_cortex-a53_musl/helloworld-1.0
├── helloworld
├── helloworld.c
├── helloworld.o
├── ipkg-aarch64_cortex-a53
│   └── helloworld
│       ├── CONTROL
│       │   ├── control
│       │   ├── postinst
│       │   └── prerm
│       └── usr
│           └── bin
│               └── helloworld
└── Makefile

#生成ipkg安装包位于./bin/packages/aarch64_cortex-a53/mypackages/:

./bin/packages/aarch64_cortex-a53/mypackages/
└── helloworld_1.0-1_aarch64_cortex-a53.ipk

根据Makefile配置helloworld也被安装到staging_dir下:./staging_dir/target-aarch64_cortex-a53_musl/root-armvirt/usr/bin/helloworld。

此时如果执行make,则helloworld可执行文件已经位于镜像中,烧录启动即可使用。

OpenWRT的目录结构解释如下,bin build_dir dl staging_dir是编译后创建的:

├── bin--编译完成后ipk和image文件存放在此。
│   ├── packages--存放base/luci/packages/routing/telephony等编译出来的ipk包。
│   └── targets--目标镜像文件。
├── BSDmakefile
├── build_dir--下载的软件包解压到此,然后进行编译。
│   ├── hostpkg--编译在host环境中使用的工具。
│   ├── target-aarch64_cortex-a53_musl--编译在target环境中使用的工具。
│   └── toolchain-aarch64_cortex-a53_gcc-11.2.0_musl--交叉工具链的编译。
├── config--menuconfig配置文件。
│   ├── check-uname.sh
│   ├── Config-build.in
│   ├── Config-devel.in
│   ├── Config-images.in
│   └── Config-kernel.in
├── Config.in--配置文件的总入口。
├── COPYING
├── dl--下载的软件包存放在此目录。
│   ├── attr-2.5.1.tar.gz
...
│   └── zstd-1.5.5.tar.gz
├── feeds--根据feeds.conf.default生成的OpenWRT的package来源地。
│   ├── luci
│   ├── luci.index -> luci.tmp/.packageinfo
│   ├── luci.targetindex -> luci.tmp/.targetinfo
│   ├── luci.tmp
│   ├── packages
│   ├── packages.index -> packages.tmp/.packageinfo
│   ├── packages.targetindex -> packages.tmp/.targetinfo
│   ├── packages.tmp
│   ├── routing
│   ├── routing.index -> routing.tmp/.packageinfo
│   ├── routing.targetindex -> routing.tmp/.targetinfo
│   ├── routing.tmp
│   ├── telephony
│   ├── telephony.index -> telephony.tmp/.packageinfo
│   ├── telephony.targetindex -> telephony.tmp/.targetinfo
│   └── telephony.tmp
├── feeds.conf.default
├── include--存放mk文件。
│   ├── autotools.mk
...
│   └── version.mk
├── key-build
├── key-build.pub
├── key-build.ucert
├── key-build.ucert.revoke
├── LICENSES
│   ├── BSD-2-Clause
│   ├── BSD-3-Clause
│   ├── GPL-1.0
│   ├── GPL-2.0
│   ├── ISC
│   ├── Linux-syscall-note
│   └── MIT
├── Makefile--make默认的配置文件。
├── package--不同类别package的makefile文件和menuconfig配置文件。
│   ├── base-files
│   ├── boot
│   ├── devel
│   ├── feeds
│   ├── firmware
│   ├── kernel
│   ├── libs
│   ├── Makefile
│   ├── network
│   ├── system
│   └── utils
├── README.md
├── rules.mk
├── scripts--编译过程中使用的脚本文件。
│   ├── arm-magic.sh
...
│   └── xxdi.pl
├── staging_dir--生成最终文件系统之前的临时安装目录。
│   ├── host
│   ├── hostpkg
│   ├── packages
│   ├── target-aarch64_cortex-a53_musl
│   └── toolchain-aarch64_cortex-a53_gcc-11.2.0_musl
├── target--imagebuilder、linux、sdk、toolchain的makefile和配置文件。
│   ├── Config.in
│   ├── imagebuilder
│   ├── linux
│   ├── llvm-bpf
│   ├── Makefile
│   ├── sdk
│   └── toolchain
├── tmp
│   ├── a.out
│   ├── info
│   ├── opkg_install_list
│   └── test.fs
├── toolchain--编译gcc/binutils/gdb/glibc/mold/must/nasm等工具的makefile文件和配置文件。
│   ├── binutils
│   ├── build_version
│   ├── Config.in
│   ├── fortify-headers
│   ├── gcc
│   ├── gdb
│   ├── glibc
│   ├── info.mk
│   ├── kernel-headers
│   ├── Makefile
│   ├── musl
│   ├── nasm
│   └── wrapper
└── tools--编译过程中所使用到的工具。
    ├── autoconf
...
    └── zstd

feeds是一系列package的存放点。scripts/feeds脚本用于管理feeds。feeds.conf.default用于配置feeds。

update:根据feeds.conf获取package,并拷贝到feeds目录下。 list:显示feeds,或其package列表详细信息。 install:将update命令从feeds获取packages链接到package/feeds/中。 uninstall:移除某个package。 search:查找特定package信息。

在对OpenWRT的feeds进行配置后,可以进行配置和编译。配置toolchain、kernel、packages: make menuconfig make

即可开始编译:

下载选中的package源码。 编译交叉编译工具链和host应用。 交叉编译kernel和选中的packages。 make V=x指定输出的不同编译log等级

其他常见编译操作:

运行make menuconfig选定目标映像; 运行make defconfig为构建环境和设备设定默认配置; 运行make kernel_menuconfig(可选); 运行make menuconfig配置软件包; 运行make download(在最终构建前下载所有依赖, 并激活多线程编译); 运行scripts/diffconfig.sh >mydiffconfig(将所有修改保存到mydiffconfig文件);

一、假如自定义的package目录结构图如下所示

http_upgrade/
├── config
│   └── http_url
├── init.d
│   └── get_route_data
├── Makefile
├── rc.d
│   └── S110http_upgrade
└── src
    ├── client.c
    ├── client.h
    ├── debug.c
    ├── debug.h
    ├── http_upgrade.c
    ├── Makefile
    ├── safe.c
    ├── safe.h
    ├── system_status.c
    └── system_status.h

4 directories, 14 files

注意:

(可选)config目录主要是放置程序的配置文件 (可选)init.d目录主要是放置自定义的脚本 (可选)rc.d目录主要是放置开机运行程序,这里是需要将自定义的程序开机启动 (可选)src目录主要是放置源码以及编译源码的makefile文件 (必选)Makefile,这里最关键的就是makefile文件

#
# Copyright (C) 2012 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#

include $(TOPDIR)/rules.mk

PKG_NAME:=http_upgrade #包的名字,在make menuconfig中看到的
PKG_RELEASE:=1

PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)

include $(INCLUDE_DIR)/package.mk

define Package/http_upgrade    #---包的目录
  SECTION:=utils
  CATEGORY:=Utilities #--------包放到哪个目录下,这里放到Utilities 下
  TITLE:=ZK contral x86 remote upgrade firmware  #-包的描述
  DEPENDS:=+libpthread +jansson +libcurl   #-----包需要的依赖库
endef

define Build/Prepare
        mkdir -p $(PKG_BUILD_DIR)
        $(CP) ./src/* $(PKG_BUILD_DIR)/
endef

define Build/Configure
endef

define Build/Compile
        $(MAKE) -C $(PKG_BUILD_DIR) \
                CC="$(TARGET_CC)" \
                CFLAGS="$(TARGET_CFLAGS) -Wall" \
                LDFLAGS="$(TARGET_LDFLAGS)"
endef

define Package/http_upgrade/install  #-------安装过程
        $(INSTALL_DIR) $(1)/etc/init.d   #--安装目录
        $(INSTALL_BIN) ./init.d/* $(1)/etc/init.d #-将包init.d目录下的文件安装到openwrt下的init.d目录下

        $(INSTALL_DIR) $(1)/usr/sbin
        $(INSTALL_BIN) $(PKG_BUILD_DIR)/http_upgrade $(1)/usr/sbin/  #-将http_upgrade文件安装到openwrt下的/usr/sbin/目录下

        $(INSTALL_DIR) $(1)/etc/config
        $(INSTALL_DATA) ./config/* $(1)/etc/config   #---将包下config目录下面的文件安装到openwrt的/etc/config/目录下

        $(INSTALL_DIR) $(1)/etc/rc.d
        $(INSTALL_BIN) ./rc.d/* $(1)/etc/rc.d   #------将包下rc.d目录下面的文件安装到openwrt的/etc/rc.d目录下
endef

$(eval $(call BuildPackage,http_upgrade))

生成文件链接index,并进行安装

./scripts/feeds update -i packages
./scripts/feeds install -a
#或者用单独编译指令:make package/app/helloword/compile
#package编译
#单独编译某一个模块:

make package/example/download #- download the soures of example
make package/example/prepare #- extract the sources, apply patches and download if necessary
make package/example/compile #- compile example, prepare and download if necessary
make package/example/clean #- clean the sourcecode
make package/index #- build a repository index to make the output directory usable as local opkg source

编译中间过程位于build_dir中,按照不同的package分列,里面包含源代码、编译脚本、编译中间文件以及输出可执行或者库文件等

staging_dir是一个临时集合,后面可能还会有strip等操作

bin中存放最终镜像和安装包

编译完成后,bin/packages/mipsel_24kc/base下可看到对应的ipk文件生成,build_dir/target-mipsel_24kc_glibc/目录下,也同样生成了可执行文件。

build_dir/target-aarch64_cortex-a53_musl/
├── busybox-default...
├── root-armvirt--即将要打包的rootfs文件集合。
├── root.orig-armvirt
...
└── zlib-1.2.11

build_dir/target-aarch64_cortex-a53_musl/
├── busybox-default...
├── root-armvirt--即将要打包的rootfs文件集合。
├── root.orig-armvirt
...
└── zlib-1.2.11

bin/targets/
└── armvirt
    └── 64
        ├── config.buildinfo
        ├── feeds.buildinfo
        ├── openwrt-armvirt-64-default.manifest
        ├── openwrt-armvirt-64-default-rootfs.tar.gz
        ├── openwrt-armvirt-64-Image
        ├── openwrt-armvirt-64-Image-initramfs
        ├── openwrt-armvirt-64-rootfs.cpio.gz
        ├── openwrt-armvirt-64-rootfs-ext4.img.gz
        ├── openwrt-armvirt-64-rootfs-squashfs.img.gz
        ├── packages
        │   ├── base-files_1505-r20341-591b7e93d3_aarch64_cortex-a53.ipk
        │   ├── dropbear_2022.82-4_aarch64_cortex-a53.ipk
        │   ├── fstools_2022-06-02-93369be0-2_aarch64_cortex-a53.ipk
        │   ├── fwtool_2019-11-12-8f7fe925-1_aarch64_cortex-a53.ipk
        │   ├── index.json
        │   ├── kernel_5.10.221-1-95f66e1daaaff0091d354d5d867e8a64_aarch64_cortex-a53.ipk
...
        │   ├── mtd_26_aarch64_cortex-a53.ipk
        │   ├── Packages
        │   ├── Packages.gz
        │   ├── Packages.manifest
        │   └── Packages.sig
        ├── sha256sums
        └── version.buildinfo

参考文章:

https://www.cnblogs.com/arnoldlu/p/18306851