kernel_001.png

如果你在shell prompt只下make命令而已,第一個rule永遠被執行。 這叫default goal。如果你有指定target名字,例如make all,則會 去執行這個target的動作,此Makefile中會執行 help target 中的命令的

@make -s U_help "UBoot make target help" 

@make -s K_help "Linux Kernel make target help"

@make -s F_help "Linux Fille System make target help"

 

kernel_002.png

 

kernel_003.png

 

 

kernel_004.png

make K_defc 會 test K_BUILD_DIR=(PWD)/build/linux是否存在有則移除,再make $(STEP_K_DEFC)的target=K_prepare  K_reset K_defconfig   K_build K_uimage K_upload

K_prepare:

kernel_006.png

kernel_013.png

 

K_reset:

kernel_008.png

bashrc.linux

export TOOLCHAIN_PATH=/opt/acrospeed/mips-linux-uclibc
export PATH=$PATH:${TOOLCHAIN_PATH}/bin

export HOST=mips-linux-uclibc
export CROSS_COMPILE=${HOST}-
export MALLOC_CHECK_=0
export MGCC=${CROSS_COMPILE}gcc

alias MLD=${CROSS_COMPILE}ld
alias MNM=${CROSS_COMPILE}nm
alias MDUMP=${CROSS_COMPILE}objdump
alias MCOPY=${CROSS_COMPILE}objcopy

K_SET_ENV        ?=. $(PWD)/bashrc.linux

K_ENV_EXEC       = $(K_SET_ENV); bash -c "$(1)"

K_BUILD_MAKE    =make -C $(K_DIR) O=$(K_BUILD_DIR)

linux kernel 執行 make -C /linux  O=/build/linux mrproper

 

kernel_016.png

使用eclipse可以把Enable Floding打開Makefile可以很簡潔的方式查看,因為沒有 M=xxx所以 KBUILD_SRC是空的

 

 

kernel_017.png

從上面看到,FORCE 既沒有依賴的規則,其底下也沒有可執行的命令。如果一個規則沒有命令或者依賴,而且它的目標不是一個存在的文檔名,在執行此規則時,目標總會被認為是最新的。也就是説,這個規則一旦被執 行,make 就認為它所表示的目標已經被更新過。當將這樣的目標(FORCE)作為一個規則的依賴時(如上的 vmlinux: ),由於依賴總被認為是被更新過的,所以作為依賴所在的規則定義的命令總會被執行。
make 有一個環境變數叫“MAKECMDGOALS”是make 執行當時命令列上指定了哪些工作目標. 此變數並不包含命令列選項或變數的賦值.

其中 $(if $(KBUILD_VERBOSE:1=)),@) 的用法看起來有點蹊蹺,實際上$(VAR:x=y) 這種語法相當於 $(patsubst x,y,$(VAR)) 的縮寫。這裡需要注意一點,x 和 y 前面不能有 ‘%’ 匹配符,這是因為 '%' 已經被默認添加,所以它就如同如下形式:
$(patsubst %x,%y,$(VAR))
這樣,$(if $(KBUILD_VERBOSE:1=)),@) 被展開為:
$(if $(patsubst %1,%,$(KBUILD_VERBOSE)),@)
所以,只要 KBUILD_VERBOSE 為非 1 的任何字元時,整個運算式的結果就是 : @ 。如果 KBUILD_VERBOSE 為 1 時,那麼整個運算式結果為空。實際上,運算式結果為 @ 時,就是希望後面的命令能夠靜默執行。

sub-make:會先assigned KBUILD_SRC=$(CURDIR) 然後

make -C /home/ip1829/SDK_ICPlus_IP1829A_IP211_FW_v2.11.6/build/linux \
KBUILD_SRC=/home/ip1829/SDK_ICPlus_IP1829A_IP211_FW_v2.11.6/src/linux \
KBUILD_EXTMOD="" -f /home/ip1829/SDK_ICPlus_IP1829A_IP211_FW_v2.11.6/src/linux/Makefile \
mrproper

 

 

kernel_018.png

目錄會swtich to KBUILD_OUTPUT 然後執行 KBUILD_SRC目錄下的Makefile

 

kernel_019.png

 

kernel_021.png

/arch/mips/Makefile

kernel_022.png

$(init-y)= init/

