OpenWRT(3):目录结构、创建维护feeds、创建package及其编译安装
总结OpenWRT目录结构,然后创建feeds,并创建package。
编译package,并安装到target进行测试。
1 OpenWRT目录结构
OpenWRT的目录结构解释如下,高亮部分是编译后创建的:
├── 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
2 OpenWRT feeds管理
feeds是一系列package的存放点。scripts/feeds脚本用于管理feeds。feeds.conf.default用于配置feeds。更多参考:参考:[OpenWrt Wiki] OpenWrt Feeds。
2.1 feeds管理
./scripts/feeds用于管理OpenWRT的feeds:
Usage: ./scripts/feeds <command> [options] Commands: list [options]: List feeds, their content and revisions (if installed) Options: -n : List of feed names. -s : List of feed names and their URL. -r <feedname>: List packages of specified feed. -d <delimiter>: Use specified delimiter to distinguish rows (default: spaces) -f : List feeds in feeds.conf compatible format (when using -s). install [options] <package>: Install a package Options: -a : Install all packages from all feeds or from the specified feed using the -p option. -p <feedname>: Prefer this feed when installing packages. -d <y|m|n>: Set default for newly installed packages. -f : Install will be forced even if the package exists in core OpenWrt (override) search [options] <substring>: Search for a package Options: -r <feedname>: Only search in this feed uninstall -a|<package>: Uninstall a package Options: -a : Uninstalls all packages. update -a|<feedname(s)>: Update packages and lists of feeds in feeds.conf . Options: -a : Update all feeds listed within feeds.conf. Otherwise the specified feeds will be updated. -i : Recreate the index only. No feed update from repository is performed. -f : Force updating feeds even if there are changed, uncommitted files. clean: Remove downloaded/generated files.
- update:根据feeds.conf获取package,并拷贝到feeds目录下。
- list:显示feeds,或其package列表详细信息。
- install:将update命令从feeds获取packages链接到package/feeds/中。
- uninstall:移除某个package。
- search:查找特定package信息。
2.2 新增feeds
修改feeds.conf.default文件,新增feeds配置:
Method | Function |
---|---|
src-bzr | Data is downloaded from the source path/URL using bzr |
src-cpy | Data is copied from the source path. The path can be specified as either relative to OpenWrt repository root or absolute. |
src-darcs | Data is downloaded from the source path/URL using darcs |
src-git | Data is downloaded from the source path/URL using git as a shallow (depth of 1) clone |
src-git-full | Data is downloaded from the source path/URL using git as a full clone |
src-gitsvn | Bidirectional operation between a Subversion repository and git |
src-hg | Data is downloaded from the source path/URL using hg |
src-link | A symlink to the source path is created. The path must be absolute. |
src-svn | Data is downloaded from the source path/URL using svn |
以git为例:
src-git local_feed_name https://example.com/repo_name/something.git;branch_name src-git local_feed_name https://example.com/repo_name/something.git^commit_hash
3 OpenWRT编译流程
3.1 整体编译
在对OpenWRT的feeds进行配置后,可以进行配置和编译。
配置toolchain、kernel、packages:
make menuconfig
make即可开始编译:
- 下载选中的package源码。
- 编译交叉编译工具链和host应用。
- 交叉编译kernel和选中的packages。
make V=x指定输出的不同编译log等级:
V=99 and V=1 are now deprecated in favor of a new verbosity class system, though the old flags are still supported. You can set the V variable on the command line (or OPENWRT_VERBOSE in the environment) to one or more of the following characters: - s: stdout+stderr (equal to the old V=99) - c: commands (for build systems that suppress commands by default, e.g. kbuild, cmake) - w: warnings/errors only (equal to the old V=1)
其他常见编译操作:
- 运行make menuconfig选定目标映像;
- 运行make defconfig为构建环境和设备设定默认配置;
- 运行make kernel_menuconfig(可选);
- 运行make menuconfig配置软件包;
- 运行make download(在最终构建前下载所有依赖, 并激活多线程编译);
- 运行scripts/diffconfig.sh >mydiffconfig(将所有修改保存到mydiffconfig文件);
3.2 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
对一个package执行多个编译选项,注意clean和compile之间不能有空格:
make package/example/{clean,compile} V=99
编译中间过程位于build_dir中,按照不同的package分列,里面包含源代码、编译脚本、编译中间文件以及输出可执行或者库文件等:
build_dir/target-aarch64_cortex-a53_musl/ ├── busybox-default... ├── root-armvirt--即将要打包的rootfs文件集合。 ├── root.orig-armvirt ... └── zlib-1.2.11
staging_dir是一个临时集合,后面可能还会有strip等操作:
staging_dir/target-aarch64_cortex-a53_musl/ ├── host ├── packages ├── pkginfo ├── root-armvirt ├── stamp └── usr
bin中存放最终镜像和安装包:
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
4 OpenWRT新增package和feeds
参考:《[OpenWrt Wiki] Creating a simple “Hello, world!” application》、《[OpenWrt Wiki] Creating a package from your application》、《[OpenWrt Wiki] Including your package feed into OpenWrt build system》、《[OpenWrt Wiki] Building, deploying and testing your application》。
4.1 创建package内容
编写测试程序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))
4.2 创建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
4.3 配置并编译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可执行文件已经位于镜像中,烧录启动即可使用。
4.4 安装卸载package
通过scp将ipk传到target:
scp bin/packages/aarch64_cortex-a53/mypackages/helloworld_1.0-1_aarch64_cortex-a53.ipk root@192.168.2.2:/
安装ipk:
opkg install helloworld_1.0-1_aarch64_cortex-a53.ipk
执行helloworld:
Hello, world!
卸载helloworld:
opkg remove helloworld
opkg显示已安装列表:
opkg list