$(Q)變量
內(nèi)核 Makefile 文件 238 行到 259 行的注釋中知道,$(Q)變量的作用是決定是否在執(zhí)行命令時(shí)輸出詳細(xì)的命令信息。底下對其有定義:
定義的意思是,如果 KBUILD_VERBOSE 為 1,則quiet 和 Q 為空,即執(zhí)行命令時(shí)會(huì)輸出命令執(zhí)行的詳細(xì)信息;否則 quiet 為 quiet_ ,Q 為 @ 。在Makefile 中,如果一個(gè)命令前使用了 @符號,那么在執(zhí)行命令時(shí)將不輸出命令的執(zhí)行詳細(xì)信息。
拋開內(nèi)核 Makefile 文件的龐大,這里只依樣畫葫蘆的做一下實(shí)驗(yàn),下面是一個(gè)測試 Makefile :
KBUILD_VERBOSE := 1 ifeq ($(KBUILD_VERBOSE), 1) quiet = Q = else quite = quiet_ Q = @ endif all: $(Q)mkdir -p /home/beyes/makefile_test/quite/test_quite
Make一下:
beyes@debian:~/makefile_test/quite$ make mkdir -p /home/beyes/makefile_test/quite/test_quite
由執(zhí)行結(jié)果看到,Makefile 中的 mkdir命令執(zhí)行過程整個(gè)輸了出來。
再改一下 Makefile 中的 KBUILD_VERBOSE := 1 為KBUILD_VERBOSE := 0,那么再次執(zhí)行make 時(shí),已經(jīng)看不見任何輸出。
= 和 :=符號的區(qū)別
= 和 := 都是變量賦值符號。但是它們有些區(qū)別:
"=" 如果右值包含另一個(gè)變量,那么可以在后面定義這個(gè)變量。":=" 如果右值包含另一個(gè)變量,則只能引用已定義的變量。
下面看示例:
drivers-y := drivers/ $(head-y)head-y = header/all: @echo $(drivers-y)
輸出:
$ make drivers/
drivers-y 的后面跟著一個(gè) $(head-y)變量,這個(gè)變量在 drivers-y 之前并未定義過,但是由于這里使用了 := 符號,所以在 drivers-y 的下一行再定義head-y 已然無效。
那么將上面的 drivers-y 中的符號改成 = 符號,那么便可以看到區(qū)別:
drivers-y = drivers/ $(head-y)head-y = header/all: @echo $(drivers-y)
輸出:
[beyes@SLinux Makefile]$ make drivers/ header/
=
var = def
這里的意思是,如果 var這個(gè)變量沒有被定義過,那么它的值就被定義為 def 。如果被定義過,則 def 不會(huì)被賦值到 var 中:
var = defall: @echo $(var)
輸出:
$ make def
如果是:
var = definedvar = defall: @echo $(var)
則輸出:
$ make defined
+/-符號
除了 '-' 符號外,還可以看到 '+' 符號,它的意思和 '-' 相反,表示不忽略。這就意味著,像 make 的命令行選項(xiàng)-n(--just print), -t(touch) 并不影響之前帶 '+' 符號的命令的執(zhí)行。像 -n選項(xiàng),一般情況下,它只是在解析命令,而不真正執(zhí)行它們,但是命令前使用了 '+' 之后, -n選項(xiàng)就不能阻止命令被執(zhí)行。如一個(gè)目錄下有這幾個(gè)文件:
$ ls Makefile test2.txt test.txt
Makefile 的內(nèi)容為:
all: @rm -f test.txt +@rm -f test2.txt
使用 -n 選項(xiàng)來運(yùn)行 make:
$ make -n rm -f test.txt rm -f test2.txt
再檢查一下當(dāng)前目錄:
$ ls Makefile test.txt
可見 test2.txt已經(jīng)被刪除。
@:
在一些 Makefile 中可能會(huì)在偽目標(biāo)下的命令中看到 @: 這個(gè)符號,其實(shí)這不是代表一個(gè)特殊變量。這里的 @ 符號和@echo 中表示的意思(不顯示命令執(zhí)行的詳細(xì)內(nèi)容)一樣,而冒號 ":" 實(shí)際上是 shell 中的內(nèi)置符號,它表示的是一種空命令,什么都不做,也就是執(zhí)行到它時(shí),它上面的命令都已經(jīng)成功執(zhí)行,最后成功退出。
$$
在使用變量時(shí),需要在變量前加 "$" 符號,但最好是用 () 或 {} 將變量括起來,比如 $(VAR) 或 ${VAR}。如果要使用真實(shí)的 "$“ 字符,那么需要用兩個(gè) "$" 表示,即 "$$"。
比如下面的代碼:
$ cat Makefileall: @echo "$$HOME" @echo "$$BASH" @echo "$$PATH"
運(yùn)行輸出:
$ make /home/beyes /bin/sh /usr/local/Trolltech/Qt-4.3.2/bin:/usr/lib/qt-3.3/bin:/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin:/home/beyes/bin
上面,$HOME,$BASH,$PATH都是系統(tǒng)內(nèi)置變量。引用這些變量時(shí),就需要用 $$,如果只用一個(gè) $ (如 @echo"$HOME"),那么你不會(huì)看到你所希望看到的結(jié)果。
$^,$+,$*,$(@D),$(@F),$(*D),$(*F),$(%D),$(%F),
$(%D),$(%F),$(
$(?D),$(?F)
$^、$+:
$^ 表示所有依賴文件列表。一個(gè)文件可重復(fù)出現(xiàn)在目標(biāo)的依賴中,$^ 只記錄它的一次引用情況,也就是說 $^ 會(huì)去掉重復(fù)的依賴文件。$+類似于 $^,但它保留了依賴文件中重復(fù)出現(xiàn)的文件。下面舉例說明這兩個(gè)變量的區(qū)別。
先在一個(gè)目錄下建立 3 個(gè)文件:
$ echo "are" > test1.txt$ echo "you" > test2.txt$ echo "ok" > test3.txt
測試代碼:
all:test1.txt test2.txt test3.txt test1.txt $(shell cat $^ > integra1) $(shell cat $+ > integra2)
運(yùn)行輸出:
beyes@debian:~/Makefile/prereq$ cat integra1 are you okbeyes@debian:~/Makefile/prereq$ cat integra2 are you ok are
由輸出可以很清楚的看到這兩個(gè)變量的區(qū)別。
$*
$* 有一個(gè)形象的詞來稱呼它 --- “莖” 。如果目標(biāo)文件名中帶有一個(gè)可識別的后綴,那么 $* 就表示文件中移除后綴以外的部分。比如main.o 作為目標(biāo)時(shí),$* 就表示為 main 。如果目標(biāo)包含不可識別的后綴時(shí),該變量為空。
$(@D)
代表目標(biāo)文件的目錄部分(要去掉目錄部分的最后一個(gè)斜杠),如下例所示:
/home/beyes/Makefile/main.o: @echo $(@D)
運(yùn)行輸出:
$ make /home/beyes/Makefile
如果目標(biāo)中不包含斜杠,那么輸出值為 '.'表示當(dāng)前目錄。
$(@F)
目標(biāo)文件的完整文件名初目錄以外的部分,換句話說表示的是實(shí)際的文件名。如下示例:
/home/beyes/Makefile/main.o: @echo $(@F)
運(yùn)行輸出:
$ make main.o
$(*D) 和 $(*F)
分別表示目標(biāo) “莖” 中的目錄部分和文件名部分。如下示例:
/home/beyes/Makefile/main.o: @echo $(*D) @echo $(*F)
運(yùn)行輸出:
$ make /home/beyes/Makefile main
$(%D) 和 $(%F)
當(dāng)以 "archive(member)" 這樣形式的靜態(tài)庫為目標(biāo)時(shí),分別表示庫文件成員 "member"名中的目錄部分和文件名部分。它僅對這種形式的規(guī)則目標(biāo)有效。如下示例:
Mylib.a(/home/beyes/main/are.o): @echo $(%D) @echo $(%F)
運(yùn)行輸出:
$ make /home/beyes/main are.o
$(
分別表示規(guī)則中第一個(gè)依賴文件的目錄部分和文件名部分。如下示例:
/home/beyes/main/are.o: @echo hellosomething.o: @echo makefileall:/home/beyes/main/are.o something.o @echo $(<<span style="color: #000000;">D) @echo $(
運(yùn)行輸出:
$ make all hello makefile /home/beyes/main are.o
$(^D) 和 $(^F)
分別表示所有依賴文件的目錄部分和文件部分(不存在同一文件)。如下示例:
/home/beyes/main/are.o: @echo hello/home/beyes/something.o: @echo makefileall:/home/beyes/main/are.o /home/beyes/something.o @echo $(^D) @echo $(^F)
運(yùn)行輸出:
$ make all hello makefile /home/beyes/main /home/beyes are.o something.o
$(+D) 和 $(+F)
分別表示所有依賴文件的目錄部分和文件部分(可存在重復(fù)文件)。
$(?D) 和$(?F)
分別表示被更新的依賴文件的目錄部分和問及文件部分。
error函數(shù)
error 函數(shù)表示產(chǎn)生了一個(gè)致命錯(cuò)誤,當(dāng)它執(zhí)行后,編譯會(huì)停止。
它的使用方法是:
$(error <錯(cuò)誤消息>)
測試代碼:
KBUILD_VERBOSE := 1 TEST_MSG := "are you ok?" ifeq ($(KBUILD_VERBOSE), 1) $(error KBUILD_VERBOSE is $(KBUILD_VERBOSE), we will stop here) quite = Q = else quite = quiet_ Q = @ endif all: $(Q)echo $(TEST_MSG)
運(yùn)行輸出:
beyes@debian:~/makefile_test/error$ makeMakefile:7: *** KBUILD_VERBOSE is 1, we will stop here。 停止。
由輸出可見,all: 目標(biāo)下的 echo語句并沒有執(zhí)行輸出,整個(gè)編譯在 error 函數(shù)執(zhí)行后停止了。如果將上面的 KBUILD_VERBOSE 的值改為 0 ,那么再make 時(shí)輸出:
beyes@debian:~/makefile_test/error$ makeare you ok?
$@, $^, $< , $?符號
Makefile $@, $^, $<</p>
$@ 表示目標(biāo)文件$^ 表示所有的依賴文件$<<span style="color: #000000;"> 表示第一個(gè)依賴文件$? 表示比目標(biāo)還要新的依賴文件列表
如一個(gè)目錄下有如下文件:
$ lshello.c hi.c main.c Makefile
按照 Makefile 規(guī)則規(guī)規(guī)矩矩的寫:
main: main.o hello.o hi.o gcc -o main main.o hello.o hi.omain.o: main.c cc -c main.chello.o: hello.c cc -c hello.chi.o: hi.c cc -c hi.cclean: rm *.o rm main
改為用上述符號進(jìn)行替代:
main: main.o hello.o hi.o gcc -o $@ $^main.o: main.c cc -c $<<span style="color: #000000;">hello.o: hello.c cc -c $<<span style="color: #000000;">hi.o: hi.c cc -c $<<span style="color: #000000;">clean: rm *.o rm main
beyes@debian:~/makefile_test/semicolon/real$ make cc -c main.c cc -c hello.c cc -c hi.c gcc -o main main.o hello.o hi.obeyes@debian:~/makefile_test/semicolon/real$ ls hello.c hello.o hi.c hi.o main main.c main.o Makefile
patsubst 和 filter函數(shù)
filter 函數(shù)的使用形式如:
$(filter , )
該函數(shù)的功能是,以 模式過濾 字符串中的單詞,保留符合模式的單詞。
該函數(shù)的返回值是符合 模式的字符串。
patsubst 函數(shù)的使用形式如:
$(patsubst , , )
該函數(shù)的功能是,查找中的單詞(這些單詞以“空格”、“Tab”或“回車”,“換行”分隔)是否符合 中的模式,如果匹配,那么使用 替換。這里, 可以包括通配符“%” (表示任意長字符串)。如果 中也包含 “%” 符號,那么 中的 “%” 所代表的字符串就是 中的的那個(gè)字符串。若要使用 %字符,那么要使用 ‘\’ 符號進(jìn)行轉(zhuǎn)義,即 “\%” 。
函數(shù)的返回值是替換過的字符串。
下面使用一個(gè)實(shí)例說明這兩個(gè)函數(shù)的應(yīng)用。下面的代碼摘自內(nèi)核源碼樹下頂層的 Makefile, 為了演示,做了一點(diǎn)修改:
init-y := init/ testdrivers-y := drivers/ sound/net-y := net/ test2libs-y := lib/core-y := usr/vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(core-y) $(drivers-y) $(net-y) $(libs-y) ))vmlinux-dirs2 := $(init-y) $(drivers-y) $(net-y) $(libs-y) $(core-y)all: @echo vmlinux-dirs2: $(vmlinux-dirs2) @echo vmlinux-dirs: $(vmlinux-dirs)
運(yùn)行輸出:
linux-suse10:~/Makefile_test # make vmlinux-dirs2: init/ test drivers/ sound/ net/ test2 lib/ usr/ vmlinux-dirs: init usr drivers sound net lib
由上面的vmlinux-dirs2輸出可見,所有變量內(nèi)容都被輸出。
對vmlinux-dirs 的輸出,則體現(xiàn)了上述兩個(gè)函數(shù)的應(yīng)用。首先 filter 過濾掉了沒有以 /符號作為結(jié)尾的字符串;然后再經(jīng)過 patsubst 函數(shù)過濾掉了所有以 / 符號結(jié)尾字符串中的 / 符號。
filter-out --反過濾函數(shù)
格式:
$(filter-out ,)
說明:
以 模式過濾 字符串中的單詞,去除符合模式 的單詞。返回不符合模式 的字符串。如果 是一樣或者是其子集,那么返回空。
如:
objs = hello.c world.c are.c you.c ok.cnew = hello.c world.c are.c you.c ok.c add.call: @echo $(filter-out $(new), $(objs))
運(yùn)行輸出時(shí)為空。當(dāng) new 改為和 objs一樣時(shí),同樣輸出為空。當(dāng) new 改為hello.c world.c are.c you.c 時(shí),輸出 ok.c。
再做一個(gè)實(shí)驗(yàn),如果 new 中包含的字符串比 objs 中的還是少一個(gè) ok.c ,但是字符串的順序和 ojbs中的不一樣,那結(jié)果是不是仍然輸出 ok.c 呢?答案是一定的!這一無關(guān)順序的“智能”特性比較重要,像在內(nèi)核 Makefile的參數(shù)檢查中(比較新舊編譯選項(xiàng)是否一樣)就體現(xiàn)了這一點(diǎn),如在 script/Kbuild.include 中對arg-check的定義體現(xiàn)了這一點(diǎn):
arg-check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) $(filter-out $(cmd_$@), $(cmd_$(1))) )
origin 函數(shù) --告知變量的出生情況
origin 函數(shù)的作用是告訴你變量是哪里來的,其出生狀況如何,他并不改變變量。其語法是:
$(origin )
上面, 為變量的名字,而不是引用,所以一般沒有 $字符在前。origin 函數(shù)通過返回值來告訴你 的出生情況。下面用實(shí)例說明:
1. 當(dāng)從來未定義過該變量時(shí),origin 函數(shù)返回 "undefined" 。如下面的 Makefile 代碼:
all: @echo $(origin V)
運(yùn)行輸出:
$ make undefined
2. 如果該變量為環(huán)境變量,那么返回 "enviroment"。如下面的 Makefile 代碼:
all: @echo $(origin USER)
運(yùn)行輸出:
$ make environment
其中 USER 這個(gè)變量為系統(tǒng)定義的當(dāng)前用戶,使用 env命令可以看到。
3. 如果變量是個(gè)默認(rèn)定義,那么返回 "default"。如下面的 Makefile 代碼:
all: @echo $(origin CC)
運(yùn)行輸出:
$ make default
4. 如果一個(gè)變量被定義在 Makefile 文件中,那么返回"file" 。如下面的 Makefile 代碼:
V := 1all: @echo $(origin V)
運(yùn)行輸出:
$ make file
5. 如果變量來自命令行,那么返回 "command line"。如下面的 Makefile 代碼:
all: @echo $(origin MyVar)
運(yùn)行方法:
$ make MyVar="Are you ok?" command line
6. 如果變量被 override 被重新定義過,那么返回"override"。如下面的 Makefile 代碼:
verride SHELL = /bin/shall: @echo $(origin SHELL)
運(yùn)行輸出:
$ make override
上面,SHELL 原本是個(gè)環(huán)境變量,但在 Makefile 里被override 指示符重定義過。
7. 如果變量是自動(dòng)化變量(如 $@, $< 等),那么返回 "automatic" 。如下面的 Makefile代碼:
all: @echo $(origin @)
運(yùn)行輸出:
$ make automatic
ifdef, ifndef, ifeq,ifneq,
用內(nèi)核 Makefile 中的一段代碼說明:
# To put more focus on warnings, be less verbose as default# Use 'make V=1' to see the full commandsifdef V ifeq ("$(origin V)", "command line") KBUILD_VERBOSE = $(V) endifendififndef KBUILD_VERBOSE KBUILD_VERBOSE =0endif
代碼中注釋的意思是,為了能將精力集中在警告信息上面,默認(rèn)上不輸出詳細(xì)而顯得冗余的編譯信息,如果想看到完整的命令執(zhí)行情況,可以在make 時(shí)使用參數(shù) V=1 。
下面根據(jù)代碼分析這 4 個(gè)符號的作用,實(shí)際上它們和 C 語言中的意思是一樣的。
ifdef V 表示如果 V 變量被定義過,那么會(huì)執(zhí)行下面的 ifeq 語句。V變量的定義來源可以有不同,如在文件中定義,在命令行中定義,在環(huán)境變量中定義等。
ifeq ("$(origin V)", "command line") 表示若 V 是在命令行里已被定義,那么執(zhí)行下面的KBUILD_VERBOSE = $(V) 語句。也就是說,ifeq用以判斷后面括號里的兩個(gè)值是否相等,如果相等則執(zhí)行下面的語句。如果不相等,則不執(zhí)行。
ifndef 表示如果后面的變量沒有被定義過,則執(zhí)行其下面的語句。
上面,每個(gè) ifdef , ifeq 和 ifndef 都要和一個(gè) endif 匹配以構(gòu)成一個(gè)完整的判斷式。
另外,在內(nèi)核 Makefile 中還有如對 (C) 以及 (M) 等選項(xiàng)同樣分析。
(C) 選項(xiàng)有是關(guān)于代碼檢查的選擇:
# Call a source code checker (by default, "sparse") as part of the# C compilation.## Use 'make C=1' to enable checking of only re-compiled files.# Use 'make C=2' to enable checking of *all* source files, regardless# of whether they are re-compiled or not.## See the file "Documentation/sparse.txt" for more details, including# where to get the "sparse" utility.ifdef C ifeq ("$(origin C)", "command line") KBUILD_CHECKSRC = $(C) endifendififndef KBUILD_CHECKSRC KBUILD_CHECKSRC =0endif
(M) 選項(xiàng)關(guān)于模塊的編譯:
# Use make M=dir to specify directory of external module to build# Old syntax make ... SUBDIRS=$PWD is still supported# Setting the environment variable KBUILD_EXTMOD take precedenceifdef SUBDIRS KBUILD_EXTMOD ?= $(SUBDIRS)endififdef M ifeq ("$(origin M)", "command line") KBUILD_EXTMOD := $(M) endifendif
像我們經(jīng)常編譯驅(qū)動(dòng)模塊時(shí)會(huì)使用下面的命令:make -C/lib/modules/`uname -r`/build M=`pwd` modules
上面,使用 pwd 命令給出了要編譯的模塊所在的路徑。
像 ifeq 和 ifneq的第一個(gè)參數(shù)也可以不止一個(gè)變量,當(dāng)有多個(gè)變量時(shí),可能需要考慮每個(gè)變量的條件是否都滿足判斷條件,直到所有的變量都不滿足時(shí),才認(rèn)為整個(gè)表達(dá)式是不滿足的。示例代碼如下:
hostprogs-y := 1hostprogs-m :=ifneq ($(hostprogs-y)$(hostprogs-m),) testvar := "defined"endifall: @echo "$(testvar)"
運(yùn)行輸出:
$ make defined
如果將上面代碼中對 hostprogs-y的定義設(shè)為空,那么輸出將為空;而 hostprogs-y 和 hostprogs-m 這兩個(gè)變量只要有一個(gè)味真,那么就認(rèn)為整個(gè)ifneq 判斷成立。
網(wǎng)址:http://www.cnblogs.com/baiyw/p/3303758.html