$(core-y)=user/ arch/mips kernel/ mm/ fs/ ipc/ security/ crypto/ block/

$(net-y)=net/

$(lib-y)=lib/ arch/mips/fw/lib/ arch/mips/lib/

 

kernel_015.png

執行 make -f KBUILD_SRC/scripts/Makefile.clean obj=$(patsubst _clean_%,%,$@)

 

第一次執行Makefile.clean obj=/arch/mips

kernel_023.png

Makefile.clean include arch/mips/Kbuild

          Kbuild include Kbuild.platforms

                      Kbuild.platform 根據 platforms include arch/mips/bcm63xx/Platform.... arch/mips/Icplus/Platform

Obj- 是不需要include的platform 也就是會被clean的目錄

 

K_defconfig:

kernel_007.png

linux kernel 執行 make -C /linux  O=/build/linux apollo_defconfig

 

 

kernel_012.png

KBUILD_OUTPUT=/build/linux

 

有一個 make 的環境變量叫“MAKECMDGOALS”,這個變量中會存放你所指定的終極目標的列表,如果在命令行上,你沒有指定目標,那麼,這個變量是空值。

 

 

kernel_010.png

 

linux/arch/mips/configs

kernel_009.png

Linux內核的Makefile與我們平時寫的Makefile有所不同,它由五部分組成:
    Makefile : 頂層Makefile。
    config: kernel配置文件。
    arch/xxx/Makefile: 具體架構的Makefile。
    scripts/Makefile.xxx : 通用規則。
    kbuild Makefile: 整個kernel中大約有數百個這種文件。

 

if函數的語法是:
$(if <condition>,<then-part>) 或是 $(if <condition>,<then-part>,<else-part>)
可見,if函數可以包含「else」部分,或是不含。即if函數的參數可以是兩個,也可以是三個。<condition>參數是if的表達式,如果其返回的為非空字符串,那麼這個表達式就相當於返回真,於是,<then-part>會被計算,否則<else-part>會被計算。
而if函數的返回值是,如果<condition>為真(非空字符串),那個<then-part>會是整個函數的返回值,如果<condition>為假(空字符串),那麼<else-part>會是整個函數的返回值,此時如果<else-part>沒有被定義,那麼,整個函數返回空字串。
所以,<then-part>和<else-part>只會有一個被計算。

 

origin函數不像其它的函數,他並不操作變數的值,他只是告訴你你的這個變數是哪裡來的?
其語法是:$(origin <variable>)
注意,<variable>是變數的名字,不應該是引用。所以你最好不要在<variable>中使用「$」字符。Origin函數會以其返回值來告訴你這個變數的「出生情況」,下面,是origin函數的返回值:
「undefined」      如果<variable>從來沒有定義過,origin函數返回這個值「undefined」。
「default」           如果<variable>是一個默認的定義,比如「CC」這個變數,這種變數我們將在後面講述。
「environment」  如果<variable>是一個環境變數,並且當Makefile被執行時,「-e」參數沒有被打開。
「file」                 如果<variable>這個變數被定義在Makefile中。
「command line」如果<variable>這個變數是被命令行定義的。
「override」         如果<variable>是被override指示符重新定義的。
「automatic」       如果<variable>是一個命令運行中的自動化變數。關於自動化變量將在後面講述。

這些信息對於我們編寫Makefile是非常有用的,例如,假設我們有一個Makefile其包了一個定義文件Make.def,在Make.def中定義了一個變數「bletch」,而我們的環境中也有一個環境變數「bletch」,此時,我們想判斷一下,如果變量來源於環境,那麼我們就把之重定義了,如果來源於Make.def或是命令行等非環境的,那麼我們就不重新定義它。於是,在我們的Makefile中,我們可以這樣寫:
ifdef bletch
      ifeq "$(origin bletch)" "environment"
           bletch = barf, gag, etc.
      endif
endif
當然,你也許會說,使用override關鍵字不就可以重新定義環境中的變數了嗎?為什麼需要使用這樣的步驟?是的,我們用override是可以達到這樣的效果,可是override過於粗暴,它同時會把從命令行定義的變數也覆蓋了,而我們只想重新定義環境傳來的,而不想重新定義命令行傳來的。

 

