Makefile中的变量
Makefile中變量有以下幾個(gè)特征:
1. Makefile中變量和函數(shù)的展開(除規(guī)則命令行中的變量和函數(shù)以外),是在make讀取makefile文件時(shí)進(jìn)行的,這里的變量包括了使用“=”定義和使用指示符“define”定義的。
2. 變量可以用來代表一個(gè)文件名列表、編譯選項(xiàng)列表、程序運(yùn)行的選項(xiàng)參數(shù)列表、搜索源文件的目錄列表、編譯輸出的目錄列表和所有我們能夠想到的事物。
3. 變量名是不包括“:”、“#”、“=”、前置空白和尾空白的任何字符串。
4. 變量名是大小寫敏感的。推薦的做法是在對于內(nèi)部定義定義的一般變量(例如:目標(biāo)文件列表objects)使用小寫方式,而對于一些參數(shù)列表(例如:編譯選項(xiàng)CFLAGS)采用大寫方式。
5. 另外有一些變量名只包含了一個(gè)或者很少的幾個(gè)特殊的字符(符號)。稱它們?yōu)樽詣?dòng)化變量。像“$<”、“$@”、“$?”、“$*”等。
(1) 變量的引用
??????Makefile中在對一些簡單變量的引用,我們也可以不使用“()”和“{}”來標(biāo)記變量名,而直接使用“$x”的格式來實(shí)現(xiàn),此種用法僅限于變量名為單字符的情況。另外自動(dòng)化變量也使用這種格式。對于一般多字符變量的引用必須使用括號了標(biāo)記,否則make將把變量名的首字母作為作為變量而不是整個(gè)字符串(“$PATH”在Makefile中實(shí)際上是“$(P)ATH”)。這一點(diǎn)和shell中變量的引用方式不同。shell中變量的引用可以是“${xx}”或者“$xx”格式。但在Makefile中多字符變量名的引用只能是“$(xx)”或者“${xx}”格式。
(2) 變量的定義
兩種風(fēng)格:遞歸展開式變量和直接展開式變量。前者前者在引用的地方是嚴(yán)格的文本替換,后者用:=定義,變量值中對其他量或者函數(shù)的引用在定義變量時(shí)被展開(對變量進(jìn)行替換),此風(fēng)格變量在定義時(shí)就完成了對所引用變量和函數(shù)的展開,因此不能實(shí)現(xiàn)對其后定義變量的引用(前者是嫩購實(shí)現(xiàn)這個(gè)功能的)。如:
CFLAGS := $(include_dirs) -O
include_dirs := -Ifoo -Ibar
由于變量“include_dirs”的定義出現(xiàn)在“CFLAGS”定義之后。因此在“CFLAGS”的定義中,“include_dirs”的值為空。“CFLAGS”的值為“-O”而不是“-Ifoo -Ibar -O”。這一點(diǎn)也是直接展開式和遞歸展開式變量的不同點(diǎn)。
??? 在復(fù)雜的Makefile中,推薦使用直接展開式變量。因?yàn)檫@種風(fēng)格變量的使用方式和大多數(shù)編程語言中的變量使用方式基本上相同。它可以使一個(gè)比較復(fù)雜的Makefile在一定程度上具有可預(yù)測性。而且這種變量允許我們利用之前所定義的值來重新定義它(比如使用某一個(gè)函數(shù)來對它以前的值進(jìn)行處理并重新賦值),此方式在Makefile中經(jīng)常用到。盡量避免和減少遞歸式變量的使用。
???????? 當(dāng)定義不包含尾空格的變量時(shí),就不能使用這種方式,將變量定義和注釋書寫在同一行并使用若干空格分開。否則,注釋之前的空格會(huì)被作為變量值的一部分。例如下邊的做法就是不正確的:
dir := /foo/bar # directory to put the frobs in
變量“dir”的值是“/foo/bar ”(后面有4個(gè)空格),這可能并不是想要實(shí)現(xiàn)的。如果一個(gè)文件以它作為路徑來表示“$(dir)/file”,那么大錯(cuò)特錯(cuò)了。
“?=”操作符
GNU make中,還有一個(gè)被稱為條件賦值的賦值操作符“?=”。被稱為條件賦值是因?yàn)?#xff1a;只有此變量在之前沒有賦值的情況下才會(huì)對這個(gè)變量進(jìn)行賦值。例如:
FOO ?= bar
其等價(jià)于:
ifeq ($(origin FOO), undefined)
FOO = bar
endif
含義是:如果變量“FOO”在之前沒有定義,就給它賦值“bar”。否則不改變它的值。
“+=”操作符
使用“+=”操作符,相當(dāng)于:
objects = main.o foo.o bar.o utils.o
objects := $(objects) another.o
如果被追加值的變量之前沒有定義,那么,“+=”會(huì)自動(dòng)變成“=”,此變量就被定義為一個(gè)遞歸展開式的變量。如果之前存在這個(gè)變量定義,那么“+=”就繼承之前定義時(shí)的變量風(fēng)格。
variable := value
variable += more
就是
variable := value
variable := $(variable) more
variable = value
variable += more
相當(dāng)于:
temp = value
variable = $(temp) more
(3) 變量的高級用法
1.?? 變量的替換引用
對于一個(gè)已經(jīng)定義的變量,可以使用“替換引用”將其值中的后綴字符(串)使用指定的字符(字符串)替換。
例如:
foo := a.o b.o c.o
bar := $(foo:.o=.c)
在這個(gè)定義中,變量“bar”的值就為“a.c b.c c.c”。使用變量的替換引用將變量“foo”以空格分開的值中的所有的字的尾字符“o”替換為“c”,其他部分不變。
又如:
foo := a.o b.o c.o
bar := $(foo:%.o=%.c)
這個(gè)例子同樣使變量“bar”的值為“a.c b.c c.c”。這種格式的替換引用方式比第一種方式更通用。
使用環(huán)境變量需要注意以下幾點(diǎn):
1. 在Makefile中對一個(gè)變量的定義或者以make命令行形式對一個(gè)變量的定義,都將覆蓋同名的環(huán)境變量(注意:它并不改變系統(tǒng)環(huán)境變量定義,被修改的環(huán)境變量只在make執(zhí)行過程有效)。而make使用“-e”參數(shù)時(shí),Makefile和命令行定義的變量不會(huì)覆蓋同名的環(huán)境變量,make將使用系統(tǒng)環(huán)境變量中這些變量的定義值。
2. make的遞歸調(diào)用中,所有的系統(tǒng)環(huán)境變量會(huì)被傳遞給下一級make。默認(rèn)情況下,只有環(huán)境變量和通過命令行方式定義的變量才會(huì)被傳遞給子make進(jìn)程。在Makefile中定義的普通變量需要傳遞給子make時(shí)需要使用“export”指示符來對它聲明。
3. 一個(gè)比較特殊的是環(huán)將變量“SHELL”。在系統(tǒng)中這個(gè)環(huán)境變量的用途是用來指定用戶和系統(tǒng)的交互接口,顯然對于make是不合適的。因此make的執(zhí)行環(huán)境變量“SHELL”沒有使用同名的環(huán)境變量定義,而是“/bin/sh”。make默認(rèn)“/bin/sh”作為它的命令行解釋程序(make在執(zhí)行之前將變量“SHELL”設(shè)置為“/bin/sh”)。
gcc -O2 -o $@ $< 意思
-O2表示優(yōu)化選項(xiàng),2表示最優(yōu)優(yōu)化,即編譯器會(huì)優(yōu)化你的程序;-o表示后邊接的是文件名稱;$@是Makefile的通配符,代指你前面指定的文件名,例如有規(guī)則%.o:%.c,那么$@表示xxx.o文件(xxx是你的源代碼文件的名稱前綴);$<表示搜索到的第一個(gè)匹配的文件,對于規(guī)則%.o:%.c,$<表示第一個(gè)找到的.c文件。簡而言之,假設(shè)在一個(gè)文件夾下有若干.c文件,那么下面的規(guī)則:
%.o:%.c
<TAB>gcc -O2 -o $@ $<??? #<TAB>表示Tab鍵
表示把所有的.c文件編譯成中間.o文件。
http://zhidao.baidu.com/question/246239567.html
四、嵌套執(zhí)行make
在一些大的工程中,我們會(huì)把我們不同模塊或是不同功能的源文件放在不同的目錄中,我們可以在每個(gè)目錄中都書寫一個(gè)該目錄的Makefile,這有利于讓我們的Makefile變得更加地簡潔,而不至于把所有的東西全部寫在一個(gè)Makefile中,這樣會(huì)很難維護(hù)我們的Makefile,這個(gè)技術(shù)對于我們模塊編譯和分段編譯有著非常大的好處。
例如,我們有一個(gè)子目錄叫subdir,這個(gè)目錄下有個(gè)Makefile文件,來指明了這個(gè)目錄下文件的編譯規(guī)則。那么我們總控的Makefile可以這樣書寫:
subsystem:
cd subdir && $(MAKE)
其等價(jià)于:
subsystem:
$(MAKE) -C subdir
定義$(MAKE)宏變量的意思是,也許我們的make需要一些參數(shù),所以定義成一個(gè)變量比較利于維護(hù)。這兩個(gè)例子的意思都是先進(jìn)入“subdir”目錄,然后執(zhí)行make命令。
我們把這個(gè)Makefile叫做“總控Makefile”,總控Makefile的變量可以傳遞到下級的Makefile中(如果你顯示的聲明),但是不會(huì)覆蓋下層的Makefile中所定義的變量,除非指定了“-e”參數(shù)。
如果你要傳遞變量到下級Makefile中,那么你可以使用這樣的聲明:
export <variable ...>
GNU組織建議把編譯器為每一個(gè)源文件的自動(dòng)生成的依賴關(guān)系放到一個(gè)文件中,為每一個(gè)“name.c”的文件都生成一個(gè)“name.d”的Makefile文件,[.d]文件中就存放對應(yīng)[.c]文件的依賴關(guān)系。
于是,我們可以寫出[.c]文件和[.d]文件的依賴關(guān)系,并讓make自動(dòng)更新或自成[.d]文件,并把其包含在我們的主Makefile中,這樣,我們就可以自動(dòng)化地生成每個(gè)文件的依賴關(guān)系了。 這里,我們給出了一個(gè)模式規(guī)則來產(chǎn)生[.d]文件: %.d: %.c @set -e; rm -f $@; \ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ rm -f $@.$$$$ 這個(gè)規(guī)則的意思是,所有的[.d]文件依賴于[.c]文件,“rm -f $@”的意思是刪除所有的目標(biāo),也就是[.d]文件,第二行的意思是,為每個(gè)依賴文件“$<”,也就是[.c]文件生成依賴文件,“$@”表示模式“%.d”文件,如果有一個(gè)C文件是name.c,那么“%”就是“name”,“$$$$”意為一個(gè)隨機(jī)編號,第二行生成的文件有可能是“name.d.12345”,第三行使用sed命令做了一個(gè)替換,關(guān)于sed命令的用法請參看相關(guān)的使用文檔。第四行就是刪除臨時(shí)文件。 總而言之,這個(gè)模式要做的事就是在編譯器生成的依賴關(guān)系中加入[.d]文件的依賴,即把依賴關(guān)系: main.o : main.c defs.h 轉(zhuǎn)成: main.o main.d : main.c defs.h 于是,我們的[.d]文件也會(huì)自動(dòng)更新了,并會(huì)自動(dòng)生成了,當(dāng)然,你還可以在這個(gè)[.d]文件中加入的不只是依賴關(guān)系,包括生成的命令也可一并加入,讓每個(gè)[.d]文件都包含一個(gè)完賴的規(guī)則。一旦我們完成這個(gè)工作,接下來,我們就要把這些自動(dòng)生成的規(guī)則放進(jìn)我們的主Makefile中。我們可以使用Makefile的“include”命令,來引入別的Makefile文件(前面講過),例如: sources = foo.c bar.c include $(sources:.c=.d) 上述語句中的“$(sources:.c=.d)”中的“.c=.d”的意思是做一個(gè)替換,把變量$(sources)所有[.c]的字串都替換成[.d],關(guān)于這個(gè)“替換”的內(nèi)容,在后面我會(huì)有更為詳細(xì)的講述。當(dāng)然,你得注意次序,因?yàn)閕nclude是按次來載入文件,最先載入的[.d]文件中的目標(biāo)會(huì)成為默認(rèn)目標(biāo)。 書寫命令總結(jié)
以上是生活随笔為你收集整理的Makefile中的变量的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 正点原子 STM32芯片解读 M3_Ba
- 下一篇: Unknown storage engi