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