目錄函數
Tags : Makefileui
本週是成胖子每週一博的第五週.
更好的閱讀體驗,請點擊這裏命令行
前一篇博客中,咱們已經知道整個openwrt的編譯順序,本文咱們來探討與開發者息息相關的單個ipk的編譯過程.在開發者進行二次開發的時候,咱們既能夠單個編譯ipk也能夠完整編譯整個鏡像文件.在完整編譯的時候,咱們選中的單個ipk一樣會被編入鏡像文件中,因此完整編譯一樣會進行單個ipk包的編譯.code
咱們前面在stampfile函數部分提升過,當編譯目標爲package/stamp-compile的時候,實際執行的目標爲package/compile;同時根據subdir函數的定義,package/compile將會依賴於package文件夾下被make menuconfig
選中的子文件夾的compile.簡而言之,當咱們執行make package/compile
至關於對全部選中的文件夾執行make package/XXX/compile
.blog
咱們以一個具體的包的編譯過程來看看,本文咱們以package/network/services/dropbear這個包爲例.當咱們在命令行中輸入make package/network/services/dropbear/compile
的時候,make將會讀入dropbear下的Makefile文件,同時目標指定爲compile.1ip
由於空間問題,我在這裏不展開具體的Makefile文件.相信能看這篇博客的同窗應該都有源碼,本身打開即是.
下面咱們根據GNU make語法來分析這個Makefile文件.它包含了兩個.mk文件:一個是rules.mk,另外一個是package.mk.ci
rules.mk
: 這個文件咱們前文已經提到過了,主要是大量變量的定義.包括各類路徑的定義,編譯器的定義等等.其中要說明的是.config文件也是這裏被包含進來的.開發
package.mk
: 這個文件首先定義和補充了一些變量.其次是openwrt爲咱們封裝了BuildPackage函數,對於普通開發者而言,只須要參照模板定義相應的變量,最後調用這個函數便可.get
其他的咱們能夠認爲是變量的賦值語句,很明顯使用它們的地方並不在這裏.關於模板和變量值的說明及做用.,你能夠參照官方說明,也能夠在網上找到一大堆資料.編譯器
最後,最重要的語句是這一句:
$(eval $(call BuildPackage,dropbear))
這裏將會把dropbear做爲參數值傳給函數BuildPackage
Tips
: 不知道你們還記得咱們Makefile的執行順序麼?Makefile是先讀入全部信息,展開,而後生成依賴關係.最後再按依賴關係前後來執行.
BuildPackage的定義在package.mk中,定義以下:
define BuildPackage $(Build/IncludeOverlay) $(eval $(Package/Default)) $(eval $(Package/$(1))) ifdef DESCRIPTION $$(error DESCRIPTION:= is obsolete, use Package/PKG_NAME/description) endif ifndef Package/$(1)/description define Package/$(1)/description $(TITLE) endef endif BUILD_PACKAGES += $(1) $(STAMP_PREPARED): $$(if $(QUILT)$(DUMP),,$(call find_library_dependencies,$(DEPENDS))) $(foreach FIELD, TITLE CATEGORY SECTION VERSION, ifeq ($($(FIELD)),) $$(error Package/$(1) is missing the $(FIELD) field) endif ) $(if $(DUMP), \ $(Dumpinfo/Package), \ $(foreach target, \ $(if $(Package/$(1)/targets),$(Package/$(1)/targets), \ $(if $(PKG_TARGETS),$(PKG_TARGETS), ipkg) \ ), $(BuildTarget/$(target)) \ ) \ ) $(if $(PKG_HOST_ONLY)$(DUMP),,$(call Build/DefaultTargets,$(1))) endef
那麼這裏的$(1)就是指的傳入的參數dropbear.這裏包含了一些檢查和補充變量定義.繼續深究下去的線索是第25~32行之間.這裏我將它簡化後就是展開BuildTarget/ipkg;同時第33行,將dropbear看成參數傳給函數Build/DefaultTargets.
BuildTarget/ipkg定義在package-ipkg.mk中,咱們須要重點關注其中的冒號,這個造成咱們的依賴關係.
Build/DefaultTargets定義在package.mk中,其中造成了咱們stamp-*的依賴關係.根據這些依賴關係,我將關係圖繪製以下:
當咱們得出依賴關係後,執行過程就是倒序進行而已,即從上圖的右邊向左執行.這也能夠和咱們預料的執行過程相印證.
$(stamp-prepared)
: 主要完成代碼包的準備工做,若是開發者定義了build/prepare,則執行build/prepare.若是開發者未定義,則執行build/prepare/default這其中包含了多個情形,最爲常見的是將dl下的壓縮包解壓並打上patch.
$(stamp-built)
: 這個將會進入到build_dir/target-XXX/下對應的文件夾進行編譯.同時將會帶入一些定義好的變量.好比CFLAGS,LDFLAGS.
IPKG_(1)
: 這個目標將會將編譯好的文件安裝到對應的ipkg-arch目錄下,同時將這個目錄打包爲ipk文件.
本週博客基本就到這裏,原本私心想着元旦沒啥大事,能夠寫兩篇的.結果混着混着就到第三天晚上了.剩下的最後一篇咱們看看單個的ipk編譯好了,內核的編譯過程,最後的打包過程.整個鏡像文件由哪些部分組成.下週再見.
所有過程分析請參見前文,至少還應包含必要的檢查,tools和toolchain的編譯.這裏由於咱們主要分析單個ipk的編譯過程,因此我將之略過↩