Arm linux 內核構建

1、概述linux

本文基於Linux Kernel 4.10版本講解。函數

Linux內核採用相似於GNU Make的kbuild構建而成,關於內核的構建系統kbuild,能夠先看本公衆號內之前的文章:ui

Kbuild結構簡介

 

arm linux 內核的構建分爲三次編譯連接,一次組合。三次連接的中間結果分別是:spa

        1.arch/arm/boot/compressed/vmlinux.net

        2.arch/arm/boot/vmlinux.binip

        3.arch/arm/boot/setup.binci

最後的組合就是將vmlinux.bin和setup.bin組合成arch/arm/boot/zImage:字符串

 

 2、vmlinux的構建get

vmlinux的構建在頂層的Makefile中:cmd

cmd_link-vmlinux =                                         \

     $(CONFIG_SHELL) $<$(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) ;      \

     $(if $(ARCH_POSTLINK), $(MAKE) -f$(ARCH_POSTLINK) $@, true)

    

vmlinux: scripts/link-vmlinux.sh vmlinux_prereq$(vmlinux-deps) FORCE

         +$(callif_changed,link-vmlinux)

 

其中,call是make的內置函數,用於調用用戶本身定義的帶有參數的函數,這裏調用的是if_changed,參數是link-vmlinux。

 

if_changed是scripts/Kbuild.include裏定義的一個函數,定義以下:

 

if_changed = $(if $(strip $(any-prereq) $(arg-check)),   \

@set -e;                                                                                  \

$(echo-cmd) $(cmd_$(1));                                                 \

echo 'cmd_$@ :=$(make-cmd)' > $(dot-target).cmd)

 

any-prereq檢查是否有依賴比目標新,或者依賴尚未建立;arg-check檢查編譯目標的命令相對上次是否發生變化。set –e 命令表示make出錯時直接退出,加個@符號表示不顯示該set命令。cmd_$(1)中的1表示傳給if_changed的第一個參數。嵌入式物聯網智能硬件企鵝意義氣嗚嗚吧久零就易,在這裏傳給if_changed的實參是link-vmlinux,因此cmd_$(1)展開後爲cmd_link-vmlinux。

 

注意cmd_link-vmlinux中的$<表示規則中的第一個依賴,即scripts/link-vmlinux.sh。這個腳本用於vmlinux的連接,內容以下:

 

# Link of vmlinux

# ${1} - optionalextra .o files

# ${2} - output file

vmlinux_link()

{

    locallds="${objtree}/${KBUILD_LDS}"

    local objects

 

    if [ "${SRCARCH}" !="um" ]; then

        if [ -n"${CONFIG_THIN_ARCHIVES}" ]; then

            objects="--whole-archivebuilt-in.o ${1}"

        else

            objects="${KBUILD_VMLINUX_INIT}   \

                --start-group                                           \

                ${KBUILD_VMLINUX_MAIN}             \

                --end-group                                           \

                ${1}"

        fi

 

        ${LD} ${LDFLAGS}${LDFLAGS_vmlinux} -o ${2}      \

            -T ${lds} ${objects}

         else

            ... ...

         fi

}

 

若是平臺不是「um」,就將變量KBUILD_VMLINUX_INIT和KBUILD_VMLINUX_MAIN中的目標文件連接爲vmlinux;不然就直接編譯爲vmlinux,也就是式中的${2}。

 

接下來以core-y來分析變量KBUILD_VMLINUX_MAIN:

 

Linux-4.10/Makefile:

exportKBUILD_VMLINUX_INIT := $(head-y) $(init-y)

exportKBUILD_VMLINUX_MAIN := $(core-y) $(libs-y) $(drivers-y) $(net-y) $(virt-y)

exportKBUILD_LDS          :=arch/$(SRCARCH)/kernel/vmlinux.lds

 

… …

core-y                := usr/

… …

core-y                += kernel/ certs/ mm/ fs/ ipc/security/ crypto/ block/

… …

core-y                := $(patsubst %/, %/built-in.o,$(core-y))

 

make 的內置函數patsubst用於查找模式匹配的字符串,並進行替換。在上面這句語句裏,就是將全部‘/’替換成‘/built-in.o’。所以core-y最終變爲:

 

core-y :=user/built-in.o kernel/built-in.o mm/built-in.o fs/built-in.o ipc/built-in.osecurity/ built-in.o crypto/ built-in.o block/ built-in.o

 

再看其餘幾個相似的賦值語句:

init-y                   := $(patsubst %/,%/built-in.o, $(init-y))

drivers-y           :=$(patsubst %/, %/built-in.o, $(drivers-y))

net-y                  := $(patsubst %/,%/built-in.o, $(net-y))

libs-y1                := $(patsubst %/, %/lib.a,$(libs-y))

libs-y2                := $(patsubst %/, %/built-in.o,$(libs-y))

libs-y                  := $(libs-y1) $(libs-y2)

virt-y                  := $(patsubst %/,%/built-in.o, $(virt-y))

 

不難看出,vmlinux就是由這些目錄下的built-in.o和lib.a連接而成。

 

vmlinux的另外一個依賴是vmlinux-deps,其構建規則也在頂層Makefile中定義:

 

Linux-4.10/Makefile:

vmlinux-dirs     := $(patsubst %/,%,$(filter %/, $(init-y)$(init-m) \

                        $(core-y) $(core-m) $(drivers-y)$(drivers-m) \

                        $(net-y) $(net-m) $(libs-y) $(libs-m)$(virt-y)))

 

vmlinux-deps :=$(KBUILD_LDS) $(KBUILD_VMLINUX_INIT) $(KBUILD_VMLINUX_MAIN)

… …

# The actual objectsare generated when descending,

# make sure noimplicit rule kicks in

$(sort$(vmlinux-deps)): $(vmlinux-dirs) ;

… …

$(vmlinux-dirs):prepare scripts

         $(Q)$(MAKE) $(build)=$@

 

目標vmlinux-deps的構建規則下沒有命令可執行,只依賴於另一個目標vmlinux-dirs, 該變量的賦值語句裏的filter表示過濾掉不以‘/’結尾的字符串。而filter的這些輸入變量,如core-y,其子目錄都是以‘/’結尾。所以vmlinux-dirs是一個多目標規則,至關於:

 

init: prepare scripts

         $(Q) $(MAKE) $(build) =$@

kernel: preparescripts

         $(Q) $(MAKE) $(build) =$@

… …

規則中的命令展開爲:

Make –f script/Makefile.buildobj=$@

Make的自動變量$@表示規則的目標,這裏就是要構建的子目錄init,kernel等。

 

總結一下,kbuild依次構建Makefile中指定的子目錄,生成built-in.o、lib.a等文件,而後連接爲vmlinux。

相關文章
相關標籤/搜索