標籤(空格分隔): Makefilehtml
本週是成胖子每週一博第六週,更好地閱讀體驗,請點擊這裏linux
前面咱們已經講了openwrt編譯的大部分過程,包括大體的編譯步驟,ipk的編譯等.今天是我這個系列的最後一篇,咱們來看看openwrt的各個部分是如何組織成爲最後的bin文件的.
最後一個步驟,咱們的執行的目標是target/install.函數
咱們首先經過Makefile來分析下咱們的依賴關係.學習
經過前幾篇的分析,咱們應當知道此時target/install將依賴於target/linux/install.
以下是target/linux/Makefile
的節選:ui
export TARGET_BUILD=1 prereq clean download prepare compile install menuconfig nconfig oldconfig update refresh: FORCE @+$(NO_TRACE_MAKE) -C $(BOARD) $@
咱們能夠看出,此時執行compile將會進入對應的目標平臺執行目標compile,咱們以mt7620a爲例.它屬於ramips平臺.
以下是target/linux/ramips/Makefile
的節選:.net
include $(INCLUDE_DIR)/target.mk $(eval $(call BuildTarget))
在這個Makefile文件中,咱們找不到目標compile,它被文件target.mk封裝.咱們在ipk的編譯中,已經見過相似的用法.
以下是include/target.mk
的節選:unix
ifeq ($(TARGET_BUILD),1) include $(INCLUDE_DIR)/kernel-build.mk BuildTarget?=$(BuildKernel) endif
從上面的節選咱們看到變量TARGET_BUILD爲1,因此這裏函數BuildTarget其實等於在kernel-build.mk
定義的變量BuildKernel.
以下是include/kernel-build.mk
的節選:code
define BuildKernel $(if $(QUILT),$(Build/Quilt)) $(if $(LINUX_SITE),$(call Download,kernel)) $(STAMP_CONFIGURED): $(STAMP_PREPARED) $(LINUX_KCONFIG_LIST) $(TOPDIR)/.config $(Kernel/Configure) touch $$@ $(LINUX_DIR)/.image: $(STAMP_CONFIGURED) $(if $(CONFIG_STRIP_KERNEL_EXPORTS),$(KERNEL_BUILD_DIR)/symtab.h) FORCE $(Kernel/CompileImage) $(Kernel/CollectDebug) touch $$@ install: $(LINUX_DIR)/.image +$(MAKE) -C image compile install TARGET_BUILD= endef
咱們繞來繞去,終於找到了咱們要的目標,install依賴於$(LINUX_DIR)/.image,htm
$(LINUX_DIR)/.image的依賴和執行就在節選中,咱們略過,blog
同時將進入image文件夾下,執行目標compile和install.下面我來看看進入image文件夾下,發生的故事.
打開tareget/linux/ramips/image/Makefile
,咱們找了一圈,也沒找到咱們要的目標compile和install;若是咱們是完整編譯,其實目標compile已經被執行過了.此時咱們以install爲目標.玄機就在最後一句$(eval $(call BuildImage))
中,函數BuildImage被定義在include/image.mk
中,如下爲節選:
define BuildImage ifeq ($(IB),) .PHONY: download prepare compile clean image_prepare mkfs_prepare kernel_prepare install compile: $(call Build/Compile) clean: $(call Build/Clean) image_prepare: compile mkdir -p $(KDIR)/tmp $(call Image/Prepare) else image_prepare: mkdir -p $(KDIR)/tmp endif mkfs_prepare: image_prepare $(call Image/mkfs/prepare) kernel_prepare: mkfs_prepare $(call Image/BuildKernel) $(if $(CONFIG_TARGET_ROOTFS_INITRAMFS),$(if $(IB),,$(call Image/BuildKernel/Initramfs))) $(call Image/InstallKernel) $(foreach device,$(TARGET_DEVICES),$(call Device,$(device))) $(foreach fs,$(TARGET_FILESYSTEMS) $(fs-subtypes-y),$(call BuildImage/mkfs,$(fs))) install: kernel_prepare $(foreach fs,$(TARGET_FILESYSTEMS), $(call Image/Build,$(fs)) ) $(call Image/mkfs/ubifs) $(call Image/Checksum,md5sum --binary,md5sums) $(call Image/Checksum,openssl dgst -sha256,sha256sums) endef
這裏咱們看到了咱們的目標install和它的依賴關係及執行語句,這裏$(TARGET_FILESYSTEMS)一般爲squashfs.其中大部分函數定義在咱們對應平臺的image文件夾下的Makefile中.
上文中第28行需稍加註意,這裏調用函數BuildImage/mkfs,定義以下:
define BuildImage/mkfs install: mkfs-$(1) .PHONY: mkfs-$(1) mkfs-$(1): mkfs_prepare $(Image/mkfs/$(1)) $(call Build/mkfs/default,$(1)) $(call Build/mkfs/$(1),$(1)) $(KDIR)/root.$(1): mkfs-$(1) endef
這裏能夠看到目標install依賴於mkfs-(1).
如此咱們能夠獲得整個依賴關係圖以下:
圖片不清晰能夠下載下來查看.
上一節咱們分析了依賴關係,執行過程其實就是倒敘執行的過程.
主要編輯過程就是先將內核編譯完成,而後將安裝ipk的root-ramips文件夾製做爲squash格式的二進制文件,而後包括壓縮內核,爲內核製做頭部,最後將加工過的內核部分和文件系統部分組合起來.
openwrt
的整個編譯過程是很複雜的,想一想電腦一秒能夠作多少次計算,而一次完整編譯輕輕鬆鬆就要兩三個小時.可想而知編譯過程之複雜.可是我以爲我把大致的編譯過程是弄明白了,也歡迎你們交流.一共用了5篇的篇幅,大致的編譯過程也算是交代完了.