ILD

openwrt package分析
作者:Yuan Jianpeng 邮箱:yuanjp89@163.com
发布时间:2021-4-19 站点:Inside Linux Development

    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.mk
 
PKG_NAME:=webcgi
PKG_VERSION:=1.0.0
PKG_RELEASE:=1
 
include $(INCLUDE_DIR)/package.mk
 
define Package/webcgi
  CATEGORY:=My package
  TITLE:=webcgi
  DEPENDS := +libnl +libblobmsg-json +libubus
endef
 
define Build/Prepare
        mkdir -p $(PKG_BUILD_DIR)/{lib,cgi}
endef
 
define Build/Compile
        CFLAGS="$(TARGET_CFLAGS)" LDFLAGS="$(TARGET_LDFLAGS)" make -C src/ \
            O=$(PKG_BUILD_DIR)/ CC=$(TARGET_CC)
endef
 
define Package/webcgi/install
        $(INSTALL_DIR) $(1)/web/cgi-bin
        $(INSTALL_BIN) $(PKG_BUILD_DIR)/webcgi $(1)/web/cgi-bin
endef
 
$(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/Makefile
 
Package: webcgi
Version: 1.0.0-1
Depends: +libc +USE_GLIBC:librt +USE_GLIBC:libpthread +libnl +libblobmsg-json +libubus
Conflicts:
Menu-Depends:
Provides:
Section: My section
Category: My package
Repository: base
Title: webcgi
Maintainer:
Source:
Type: ipkg
Description: 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
         webcgi
 
 
endmenu



定义中的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;) 
         
# aliases
package/webcgi/compile: package/my/webcgi/compile


可以看到有alias的支持,所以编译package/webcgi/compile,等价于:package/my/webcgi/compile。


Variant支持

一个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:=webcgi2
PKG_VERSION:=1.0.0
PKG_RELEASE:=1
 
include $(INCLUDE_DIR)/package.mk
 
define Package/webcgi3
  CATEGORY:= My package
  TITLE:=webcgi3
  DEPENDS := +libnl
  VARIANT:=3
endef
 
define Package/webcgi4
  CATEGORY:= My package
  TITLE:=webcgi4
  DEPENDS := +libubus
  VARIANT:=4
endef
 
define Build/Prepare
        mkdir -p $(PKG_BUILD_DIR)/{lib,cgi}
endef
 
define Build/Compile
    touch $(PKG_BUILD_DIR)/webcgi
endef
 
define Package/webcgi3/install
        $(INSTALL_DIR) $(1)/web/cgi-bin
        $(INSTALL_BIN) $(PKG_BUILD_DIR)/webcgi $(1)/web/cgi-bin
endef
 
define Package/webcgi4/install
        $(INSTALL_DIR) $(1)/web/cgi-bin
        $(INSTALL_BIN) $(PKG_BUILD_DIR)/webcgi $(1)/web/cgi-bin
endef
 
$(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_webcgi
Source-Makefile: package/my/webcgi/Makefile
 
Package: webcgi3
Version: 1.0.0-1
Depends: +libc +USE_GLIBC:librt +USE_GLIBC:libpthread +libnl
Conflicts:
Menu-Depends:
Provides:
Build-Variant: 3
Section: opt
Category: My package
Repository: base
Title: webcgi3
Maintainer:
Source:
Type: ipkg
Description: webcgi3
 
@@
 
Package: webcgi4
Version: 1.0.0-1
Depends: +libc +USE_GLIBC:librt +USE_GLIBC:libpthread +libubus
Conflicts:
Menu-Depends:
Provides:
Build-Variant: 4
Section: opt
Category: My package
Repository: base
Title: webcgi4
Maintainer:
Source:
Type: ipkg
Description: 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
         webcgi4
 
 
endmenu

可以看到,包括了两个包,是可以独立选择的。


生成的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
 
# aliases
package/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


Copyright © linuxdev.cc 2017-2024. Some Rights Reserved.