(五) openwrt打包過程

標籤(空格分隔): 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文件夾下,執行目標compileinstall.下面我來看看進入image文件夾下,發生的故事.
打開tareget/linux/ramips/image/Makefile,咱們找了一圈,也沒找到咱們要的目標compileinstall;若是咱們是完整編譯,其實目標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格式的二進制文件,而後包括壓縮內核,爲內核製做頭部,最後將加工過的內核部分和文件系統部分組合起來.

尾記

  1. 在網上查找資料的時候,發現大部分資料要麼雷同,要麼淺嘗輒止.
  2. 下面這篇文章在我深刻學習的過程當中,起了不小的做用.連接;就是排版太差了,我纔有了本身寫寫的衝動.
  3. openwrt的整個編譯過程是很複雜的,想一想電腦一秒能夠作多少次計算,而一次完整編譯輕輕鬆鬆就要兩三個小時.可想而知編譯過程之複雜.可是我以爲我把大致的編譯過程是弄明白了,也歡迎你們交流.一共用了5篇的篇幅,大致的編譯過程也算是交代完了.
  4. 紙上得來終覺淺,下面我以爲我還須要更多的改改寫寫來加深瞭解.最近在瞎看看linux內核相關的東西,那本書上也說了要加深學習瞭解,須要更多的修修補補.與你們共勉.
相關文章
相關標籤/搜索