make 是一個神奇的東西阿,裡邊有很多高級的用法,如果不會用的話,寫出來的Makefile會很麻煩。 下面結合一個實際的例子來看看 make 的 (1)implicit pattern rule 的重新定義 (2) 自動依賴關係的生成 (3) make 的嵌套調用。 1. 假設一個工程 project 分為兩個子工程 gtrans 和 isgen ~> ls project GTRANS ISGEN Makefile gtrans isgen // gtrans 與 isgen 都是生成的程序 project > ls GTRANS/ Makefile findGraph.d findGraph.o gtrans.d isgen.cpp preProcess.d preProcess.o findGraph.cpp findGraph.hpp gtrans.cpp gtrans.o preProcess.cpp preProcess.hpp .d 文件存儲的是 .o 文件的依賴關係, .hpp 是頭文件 2. 先看一下GRRANS / Makefile SOURCES = gtrans.cpp findGraph.cpp preProcess.cpp LIB = "/home/dab/cadlib" INCLUDE = "/home/dab/cadinc" VPATH = .. %.o: %.cpp $(CXX) -g3 -c $< -Wall -I $(INCLUDE) -o $@ %.d: %.cpp $(CXX) -MM -w $< > $@; sed 's/\($*\)\.o[ :]*/\1.o $@: /g' -i $@ gtrans: $(SOURCES:.cpp=.o) $(CXX) *.o -o ../gtrans -Wl,-R,$(LIB) -L$(LIB) -lagraph -lcdt include $(SOURCES:.cpp=.d) .PHONY: clean clean: rm ../gtrans *.o 如果不使用上面的三個功能, Makefile 將會很胖。 比如如果不重新定義 implicit pattern rule 的話, 我們要為每一個 *.o: *.cpp 的規則添加一條編譯命令, 源文件越多, 就會越麻煩。 如果重新定義一條隱晦模式規則 (Implicit pattern rule) , 就可以一次工作,受用無窮。 %.o: %.cpp $(CXX) -g3 -c $< -Wall -I $(INCLUDE) -o $@ 這一條很簡單, 變數 CXX 的默認值是 g++, $< 和 $@ 都是自動化變數, $@ is the file name of the target of the rule; $< is the name of the first dependency. 3. 在Makefile中,我們的依賴關係可能會需要包含一系列的頭文件。 如果是一個比較大型的工程,你必需清楚哪些 C 文件包含了哪些頭文件,並且,你在加入或刪除頭文件時,也需要小心地修改 Makefile,這是一個很沒有維護性的工作。為了避免這種繁重而又容易出錯的事情,我們可以使用 C / C++ 編譯的一個功能。大多數的 C / C++ 編譯器都支持一個「-M」的選項,即自動找尋源文件中包含的頭文件,並生成一個依賴關係。 比如 GTRANS > cc -MM gtrans.cpp gtrans.cpp:4:20: warning: agraph.h: No such file or directory gtrans.o: gtrans.cpp findGraph.hpp preProcess.hpp GTRANS > g++ -MM gtrans.cpp gtrans.cpp:4:20: warning: agraph.h: No such file or directory gtrans.o: gtrans.cpp findGraph.hpp preProcess.hpp 由於 gtrans.cpp 使用到了一個庫文件 agraph, 所以上面會提示一個警告, 另外如果用到了非標準庫的話, 要使用兩個 MM 選項。 我們可以使用一個極端選項 -w (另一個是 -Wall) 來關閉所有警告。 GTRANS > g++ -MM -w gtrans.cpp gtrans.o: gtrans.cpp findGraph.hpp preProcess.hpp 關於該條隱晦模式規則重定義稍微複雜一些,因為它使用到了 sed, 而用到 sed 又難免會用到 Unix 正則表達式 %.d: %.cpp $(CXX) -MM -w $< > $@; sed 's/\($*\)\.o[ :]*/\1.o $@: /g' -i $@ $(CXX) -MM -w $< > $@; 將結果重定向於 .d 文件中, 以 gtrans.d 為例, 重定向後為 gtrans.o: gtrans.cpp findGraph.hpp preProcess.hpp; sed 'script' -i [inputfile] 輸入文件為 .d 文件, 改寫后的結果也直接保存到該文件中。 sed 的腳本中 's/\($*\)\.o[ :]*/\1.o $@: /g' 's/pattern_1/pattern_2/g' 表示將 pattern_1 全部替換為 pattern_2。 那麼 \($*\)\.o[ :]* 與 \1.o $@: 這兩個 pattern 分別表示什麼呢? \( \) 這兩個之間的匹配可以保存使用,一共可以存儲9個, 比如上面的例子, 第二個 pattern 中用到了一個 \1 就是使用第一次 \( \) 之間存儲匹配的東西, 也就是上面的 $*。 而 $* 也是 make 中的一個自動化變數, $* is the stem with which an implicit rule matches, stem 就是比如 %.d 那麼這個 % 就是 stem, 匹配 gtrans.d 那麼 gtrans 就是它的 stem。 後面就簡單了 \. 就是 escape '.' 字元 (因為 . 是可以匹配任何字元的特殊字元), [ :]* 就是空格與 * 的任意數目集。 4. 最後 make 的嵌套使用很簡單, 看一下總 Makefile 例子就懂了 .PHONY: all gtrans isgen cleanall cleanGtrans cleanIsgen all: cd GTRANS && make && cd ..; cd ISGEN && make && cd .. gtrans: cd GTRANS && make isgen: cd ISGEN && make cleanall: cd GTRANS && make clean && cd ..; cd ISGEN && make clean && cd .. cleanGtrans: cd GTRANS && make clean cleanIsgen: cd ISGEN && make clean
[火星人
]
linux編程初步之跟我學之Makefile的舒爽瘦身 已經有428 次圍觀
本文地址: http://coctec.com/docs/linux/show-post-185044.html