1. 程式人生 > >make之makefile 八 make 的執行

make之makefile 八 make 的執行

一般來說,最簡單的就是直接在命令列下輸入make命令,make命令會找當前資料夾的makefile來執行,一切都是自己主動的。但也有時你或許僅僅想讓make重編譯某些檔案,而不是整個工程,而又有的時候你有幾套編譯規則,你想在不同的時候使用不同的編譯規則,等等。本章節就是講述怎樣使用make命令的。

一、make的退出碼

make命令執行後有三個退出碼:

0 —— 表示成功執行。
1 —— 假設make執行時出現不論什麼錯誤,其返回1。
2 —— 假設你使用了make的“-q”選項,而且make使得一些目標不須要更新,那麼返回2。

Make的相關引數我們會在後續章節中講述。


二、指定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,讓其完成你所指定的目標。要達到這一目的非常easy,需在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發現有未定義的變數,那麼就輸出警告資訊。