GNU Make
定義
GNU Make是一個用來控制執行檔和其他一些從源檔案來的非原始碼檔案版本的軟體。
Make可以從一個名為makefile的檔案中獲得如何構建你所寫程式的依賴關係,Makefile中列出了每個目標檔案以及如何由其他檔案來生成它。 當你編寫一個程式時,你可以為它編寫一個makefile檔案,這樣你就可以使用Make來編譯和安裝這個程式。
功能
Make 使最終用戶可以在不知道構建細節的情況下構建和安裝你的軟體,因為這些細節都記錄在了你提供的Makefile中。
基於源檔案的改動,Make可以自動知道那些檔案需要更新;它也會自動決定檔案更新的適當順序,以避免要更新的檔案依賴於另一個同樣需要更新的檔案。因此,在你修改了程式的原始碼並且執行Make後,你不必重新完全編譯你的所有檔案,只需要重新編譯那些直接或間接受到影響的檔案就好了。
Make不限於任何一種特定的語言。對於程式中任何一種非源檔案, makefile檔案中可以指定shell指令去生成它。shell 指令可以執行編譯器生成目標檔案,執行連結器生成執行檔,執行ar更新庫檔案,執行TeX(一個文本排版軟體)或Makeinfo去格式化文檔。
Make不限於用來生成軟體包。你可以用make來控制安裝和卸載軟體包,或者用來生成標籤表,以及其他的任何你想要做的,當然前提是你寫好怎么做(╬▔皿▔)凸。
Make的規則和目標
Makefile告訴Make怎樣執行一系列的指令去依靠源檔案生成一個目標檔案。Makefile中聲明了一個依賴關係的列表,這個列表應當包含所有檔案(無論是源檔案或者目標)作為輸入。
以下是個簡單的規則示例:
target: dependencies ... commands ...
當你執行make的時候你可以指定特定的目標去更新,否則Make會更新Makefile目標列表中第一個目標。當然作為這個目標輸入的其他目標會先更新。make 用makefile確定那些目標檔案應該被更新,然後那些目標檔案實際上需要更新。如果一個目標檔案比他的所有依賴都新,這樣他就是最新的了,不需要再去重新生成了。其他檔案確實需要更新,要按照正確的順序,在用來生成其他檔案之前先更新自己。
Makefiles和約定
GNU制訂了一些如何編寫Makefiles的約定,所用的GNU軟體包必須遵守。即使你不打算成為GNU軟體,在你的程式中遵循這些約定也是一個好主意,這樣用戶就可以像其他許多軟體包一樣構建你的軟體包,而且不需要學習任何特殊的東西。
這些約定可以在章節``Makefile conventions'' (147 k characters)和章節GNU Coding Standards (147 k characters)中看到。
安卓mk與makefile的關係
Android.mk和Application.mk是基於makefile裝了一層封裝,編寫Android.mk和Application.mk之後可以通過ndk-build執行so的編譯,Android.mk中新增了一些對固定檔案 固定的環境變數的的讀取
如APP_ABI := armeabi-v7a定義在Application.mk中然後執行ndk-build將只編譯armeabi-v7a的so在 當前目錄的上級目錄。
具體參考
通俗點的解釋
當你寫一個簡單的程式,只有一到兩個
源檔案的時候,輸入
% cc file1.c file2.c
就沒什麼問題,但如果有很多源檔案就會很煩人──編譯的時間也會很長。
一個方法就是使用
目標檔案,只在源檔案有改變的情況下才重新編譯源檔案。因此你可以這樣做:
% cc file1.o file2.o ... file37.c ...
上次編譯後,file37.c 發生了改變,但其他檔案沒有。這樣做可以讓編譯過程快很多,但是也不能解決累人的輸入問題。
如果有成百上千的
源檔案的話怎么辦?如果我們在與很多人合作寫程式,別人對源檔案進行了修改,又沒有告訴你,該怎么辦?
也許我們可以把以上兩種方法結合,寫一種像
shellscript 一樣的東西。這種檔案包含某種技巧可以決定什麼時候該對
源檔案進行編譯。如今所有我們要的就是一個程式可以懂得這種技巧,因為要懂得這種技巧,shell 還沒那么大的能耐。
這個程式就叫 make。它讀入一個檔案,叫
makefile,這個檔案決定了源檔案之間的依賴關係。而且決定了源檔案什麼時候該編譯什麼時候不應該編譯。例如,某個規則可以說 “ 如果 fromboz.o 比 fromboz.c 要舊,意思就是有人修改了 fromboz.c,因此我們需要重新編譯這個檔案。”這個
makefile還有規則通知 make 該 怎么 重新編譯源檔案,因此 make 是一個強大得多的工具。
makefile通常和相關的
源檔案保存在同一個目錄下,可以叫做 makefile,Makefile 或者 MAKEFILE。大多數程式設計師會使用 Makefile 這個名字,因為這樣可以讓這個檔案被放在目錄列 表的頂端,可以很容易得看見。
make命令
這是一個非常簡單的 make 檔案:
foo: foo.c
cc -o foo foo.c
包含兩行,一行是依賴關係,一行是執行動作。
依賴關係的那一行包含了程式的名字 (叫做 target),緊跟著一個冒號,然後是空格,最後是源檔案的 名字。當 make讀入這一行的時候,會檢查 foo 是否存在;如果存在,就比較 foo 和 foo.c 最後的修改時間有什 么不同。如果 foo 不存在,或者比 foo.c 要舊,就檢查執行動作那一行看看該怎么做。換句話 說,就是 foo.c 需要重新編譯的時候該怎么辦。
執行動作那一行以一個 tab (按下 tab) 開始,然後是你在命令行下產生 foo 所執行的命令。如果 foo 過期了,或者不存在,make 就會 執行這個命令來產生
foo。換句話說,這就是重新編譯 foo.c 的規則。
因此,當你輸入 make 時,它會確定 foo 和 foo.c 在修改時間上是否同步。這個原則可以在 Makefile 里擴展到成百上千的目標檔案上──實際上,在 FreeBSD 里,你只要在合適的目錄下輸入 make world 就可以編譯整個作業系統!
makefile另一個有用的特點就是目標檔案不一定就是程式。例如,我們可以 有這樣的 make 檔案。
foo: foo.c
cc -o foo foo.c
install:
cp foo /home/me
我們可以輸入如下的命令告訴 make 該執行哪個目標:
% make target
make 會只執行這個目標而忽略其他的目標。例如,如果我們輸入 make foo,就只有 foo 被執行,必要的情況下重新編譯 foo 而不會繼續執行 install 這個目標。
如果我們只是輸入 make 這個命令,make 總會尋找第一個目標,並且在執行完以後就不管其他的目標了。例如,如果我們輸入 make foo,make 就會轉到 foo 這個目標,在必要的情況下重新編譯 foo,而不會執行 install 目標, 然後就停止了。
一定要注意,install 這個目標不依賴任何其他的東西!這意味著我們一旦輸入 make install,這個目標下的所有命令都將被執行。這種情況下,foo 將被安裝到用戶的家目錄下。應用程式的
makefile正是這樣寫的,以便程式在正確編譯後可以被安裝到正確的目錄。
要嘗試解釋的話會比較容易讓人混淆。如果你不太懂 make 是如何工作的,最好的辦法就是先寫一個簡單的程式例如 “hello world” 以及和上面的例子相同的 make 檔案再去實驗。然後 再進一步,使用多個
源檔案,或者讓你的源檔案包含一個頭檔案。 touch 命令在這裡就非常有用了──它能讓在不改變檔案內容的情況下改變檔案的日期。
想進一步學習如何編寫makefile請參考引用4.