近日添加了一个包到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 ,就可以套用到其他软件包上了。