makefile的運行

一般來說,最簡單的就是直接在命令行下輸入 make 命令,make 命令會找當前目錄的makefile 來執行,一切都是自動的。但也有時你也許只想讓 make 重編譯某些文件,而不是整個工程,而又有的時候你有幾套編譯規則,你想在不同的時候使用不同的編譯規則,等等。


一、 make 的退出碼


make 命令執行後有三個退出碼:
0 - 表示成功執行。
1 - 如果 make 運行時出現任何錯誤,其返回 1。
2 - 如果你使用了 make 的“-q”選項,並且 make 使得一些目標不需要更新,那麼返回 2。


二、指定 Makefile


前面我們說過,GNU make 找尋默認的 Makefile 的規則是在當前目錄下依次找三個文件“GNUmakefile”、“makefile”和“Makefile”。其按順序找這三個文件,一旦找到,就開始讀取這個文件並執行。當前,我們也可以給 make 命令指定一個特殊名字的 Makefile。要達到這個功能,我們要使用 make 的“-f”或是“–file”參數(“–makefile”參數也行)。

例如,我們有個makefile 的名字是“hchen.mk”,那麼,我們可以這樣來讓 make 來執行這個文件:make –f hchen.mk。如果在 make 的命令行中, 你不只一次地使用了“-f”參數,那麼, 所有指定的makefile將會被連在一起傳遞給 make 執行。


三、指定目標


一般來說,make 的最終目標是 makefile 中的第一個目標,而其它目標一般是由這個目標連帶出來的。這是 make 的默認行爲。當然,一般來說,你的 makefile 中的第一個目標是由許多個目標組成,你可以指示 make,讓其完成你所指定的目標。要達到這一目的很簡單,需在 make 命令後直接跟目標的名字就可以完成(如前面提到的“make clean”形式)。

任何在 makefile 中的目標都可以被指定成終極目標,但是除了以“-”打頭,或是包含了“=”的目標,因爲有這些字符的目標,會被解析成命令行參數或是變量。甚至沒有被我們明確寫出來的目標也可以成爲 make 的終極目標,也就是說,只要 make 可以找到其隱含規則推導規則,那麼這個隱含目標同樣可以被指定成終極目標。有一個 make 的環境變量叫MAKECMDGOALS,這個變量中會存放你所指定的終極目標的列表,如果在命令行上,你沒有指定目標,那麼,這個變量是空值。這個變量可以讓你使用在一些比較特殊的情形下。比如下面的例子:

sources = foo.c bar.c
ifneq ( $(MAKECMDGOALS),clean)
include $(sources:.c=.d)
endif

基於上面的這個例子,只要我們輸入的命令不是“make clean”,那麼 makefile 會自動包含“foo.d”和“bar.d”這兩個 makefile。使用指定終極目標的方法可以很方便地讓我們編譯我們的程序,例如下面這個例子:

.PHONY: all
all: prog1 prog2 prog3 prog4

從這個例子中,我們可以看到, 這個 makefile 中有四個需要編譯的程序——“prog1”,“prog2”, “prog3”和 “prog4”,我們可以使用“make all”命令來編譯所有的目標(如果把 all 置成第一個目標,那麼只需執行“make”),我們也可以使用“make prog2”來單獨編譯標“prog2”。
即然 make 可以指定所有 makefile 中的目標,那麼也包括“僞目標”,於是我們可以根據這種性質來讓我們的 makefile 根據指定的不同的目標來完成不同的事。在 Unix 世界中,軟件發佈時,特別是 GNU 這種開源軟件的發佈時,其 makefile 都包含了編譯、安裝、打包等功能。我們可以參照這種規則來書寫我們的 makefile 中的目標。

目標名字 含義
“all” 這個僞目標是所有目標的目標,其功能一般是編譯所有的目標。
“clean” 這個僞目標功能是刪除所有被 make 創建的文件。
“install” 這個僞目標功能是安裝已編譯好的程序,其實就是把目標執行文件拷貝到指定的目標中去。
“print” 這個僞目標的功能是例出改變過的源文件。
“tar” 這個僞目標功能是把源程序打包備份。也就是一個 tar 文件。
“dist” 這個僞目標功能是創建一個壓縮文件,一般是把 tar 文件壓成 Z 文件。或是 gz 文件。
“TAGS” 這個僞目標功能是更新所有的目標,以備完整地重編譯使用。
“check”和“test” 這兩個僞目標一般用來測試 makefile 的流程。

當然一個項目的 makefile 中也不一定要書寫這樣的目標,這些東西都是 GNU 的東西,但是我想,GNU 搞出這些東西一定有其可取之處(等你的 UNIX 下的程序文件一多時你就會發現這些功能很有用了),這裏只不過是說明了,如果你要書寫這種功能,最好使用這種名
字命名你的目標,這樣規範一些,規範的好處就是——不用解釋,大家都明白。而且如果你的 makefile 中有這些功能,一是很實用,二是可以顯得你的 makefile 很專業。


四、檢查規則


有時候,我們不想讓我們的 makefile 中的規則執行起來,我們只想檢查一下我們的命令,或是執行的序列。於是我們可以使用 make 命令的下述參數:

“-n”
“--just-print”
“--dry-run”
“--recon”

不執行參數,這些參數只是打印命令,不管目標是否更新,把規則和連帶規則下的命令打印出來,但不執行,這些參數對於我們調試 makefile 很有用處。

“-t”
“--touch”

這個參數的意思就是把目標文件的時間更新,但不更改目標文件。也就是說,make 假裝編譯目標,但不是真正的編譯目標,只是把目標變成已編譯過的狀態。

“-q”
“--question”

這個參數的行爲是找目標的意思,也就是說,如果目標存在,那麼其什麼也不會輸出,當然也不會執行編譯,如果目標不存在,其會打印出一條出錯信息。

