背景

近日添加了一个包到openwrt中,在此过程中又对openwrt多了一些认识

这个包本身自带了kconfig,可直接在这个包里面执行make menuconfig进行配置,然后执行make

但要集成到openwrt中,就需要把这些配置项都集成到openwrt的配置中。

面对这种情况,当然是要找个现成的例子做参考,首先想到的就是busybox。

以下以busybox为例进行说明,源码摘自github https://github.com/openwrt/openwrt/tree/master/package/utils/busybox

如何集成配置项

busybox本身也自带了配置项,但实际上我们却可以在openwrt的总的配置项中对其进行配置,而无需进入busybox目录单独对其做配置。

通过查看busybox包的makefile,可以看到,这个集成是这么做的。
对于busybox原生的配置项不做改动,而是针对每个配置项都另外生成一个对应的配置项,用于集成到openwrt中。
这些配置项在 openwrt/package/utils/busybox/config目录中。并通过 openwrt/package/utils/busybox/Config.in 文件连接到openwrt配置项。下面结合代码分析下。

从Makefile中可以看到,对于openwrt来说,busybox包的配置,就来源于Config.in

文件 openwrt/package/utils/busybox/Makefile

define Package/busybox/config
    source "$(SOURCE)/Config.in"
endef

先来看下openwrt/package/utils/busybox/Config.in这个总的配置文件。

文件 openwrt/package/utils/busybox/Config.in

if PACKAGE_busybox

config BUSYBOX_CUSTOM
    bool "Customize busybox options"
    default n
        help
          Enabling this allows full customization of busybox settings.
          Note that there are many options here that can result in a build
          that doesn't work properly.  Enabling customization will mark your
          build as "tainted" for the purpose of bug reports.
          See the variables written to /etc/openwrt_release

          Unless you know what you are doing, you should leave this as 'n'

    source "Config-defaults.in"        #引入默认配置项的值

    if BUSYBOX_CUSTOM             #当选择了自定义配置项时
        source "config/Config.in"       #引入对应于busybox原生配置项的配置文件,允许用户完全自定义
    endif

config BUSYBOX_USE_LIBRPC
    bool
    default y if BUSYBOX_CUSTOM && BUSYBOX_CONFIG_FEATURE_HAVE_RPC
    default y if !BUSYBOX_CUSTOM && BUSYBOX_DEFAULT_FEATURE_HAVE_RPC

endif

这里面定义了一个BUSYBOX_CUSTOM配置项,当不选中时,就只引入默认配置"Config-default.in",当选中时,就再引入config目录下对应于busybox原生配置项的配置文件,以允许用户完全自定义这些配置。

先看不自定义配置的情况。此时Config.in就只引入了Config-defaults.in,打开这个文件,可以看到,里面是一系列以BUSYBOX_DEFAULT开头的配置项,如

文件 openwrt/package/utils/busybox/Config-defaults.in

config BUSYBOX_DEFAULT_HAVE_DOT_CONFIG
    bool
    default y
config BUSYBOX_DEFAULT_DESKTOP
    bool
    default n
config BUSYBOX_DEFAULT_EXTRA_COMPAT
    bool
default n

这些其实就是对应到busybox本身的所有配置项的。只是名字略有不同。最终,在Makefile中,会将这些配置项转换为busybox本身的配置文件。即

文件 openwrt/package/utils/busybox/Makefile

define Build/Configure
    grep 'CONFIG_BUSYBOX_$(BUSYBOX_SYM)' $(TOPDIR)/.config | sed -e "s,\\(# \)\\?CONFIG_BUSYBOX_$(BUSYBOX_SYM)_\\(.*\\),\\1CONFIG_\\2,g" > $(PKG_BUILD_DIR)/.config
    yes 'n' | $(MAKE) -C $(PKG_BUILD_DIR) $(MAKE_FLAGS) oldconfig
endef

从总的配置文件中,滤出所有CONFIG_BUSYBOX_$(BUSYBOX_SYM)开头的配置项,并通过sed将前缀CONFIG_BUSYBOX_$(BUSYBOX_SYM)去掉,生成用于busybox编译的.config文件。再执行一遍make oldconfig,以自动处理掉一些配置不合适的情况,修正最终的.config文件。

其中这个$(BUSYBOX_SYM)变量,也是在Makefile中赋值的。

文件 openwrt/package/utils/busybox/Makefile

