四、嵌套執行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 ...>;
如果你不想讓某些變量傳遞到下級Makefile中,那么你可以這樣聲明:
unexport <variable ...>;
如:
示例一:
export variable = value
其等價于:
variable = value
export variable
其等價于:
export variable := value
其等價于:
variable := value
export variable
示例二:
export variable += value
其等價于:
variable += value
export variable
如果你要傳遞所有的變量,那么,只要一個export就行了。后面什么也不用跟,表示傳遞所有的變量。
需要注意的是,有兩個變量,一個是SHELL,一個是MAKEFLAGS,這兩個變量不管你是否export,其總是要傳遞到下層Makefile中,特別是MAKEFILES變量,其中包含了make的參數信息,如果我們執行“總控Makefile”時有make參數或是在上層Makefile中定義了這個變量,那么MAKEFILES變量將會是這些參數,并會傳遞到下層Makefile中,這是一個系統級的環境變量。
但是make命令中的有幾個參數并不往下傳遞,它們是“-C”,“-f”,“-h”“-o”和“-W”(有關Makefile參數的細節將在后面說明),如果你不想往下層傳遞參數,那么,你可以這樣來:
subsystem:
cd subdir && $(MAKE) MAKEFLAGS=
如果你定義了環境變量MAKEFLAGS,那么你得確信其中的選項是大家都會用到的,如果其中有“-t”,“-n”,和“-q”參數,那么將會有讓你意想不到的結果,或許會讓你異常地恐慌。
還有一個在“嵌套執行”中比較有用的參數,“-w”或是“--print-directory”會在make的過程中輸出一些信息,讓你看到目前的工作目錄。比如,如果我們的下級make目錄是“/home/hchen/gnu/make”,如果我們使用“make -w”來執行,那么當進入該目錄時,我們會看到:
make: Entering directory `/home/hchen/gnu/make'.
而在完成下層make后離開目錄時,我們會看到:
make: Leaving directory `/home/hchen/gnu/make'
當你使用“-C”參數來指定make下層Makefile時,“-w”會被自動打開的。如果參數中有“-s”(“--slient”)或是“--no-print-directory”,那么,“-w”總是失效的。
五、定義命令包
如果Makefile中出現一些相同命令序列,那么我們可以為這些相同的命令序列定義一個變量。定義這種命令序列的語法以“define”開始,以“endef”結束,如:
define run-yacc
yacc $(firstword $^)
mv y.tab.c $@
endef
這里,“run-yacc”是這個命令包的名字,其不要和Makefile中的變量重名。在“define”和“endef”中的兩行就是命令序列。這個命令包中的第一個命令是運行Yacc程序,因為Yacc程序總是生成“y.tab.c”的文件,所以第二行的命令就是把這個文件改改名字。還是把這個命令包放到一個示例中來看看吧。
foo.c : foo.y
$(run-yacc)
我們可以看見,要使用這個命令包,我們就好像使用變量一樣。在這個命令包的使用中,命令包“run-yacc”中的“$^”就是“foo.y”,“$@”就是“foo.c”(有關這種以“$”開頭的特殊變量,我們會在后面介紹),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 ...>;
如果你不想讓某些變量傳遞到下級Makefile中,那么你可以這樣聲明:
unexport <variable ...>;
如:
示例一:
export variable = value
其等價于:
variable = value
export variable
其等價于:
export variable := value
其等價于:
variable := value
export variable
示例二:
export variable += value
其等價于:
variable += value
export variable
如果你要傳遞所有的變量,那么,只要一個export就行了。后面什么也不用跟,表示傳遞所有的變量。
需要注意的是,有兩個變量,一個是SHELL,一個是MAKEFLAGS,這兩個變量不管你是否export,其總是要傳遞到下層Makefile中,特別是MAKEFILES變量,其中包含了make的參數信息,如果我們執行“總控Makefile”時有make參數或是在上層Makefile中定義了這個變量,那么MAKEFILES變量將會是這些參數,并會傳遞到下層Makefile中,這是一個系統級的環境變量。
但是make命令中的有幾個參數并不往下傳遞,它們是“-C”,“-f”,“-h”“-o”和“-W”(有關Makefile參數的細節將在后面說明),如果你不想往下層傳遞參數,那么,你可以這樣來:
subsystem:
cd subdir && $(MAKE) MAKEFLAGS=
如果你定義了環境變量MAKEFLAGS,那么你得確信其中的選項是大家都會用到的,如果其中有“-t”,“-n”,和“-q”參數,那么將會有讓你意想不到的結果,或許會讓你異常地恐慌。
還有一個在“嵌套執行”中比較有用的參數,“-w”或是“--print-directory”會在make的過程中輸出一些信息,讓你看到目前的工作目錄。比如,如果我們的下級make目錄是“/home/hchen/gnu/make”,如果我們使用“make -w”來執行,那么當進入該目錄時,我們會看到:
make: Entering directory `/home/hchen/gnu/make'.
而在完成下層make后離開目錄時,我們會看到:
make: Leaving directory `/home/hchen/gnu/make'
當你使用“-C”參數來指定make下層Makefile時,“-w”會被自動打開的。如果參數中有“-s”(“--slient”)或是“--no-print-directory”,那么,“-w”總是失效的。
五、定義命令包
如果Makefile中出現一些相同命令序列,那么我們可以為這些相同的命令序列定義一個變量。定義這種命令序列的語法以“define”開始,以“endef”結束,如:
define run-yacc
yacc $(firstword $^)
mv y.tab.c $@
endef
這里,“run-yacc”是這個命令包的名字,其不要和Makefile中的變量重名。在“define”和“endef”中的兩行就是命令序列。這個命令包中的第一個命令是運行Yacc程序,因為Yacc程序總是生成“y.tab.c”的文件,所以第二行的命令就是把這個文件改改名字。還是把這個命令包放到一個示例中來看看吧。
foo.c : foo.y
$(run-yacc)
我們可以看見,要使用這個命令包,我們就好像使用變量一樣。在這個命令包的使用中,命令包“run-yacc”中的“$^”就是“foo.y”,“$@”就是“foo.c”(有關這種以“$”開頭的特殊變量,我們會在后面介紹),make在執行命令包時,命令包中的每個命令會被依次獨立執行。