“-W <file>”
“--what-if=<file>”
“--assume-new=<file>”
“--new-file=<file>

這個參數需要指定一個文件。一般是是源文件(或依賴文件),Make 會根據規則推導來運行依賴於這個文件的命令,一般來說,可以和“-n”參數一同使用,來查看這個依賴文件所發生的規則命令。另外一個很有意思的用法是結合“-p”和“-v”來輸出 makefile 被執行時的信息。


五、 make 的參數


下面列舉了所有 GNU make 3.80 版的參數定義。其它版本和產商的 make 大同小異,不過其它產商的 make 的具體參數還是請參考各自的產品文檔。


“-b”
“-m”

這兩個參數的作用是忽略和其它版本 make 的兼容性。

“-B”
“--always-make”

認爲所有的目標都需要更新(重編譯)。

“-C <dir>”
“--directory=<dir>

指定讀取 makefile 的目錄。如果有多個“-C”參數,make 的解釋是後面的路徑以前面的作爲相對路徑,並以最後的目錄作爲被指定目錄。如:“make –C ~hchen/test –C prog”等價於“make –C ~hchen/test/prog”。

“—debug[=<options>]

輸出 make 的調試信息。它有幾種不同的級別可供選擇,如果沒有參數,那就是輸出最簡單的調試信息。

下面是<options>的取值:

a —— 也就是 all,輸出所有的調試信息。(會非常的多)
b —— 也就是 basic,只輸出簡單的調試信息。即輸出不需要重編譯的目標。
v —— 也就是 verbose,在 b 選項的級別之上。輸出的信息包括哪個 makefile 被解析,不需要被重編譯的依賴文件(或是依賴目標)等。
i —— 也就是 implicit,輸出所以的隱含規則。
j —— 也就是 jobs,輸出執行規則中命令的詳細信息,如命令的 PID、返回碼等。
m —— 也就是 makefile,輸出 make 讀取 makefile,更新 makefile,執行 makefile 的信息。
“-d”相當於“--debug=a”。
“-e”
“--environment-overrides”

指明環境變量的值覆蓋 makefile 中定義的變量的值。

“-f=<file>”
“--file=<file>”
“--makefile=<file>

指定需要執行的 makefile。

“-h”
“--help”

顯示幫助信息。

“-i”
“--ignore-errors”

在執行時忽略所有的錯誤。

“-I <dir>”
“--include-dir=<dir>

指定一個被包含 makefile 的搜索目標。可以使用多個“-I”參數來指定多個目錄。

“-j [<jobsnum>]”
“--jobs[=<jobsnum>]

指同時運行命令的個數。如果沒有這個參數,make 運行命令時能運行多少就運行多少。如果有一個以上的“-j”參數,那麼僅最後一個“-j”纔是有效的。(注意這個參數在 MS-DOS中是無用的)

“-k”
“--keep-going”

出錯也不停止運行。如果生成一個目標失敗了,那麼依賴於其上的目標就不會被執行了。

“-l <load>”
“--load-average[=<load]”
“—max-load[=<load>]

指定 make 運行命令的負載。

“-n”
“--just-print”
“--dry-run”
“--recon”

僅輸出執行過程中的命令序列,但並不執行。

“-o <file>”
“--old-file=<file>”
“--assume-old=<file>

不重新生成的指定的<file>,即使這個目標的依賴文件新於它。

“-p”
“--print-data-base”

輸出 makefile 中的所有數據,包括所有的規則和變量。這個參數會讓一個簡單的 makefile都會輸出一堆信息。如果你只是想輸出信息而不想執行 makefile,你可以使用“make -qp”命令。如果你想查看執行 makefile 前的預設變量和規則,你可以使用make –p –f/dev/null。這個參數輸出的信息會包含着你的 makefile 文件的文件名和行號,所以,用這個參數來調試你的 makefile 會是很有用的,特別是當你的環境變量很複雜的時候。

“-q”
“--question”

不運行命令,也不輸出。僅僅是檢查所指定的目標是否需要更新。如果是 0 則說明要更新,如果是 2 則說明有錯誤發生。

“-r”
“--no-builtin-rules”

禁止 make 使用任何隱含規則。

“-R”
“--no-builtin-variabes”

禁止 make 使用任何作用於變量上的隱含規則。

“-s”
“--silent”
“--quiet”

在命令運行時不輸出命令的輸出。

“-S”
“--no-keep-going”
“--stop”

取消“-k”選項的作用。因爲有些時候,make 的選項是從環境變量“MAKEFLAGS”中繼承下來的。所以你可以在命令行中使用這個參數來讓環境變量中的“-k”選項失效。

“-t”
“--touch”

相當於 UNIX 的 touch 命令,只是把目標的修改日期變成最新的,也就是阻止生成目標的命令運行。

“-v”
“--version”

輸出 make 程序的版本、版權等關於 make 的信息。

“-w”
“--print-directory”

輸出運行 makefile 之前和之後的信息。這個參數對於跟蹤嵌套式調用 make 時很有用。

“--no-print-directory”

禁止“-w”選項。

“-W <file>”
“--what-if=<file>”
“--new-file=<file>”
“--assume-file=<file>

假定目標<file>需要更新,如果和“-n”選項使用,那麼這個參數會輸出該目標更新時的運行動作。如果沒有“-n”那麼就像運行 UNIX的“touch”命令一樣,使得<file>的修改時間爲當前時間。

“--warn-undefined-variables”

只要 make 發現有未定義的變量,那麼就輸出警告信息。

若想了解關於makefile的更多知識,請參考我的下一篇博客makefile的隱含規則

文章內容來自陳皓的《跟我一起寫makefile》,轉載請註明出處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章