shell函數也不像其它的函數。
顧名思義,它的參數應該就是操作系統Shell的命令。它和反引號「`」是相同的功能。這就是說,shell函數把執行操作系統命令後的輸出作為函數返回。於是,我們可以用操作系統命令以及字符串處理命令awk,sed等等命令來生成一個變數,如:
contents := $(shell cat foo)
files := $(shell echo *.c)

 

foreach的語法是:$(foreach <var>,<list>,<text>)
這個函數的意思是,把參數<list>中的單詞逐一取出放到參數<var>所指定的變量中,然後再執行<text>所包含的表達式。每一次<text>會返回一個字符串,循環過程中,<text>的所返回的每個字符串會以空格分隔,最後當整個循環結束時,<text>所返回的每個字符串所組成的整個字符串(以空格分隔)將會是foreach函數的返回值。
所以,<var>最好是一個變量名,<list>可以是一個表達式,而<text>中一般會使用<var>這個參數來依次枚舉<list>中的單詞。舉個例子:
names := a b c d
files := $(foreach n,$(names),$(n).o)
上面的例子中,$(name)中的單詞會被挨個取出,並存到變量「n」中,「$(n).o」每次根據「$(n)」計算出一個值,這些值以空格分隔,最後作為foreach函數的返回,所以,$(files)的值是「a.o b.o c.o d.o」。

 

call函數是唯一一個可以用來創建新的參數化的函數。你可以寫一個非常複雜的表達式,這個表達式中,你可以定義許多參數,然後你可以用call函數來向這個表達式傳遞參數。
其語法是:$(call <expression>,<parm1>,<parm2>,<parm3>...)當make執行這個函數時,<expression>參數中的變量,如$(1),$(2),$(3)等,會被參數<parm1>,<parm2>,<parm3>依次取代。而<expression>的返回值就是call函數的返回值。

 

過濾函數:filter。:$(filter <pattern...>,<text>)
功能:以<pattern>模式過濾<text>字符串中的單詞,保留符合模式<pattern>的單詞。可以有多個模式。
返回:返回符合模式<pattern>的字串。示例:
sources := foo.c bar.c baz.s ugh.h
foo: $(sources)
cc $(filter %.c %.s,$(sources)) -o foo
$(filter %.c %.s,$(sources))返回的值是「foo.c bar.c baz.s」。

 

反過濾函數:filter-out:$(filter-out <pattern...>,<text>)
功能:以<pattern>模式過濾<text>字符串中的單詞,去除符合模式<pattern>的單詞。可以有多個模式。
返回:返回不符合模式<pattern>的字串。示例:
objects=main1.o foo.o main2.o bar.o
mains=main1.o main2.o
$(filter-out $(mains),$(objects)) 返回值是「foo.o bar.o」。

 

$(patsubst <pattern>,<replacement>,<text>)
名稱:模式字符串替換函數——patsubst
功能:查找<text>中的單詞(單詞以「空格」、「Tab」或「回車」「換行」分隔)是否符合模式<pattern>,如果匹配的話,則以<replacement>替換。這裡,<pattern>可以包括通配符「%」,表示任意長度的字串。如果<replacement>中也包含「%」,那麼,<replacement>中的這個「%」將是<pattern>中的那個「%」所代表的字串。(可以用「\」來轉義,以「\%」來表示真實含義的「%」字符)
返回:函數返回被替換過後的字符串。
示例:$(patsubst %.c,%.o,x.c.c bar.c)
把字串「x.c.c bar.c」符合模式[%.c]的單詞替換成[%.o],返回結果是「x.c.o bar.o
備註:這和我們前面「變量章節」說過的相關知識有點相似。

如:$(var:<pattern>=<replacement>)
相當於$(patsubst <pattern>,<replacement>,$(var))」,
而「$(var: <suffix>=<replacement>)則相當於
$(patsubst %<suffix>,%<replacement>,$(var))」。
例如有:objects = foo.o bar.o baz.o
那麼,「$(objects:.o=.c)」和「$(patsubst %.o,%.c,$(objects))」是一樣的。

 

 

你知道 Linux 內核是如何構建的嗎

Linux內核Makefile筆記

 vmlinux是如何煉成的-- kernel makefile

 

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 peter27863043 的頭像
    peter27863043

    檸檬傻斌-無料

    peter27863043 發表在 痞客邦 留言(0) 人氣()