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