package是target之外的另一个概念,它表示一个包,比如busybox是一个package。package在package/目录下,比如busybox的路径为:package/utils/busybox。每个package都有一个Makefile,来定义这个package。
    添加一个package:package/my/webcgi,添加Makefile文件:package/webcgi/my/Makefile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29  | include $(TOPDIR)/rules.mkPKG_NAME:=webcgiPKG_VERSION:=1.0.0PKG_RELEASE:=1include $(INCLUDE_DIR)/package.mkdefine Package/webcgi  CATEGORY:=My package  TITLE:=webcgi  DEPENDS := +libnl +libblobmsg-json +libubusendefdefine Build/Prepare        mkdir -p $(PKG_BUILD_DIR)/{lib,cgi}endefdefine Build/Compile        CFLAGS="$(TARGET_CFLAGS)" LDFLAGS="$(TARGET_LDFLAGS)" make -C src/ \            O=$(PKG_BUILD_DIR)/ CC=$(TARGET_CC)endefdefine Package/webcgi/install        $(INSTALL_DIR) $(1)/web/cgi-bin        $(INSTALL_BIN) $(PKG_BUILD_DIR)/webcgi $(1)/web/cgi-binendef$(eval $(call BuildPackage,webcgi)) | 
执行 make prepare-tmpinfo,生成了 tmp/info/.package-webcgi包信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18  | Source-Makefile: package/my/webcgi/MakefilePackage: webcgiVersion: 1.0.0-1Depends: +libc +USE_GLIBC:librt +USE_GLIBC:libpthread +libnl +libblobmsg-json +libubusConflicts:Menu-Depends:Provides:Section: My sectionCategory: My packageRepository: baseTitle: webcgiMaintainer:Source:Type: ipkgDescription: webcgi@@ | 
配置文件 tmp/.config-package.in包含了这个包的配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17  | menu "My package"    config PACKAGE_webcgi        tristate "webcgi............................................................ webcgi"        default y if DEFAULT_webcgi        default m if ALL        select PACKAGE_libnl        select PACKAGE_libblobmsg-json        select PACKAGE_libpthread if USE_GLIBC        select PACKAGE_libc        select PACKAGE_libubus        select PACKAGE_librt if USE_GLIBC        help         webcgiendmenu | 
定义中的CATEGORY变量,表示是哪个menu。还可以定义SUBMENU变量,指定二级目录。
依赖通过DEPENDS变量定义。规则如下:
| +foo | 选中foo这个package,翻译为config为: select PACKAGE_foo | 
| foo | 依赖foo这个package,翻译为config为: depends on PACKAGE_foo | 
| @foo | 依赖配置项CONFIG_foo,翻译为config为:depends on foo | 
+foo:bar  | 如果配置项CONFIG_foo开启,则选中bar这个package, 翻译为config为:select PACKAGE_bar if foo  | 
| @foo:bar | 如果CONFIG_foo开启,则依赖CONFIG_bar。 翻译为config为:depends on !(foo) || bar 这里有问题和openwrt的文档描述不符。查看openwrt的package,没有这么用的。  | 
还可以通过定义Package/xxx/config变量,来直接定义配置项:
define Package/webcgi/config
config webcgi_name
string "name of webcgi"
depends on PACKAGE_webcgi
endef
生成的依赖文件tmp/.packagedeps包含如下webcgi的定义:
package-$(CONFIG_PACKAGE_webcgi) += my/webcgi
$(curdir)/my/webcgi/compile += $(curdir)/libs/libnl/compile $(curdir)/libs/toolchain/compile
$(if $(CONFIG_USE_GLIBC),$(curdir)/libs/toolchain/compile)
在package/Makefile中的$(eval $(call subdir,$(curdir)))生成了编译包的信息:
1 2 3 4 5 6 7 8  | package/my/webcgi/compile: package/libs/libnl/compile package/libs/toolchain/compile      @+  /work/openwrt/scripts/time.pl "time: package/my/webcgi/compile" $(SUBMAKE) -r \        -C package/my/webcgi BUILD_SUBDIR="package/my/webcgi" BUILD_VARIANT="" compile \         ||   (   printf "\\033[33m%s\\033[m\n" "    \         ERROR: package/my/webcgi failed to build." >&8;   exit 1;)          # aliasespackage/webcgi/compile: package/my/webcgi/compile | 
可以看到有alias的支持,所以编译package/webcgi/compile,等价于:package/my/webcgi/compile。
一个Makefile里面是可以定义多个包的。比如修改package/my/webcgi/Makefile如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40  | PKG_NAME:=webcgi2PKG_VERSION:=1.0.0PKG_RELEASE:=1include $(INCLUDE_DIR)/package.mkdefine Package/webcgi3  CATEGORY:= My package  TITLE:=webcgi3  DEPENDS := +libnl  VARIANT:=3endefdefine Package/webcgi4  CATEGORY:= My package  TITLE:=webcgi4  DEPENDS := +libubus  VARIANT:=4endefdefine Build/Prepare        mkdir -p $(PKG_BUILD_DIR)/{lib,cgi}endefdefine Build/Compile    touch $(PKG_BUILD_DIR)/webcgiendefdefine Package/webcgi3/install        $(INSTALL_DIR) $(1)/web/cgi-bin        $(INSTALL_BIN) $(PKG_BUILD_DIR)/webcgi $(1)/web/cgi-binendefdefine Package/webcgi4/install        $(INSTALL_DIR) $(1)/web/cgi-bin        $(INSTALL_BIN) $(PKG_BUILD_DIR)/webcgi $(1)/web/cgi-binendef$(eval $(call BuildPackage,webcgi3))$(eval $(call BuildPackage,webcgi4)) | 
可以看到Prepare和Compile是共用的,package定义和install是独立的。定义里面多了一个VARIANT变量来区分。
解析的包属性如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38  | $ cat tmp/info/.packageinfo-my_webcgiSource-Makefile: package/my/webcgi/MakefilePackage: webcgi3Version: 1.0.0-1Depends: +libc +USE_GLIBC:librt +USE_GLIBC:libpthread +libnlConflicts:Menu-Depends:Provides:Build-Variant: 3Section: optCategory: My packageRepository: baseTitle: webcgi3Maintainer:Source:Type: ipkgDescription: webcgi3@@Package: webcgi4Version: 1.0.0-1Depends: +libc +USE_GLIBC:librt +USE_GLIBC:libpthread +libubusConflicts:Menu-Depends:Provides:Build-Variant: 4Section: optCategory: My packageRepository: baseTitle: webcgi4Maintainer:Source:Type: ipkgDescription: webcgi4@@ | 
可以看到PKG_NAME定义的webcgi2,并没有出现解析结果中,实际上编译的时候的包名是Makefile所在目录的名称,PKG_NAME只是用来生成默认的PKG_BUILD_DIR等变量。但是通常PKG_NAME和Makefile所在目录名称相同。
生成的配置信息包含如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27  | menu "My package"    config PACKAGE_webcgi3        tristate "webcgi3.......................................................... webcgi3"        default y if DEFAULT_webcgi3        default m if ALL        select PACKAGE_libpthread if USE_GLIBC        select PACKAGE_librt if USE_GLIBC        select PACKAGE_libnl        select PACKAGE_libc        help         webcgi3    config PACKAGE_webcgi4        tristate "webcgi4.......................................................... webcgi4"        default y if DEFAULT_webcgi4        default m if ALL        select PACKAGE_librt if USE_GLIBC        select PACKAGE_libc        select PACKAGE_libpthread if USE_GLIBC        select PACKAGE_libubus        help         webcgi4endmenu | 
可以看到,包括了两个包,是可以独立选择的。
生成的tmp/.packagedeps包含如下:
1 2 3 4 5 6 7 8 9 10 11  | package-$(CONFIG_PACKAGE_webcgi3) += my/webcgi$(curdir)/my/webcgi/variants += $(if $(CONFIG_PACKAGE_webcgi3),3)package-$(CONFIG_PACKAGE_webcgi4) += my/webcgi$(curdir)/my/webcgi/variants += $(if $(CONFIG_PACKAGE_webcgi4),4)$(curdir)/my/webcgi/default-variant := 3$(curdir)/my/webcgi/compile += $(curdir)/libs/libnl/compile \    $(curdir)/libs/toolchain/compile $(curdir)/system/ubus/compile \    $(if $(CONFIG_USE_GLIBC),$(curdir)/libs/toolchain/compile) | 
可以看到,webcgi3/4选中的都是my/webcgi,实际上是同一个目标。但是会更新variants变量。
可以看到依赖是多个VARIANT的并集。选中两个包后,再看package/Makefile生成的编译信息:
1 2 3 4 5 6 7 8 9 10 11  | package/my/webcgi/compile: package/libs/libnl/compile package/libs/toolchain/compile \                            package/system/ubus/compile                                 @+  /work/openwrt/scripts/time.pl "time: package/my/webcgi/3/compile" $(SUBMAKE) -r \        -C package/my/webcgi BUILD_SUBDIR="package/my/webcgi" BUILD_VARIANT="3" compile             @+  /work/openwrt/scripts/time.pl "time: package/my/webcgi/4/compile" $(SUBMAKE) -r \        -C package/my/webcgi BUILD_SUBDIR="package/my/webcgi" BUILD_VARIANT="4" compile# aliasespackage/webcgi/compile: package/my/webcgi/compile | 
可以看到,实际上编译了两次,BUILD_VARIANT不同而已。通常不同的VARIANT,其PKG_BUILD_DIR不同,如果相同,编译一次后,编译另外一个VARIANT,OPENWRT检测到没有变化,就不会重新编译。就没有意义了。
从上面生成的信息可以看到,编译,实际上是进入到package/my/webcgi里面,执行compile。prepare、configure、compile比较简单,这里重点强调下安装。
首先,必须定义install,否则不会编译,并告警:
$(warning WARNING: skipping webcgi4 -- package has no install section)
第一步:
编译产物安装的stamp文件是:$(PKG_BUILD_DIR)/.pkgdir/webcgi4.installed
安装目录是:$(PKG_BUILD_DIR)/.pkgdir/webcgi4/
第二步:
然后staging里面有个root目录:/work/openwrt/staging_dir/target-mips_4kec_musl/root-realtek/
stamp文件:stamp/.webcgi4_installed
将第一步安装的文件安装到这个目录。
第三步:
安装ipkg,检查依赖等。
PDIR_webcgi4:=/work/openwrt/bin/packages/mips_4kec/base
IPKG_webcgi4:=$(PDIR_webcgi4)/webcgi4$(ABIV_webcgi4)_1.0.0-1_mips_4kec.ipk
IDIR_webcgi4:=$(PKG_BUILD_DIR)/ipkg-mips_4kec/webcgi4
.compile: $(IPKG_webcgi4) \
/work/openwrt/staging_dir/target-ips_4kec_musl/pkginfo/webcgi4.provides
$(IPKG_webcgi4) 和 provides执行的规则相同:
1 把文件安装到$(IDIR_webcgi4),然后生成provides。
    2 生成provides
    3 检查依赖,生成missing
    4 执行strip
5 生成在$(IDIR_webcgi4)/CONTROL目录下,生成包信息
6 生成IPK文件
参考
https://openwrt.org/docs/guide-developer/packages
https://openwrt.org/docs/guide-developer/build-system/use-patches-with-buildsystem