看了好幾天的《GNU Make專案管理》
makefile的規則雖然簡單,但弄出一個能真正有效工作的makefile絕對超出大多數人的想象。
Makefile的目標:
1. 不用手工指定,讓makefile自行推出檔案間的依賴關係(即.cpp與它包含的.h檔案,以及該.h檔案中包含的其他.h檔案間的依賴關係)。
2. rm了項目中的一個檔案之後,makefile還能自動維護檔案間的依賴關係(這些關係就記錄在makefile中)。
為了實現這兩個目標,這本書討論來討論去,先後提出若干種方案,但都有種種缺憾,最後的解決辦法雖然能夠工作,但hack的痕迹也太明顯了,甚至為了支援這個trick(即為每個prerequisites增加一個假象的空target,號稱是automake那幫人發明的),連gcc也增加了一個莫名其妙的選項-MP(hack啊hack)。
如果main.cpp包含了f.h,main.cpp對於f.h的依賴關係就應該被記錄下來。
如果原來main.cpp依賴於f.h,但後來f.h從項目中去掉了,main.cpp對於f.h的依賴關係就應該隨之被去掉。
這種依賴關聯性記錄在什麼地方?makefile中。
這些依賴關係是自動產生的,因為人工指定工作量太大。
去除某些依賴關係的工作也是自動的(人工做的工作就是從目錄中rm這個被其他檔案依賴的檔案),同理。
所謂自動,就還是由makefile自己來做。
根據依賴做事,維護依賴關係,這兩件事情現在都是由makefile來做。
而且還想只運行一遍make就什麼都幹了:
在依賴關係的指導下更新依賴關係,然後根據更新後的依賴關係做事。
也就是:
在makefile的指導下更新makefile(其實是更新include進來的記錄著依賴關係的.d檔案),然後根據更新後的makefile做事。
為了實現第一個目標,make在更新了依賴關係之後就要重頭再來一遍(雖然後來很巧妙的解決了再來一遍的問題, 不過太“巧妙”了)。
為了實現第二個目標,gcc增加了一個與C++編譯器這個身份十萬八千裡、莫名其妙的選項-MP。
makefile的擔子很重啊~
擔子重沒關係,反正是電腦在做,關鍵是它hack,不能夠忍受。
為什麼不把這些事情分開做呢?
比如用一個專門的程式(就叫remove-from-project吧)來負責從屬記錄依賴關係的makefile中去除相關的東西。
用add-to-project往makefile中添加新檔案。
在具有專案管理功能的IDE中做這件事情很容易。
要在命令列做也很容易。
但問題是makefile中的東西太隨心所欲了。
add-to-project和remove-from-project可以假定makefile中它需要的資訊不會被改得面目全非嗎?
它不能。
不光add-to-project和remove-from-project能夠修改它,任何一個普通的文字編輯器都時刻准著在Eric S. Raymond著名屁話(Being Textual)的教導下對其進行增刪。
可憐的makefile,它不是
class Makefile {
public:
void add_to_project(fname);
void remove_from_project(fname);
private:
...
};
而是個人人可得而改之的
struct Makefile {
...
};
其實,罪不在於Being Textual(Be不Being Textual本身就是實現細節),而在於Being Textual的目的:
“讓普通的文字編輯器能夠編輯它們”。
========================================================================================
後記,如今是2012--3-23了。
大概四年前(也就是我寫下以上內容的時候),我被makefile給嚇到了。
於是
在我還不知道scons的時候,我也嘗試著用python做了個類似的東西(epm,地址:http://sourceforge.net/apps/mediawiki/epm/index.php?title=%E4%B8%AD%E6%96%87%E5%85%A5%E5%8F%A3)。這幾年來,我自己的C++項目,小到到一個檔案,大到數百個,都一直是用epm來管理的。當然,這隻是敝帚自珍罷了,epm無論各方面跟scons都是不能比的(我當時要是知道scons,就不會有epm了)。不過,我對makefile的那段評述,大家倒是可以看看。