BUSYBOX_SYM=$(if $(CONFIG_BUSYBOX_CUSTOM),CONFIG,DEFAULT)

这样就清楚了。busybox的makefile中,在未选中CONFIG_BUSYBOX_CUSTOM的情况下,BUSYBOX_SYM的值为DEFAULT,则将CONFIG_BUSYBOX_DEFAULT_xxx过滤出来,处理为busybox最终的配置项。这些CONFIG_BUSYBOX_DEFAULT_xxx是在Config-defaults.in文件中配置好的。

在选中了CONFIG_BUSYBOX_CUSTOM的情况下,则最终将CONFIG_BUSYBOX_CONFIG_xxx过滤出来使用。

接下来看自定义的情况。自定义的情况其实也很清晰,就是引入了config目录下的配置项。
这些配置项,跟busybox源码中的布局和内容完全一致,区别只是配置项的名字都为BUSYBOX_CONFIG开头,且默认值均为对应的BUSYBOX_DEFAULT_开头的配置项。记得吗,这些BUSYBOX_DEFAULT_开头的配置项都是在Config-default.in中配置的。如下例子

文件 openwrt/package/utils/busybox/config/init/Config.in

config BUSYBOX_CONFIG_INIT
    bool "init"
    default BUSYBOX_DEFAULT_INIT
    select BUSYBOX_CONFIG_FEATURE_SYSLOG
    help
init is the first program run when the system boots.

也就是说,当用户需要自定义的时候,引入了BUSYBOX_CONFIG_xxx的配置项,但其默认值还是用的已经配置好的。此时要自定义的就是在这个基础上做修改。

最终用户的配置就体现在BUSYBOX_CONFIG_xxx的配置项上。
如上文所述,在选中了CONFIG_BUSYBOX_CUSTOM的情况下,BUSYBOX_SYM的值为CONFIG,则将CONFIG_BUSYBOX_CONFIG_xxx过滤出来,处理为busybox最终的配置项。

配置项文件的生成

搞清楚了如何集成之后,接下来的问题就是,这些BUSYBOX_DEFAULT_xxx 和 BUSYBOX_CONFIG_xxx 的配置文件,是怎么来的,如此多的配置项,肯定不可能时手工修改的,必然有自动化处理。

是的,这些BUSYBOX_CONFIG_xxx配置项,就是从busybox本身的配置项生成而来。而这些BUSYBOX_DEFAULT_xxx的默认配置值,其实就是从一份配置好的busybox.config文件生成而来。在busybox的包中,就提供了两个脚本 convert_defaults.pl 和 convert_menuconfig.pl,用来生成配置项和默认配置值

使软件包随配置项改变而重新编译

一般软件包在编译过一次之后,如果源码没有改动,则下次make无须重新编译。

但对于busybox这种包,源码未变,配置改变了的话,也是需要重新编译的。
现在的问题在于,用户修改配置项,是在openwrt的.config修改,根本不会改动到busybox这个目录下的文件。
那么busybox包就需要有一个方法,来监控配置项的变动。如果配置项变化,则需要重新编译。如何监控呢?从makefile中也可以找到答案


文件 openwrt/package/utils/busybox/Makefile

ifeq ($(DUMP),)
  STAMP_CONFIGURED:=$(strip $(STAMP_CONFIGURED))_$(shell grep '^CONFIG_BUSYBOX_' $(TOPDIR)/.config | mkhash md5)
endif

此处设置了STAMP_CONFIGURED变量,这个变量的值,是将.config中所有CONFIG_BUSYBOX_滤出,再做md5得到的值。一旦这些配置项发生变化,则md5的值会改变,STAMP_CONFIGURED的值也会改变。编译包的时候,就能判断出需要重新编译。

具体的,STAMP_CONFIGURED值是在package.mk中使用。这里还有其他的类似变量,只要改变了,就说明需要重新执行对应的操作。如STAMP_CONFIGURED,STAMP_BUILT,STAMP_INSTALLED等。

这个配置项,也会在软件包的编译目录体现出来。如果没有对其赋值,则在编译目录下,可看到名字类似 .configured_yyy 的隐藏文件。

对其进行赋值之后,这个文件的形式会变成 .configured_yyy_622f380fff06dde988852308f044653b 这种形式,后面跟着的就是由配置项生产的md5值。

结语

分析清楚了busybox的套路之后,修改下 convert_defaults.pl 和 convert_menuconfig.pl ,就可以套用到其他软件包上了。

01-13 22:32