1. 程式人生 > >Linux makefile 教程

Linux makefile 教程

使用條件判斷
——————

使用條件判斷,可以讓make根據執行時的不同情況選擇不同的執行分支。條件表示式可以是比較變數的值,或是比較變數和常量的值。

一、示例

下面的例子,判斷$(CC)變數是否“gcc”,如果是的話,則使用GNU函式編譯目標。

libs_for_gcc = -lgnu
normal_libs =

foo: $(objects)
ifeq ($(CC),gcc)
$(CC) -o foo $(objects) $(libs_for_gcc)
else
$(CC) -o foo $(objects) $(normal_libs)
endif

可見,在上面示例的這個規則中,目標“foo”可以根據變數“$(CC)”值來選取不同的函式庫來編譯程式。

我們可以從上面的示例中看到三個關鍵字:ifeq、else和endif。ifeq的意思表示條件語句的開始,並指定一個條件表示式,表示式包含兩個引數,以逗號分隔,表示式以圓括號括起。else表示條件表示式為假的情況。endif表示一個條件語句的結束,任何一個條件表示式都應該以endif結束。

當我們的變數$(CC)值是“gcc”時,目標foo的規則是:

foo: $(objects)
$(CC) -o foo $(objects) $(libs_for_gcc)

而當我們的變數$(CC)值不是“gcc”時(比如“cc”),目標foo的規則是:

foo: $(objects)
$(CC) -o foo $(objects) $(normal_libs)

當然,我們還可以把上面的那個例子寫得更簡潔一些:

libs_for_gcc = -lgnu
normal_libs =

ifeq ($(CC),gcc)
libs=$(libs_for_gcc)
else
libs=$(normal_libs)
endif

foo: $(objects)
$(CC) -o foo $(objects) $(libs)


二、語法

條件表示式的語法為:

<conditional-directive>
<text-if-true>
endif

以及:

<conditional-directive>
<text-if-true>
else
<text-if-false>
endif

其中<conditional-directive>表示條件關鍵字,如“ifeq”。這個關鍵字有四個。

第一個是我們前面所見過的“ifeq”

ifeq (<arg1>, <arg2> )
ifeq '<arg1>' '<arg2>'
ifeq "<arg1>" "<arg2>"
ifeq "<arg1>" '<arg2>'
ifeq '<arg1>' "<arg2>"

比較引數“arg1”和“arg2”的值是否相同。當然,引數中我們還可以使用make的函式。如:

ifeq ($(strip $(foo)),)
<text-if-empty>
endif

這個示例中使用了“strip”函式,如果這個函式的返回值是空(Empty),那麼<text-if-empty>就生效。

第二個條件關鍵字是“ifneq”。語法是:

ifneq (<arg1>, <arg2> )
ifneq '<arg1>' '<arg2>'
ifneq "<arg1>" "<arg2>"
ifneq "<arg1>" '<arg2>'
ifneq '<arg1>' "<arg2>"

其比較引數“arg1”和“arg2”的值是否相同,如果不同,則為真。和“ifeq”類似。

第三個條件關鍵字是“ifdef”。語法是:

ifdef <variable-name>

如果變數<variable-name>的值非空,那到表示式為真。否則,表示式為假。當然,<variable-name>同樣可以是一個函式的返回值。注意,ifdef只是測試一個變數是否有值,其並不會把變數擴充套件到當前位置。還是來看兩個例子:

示例一:
bar =
foo = $(bar)
ifdef foo
frobozz = yes
else
frobozz = no
endif

示例二:
foo =
ifdef foo
frobozz = yes
else
frobozz = no
endif

第一個例子中,“$(frobozz)”值是“yes”,第二個則是“no”。

第四個條件關鍵字是“ifndef”。其語法是:

ifndef <variable-name>

這個我就不多說了,和“ifdef”是相反的意思。

在<conditional-directive>這一行上,多餘的空格是被允許的,但是不能以[Tab]鍵做為開始(不然就被認為是命令)。而註釋符“#”同樣也是安全的。“else”和“endif”也一樣,只要不是以[Tab]鍵開始就行了。

特別注意的是,make是在讀取Makefile時就計算條件表示式的值,並根據條件表示式的值來選擇語句,所以,你最好不要把自動化變數(如“
[email protected]
”等)放入條件表示式中,因為自動化變數是在執行時才有的。

而且,為了避免混亂,make不允許把整個條件語句分成兩部分放在不同的檔案中。



使用函式
————

在Makefile中可以使用函式來處理變數,從而讓我們的命令或是規則更為的靈活和具有智慧。make所支援的函式也不算很多,不過已經足夠我們的操作了。函式呼叫後,函式的返回值可以當做變數來使用。


一、函式的呼叫語法

函式呼叫,很像變數的使用,也是以“$”來標識的,其語法如下:

$(<function> <arguments> )

或是

${<function> <arguments>}

這裡,<function>就是函式名,make支援的函式不多。<arguments>是函式的引數,引數間以逗號“,”分隔,而函式名和引數之間以“空格”分隔。函式呼叫以“$”開頭,以圓括號或花括號把函式名和引數括起。感覺很像一個變數,是不是?函式中的引數可以使用變數,為了風格的統一,函式和變數的括號最好一樣,如使用“$(subst a,b,$(x))”這樣的形式,而不是“$(subst a,b,${x})”的形式。因為統一會更清楚,也會減少一些不必要的麻煩。

還是來看一個示例:

comma:= ,
empty:=
space:= $(empty) $(empty)
foo:= a b c
bar:= $(subst $(space),$(comma),$(foo))

在這個示例中,$(comma)的值是一個逗號。$(space)使用了$(empty)定義了一個空格,$(foo)的值是“a b c”,$(bar)的定義用,呼叫了函式“subst”,這是一個替換函式,這個函式有三個引數,第一個引數是被替換字串,第二個引數是替換字串,第三個引數是替換操作作用的字串。這個函式也就是把$(foo)中的空格替換成逗號,所以$(bar)的值是“a,b,c”。


二、字串處理函式

$(subst <from>,<to>,<text> )

名稱:字串替換函式——subst。
功能:把字串<text>中的<from>字串替換成<to>。
返回:函式返回被替換過後的字串。

示例:

$(subst ee,EE,feet on the street),

把“feet on the street”中的“ee”替換成“EE”,返回結果是“fEEt on the strEEt”。


$(patsubst <pattern>,<replacement>,<text> )

名稱:模式字串替換函式——patsubst。
功能:查詢<text>中的單詞(單詞以“空格”、“Tab”或“回車”“換行”分隔)是否符合模式<pattern>,如果匹配的話,則以<replacement>替換。這裡,<pattern>可以包括萬用字元“%”,表示任意長度的字串。如果<replacement>中也包含“%”,那麼,<replacement>中的這個“%”將是<pattern>中的那個“%”所代表的字串。(可以用“/”來轉義,以“/%”來表示真實含義的“%”字元)
返回:函式返回被替換過後的字串。

示例:

$(patsubst %.c,%.o,x.c.c bar.c)

把字串“x.c.c bar.c”符合模式[%.c]的單詞替換成[%.o],返回結果是“x.c.o bar.o”

備註:

這和我們前面“變數章節”說過的相關知識有點相似。如:

“$(var:<pattern>=<replacement> )”
相當於
“$(patsubst <pattern>,<replacement>,$(var))”,

而“$(var: <suffix>=<replacement> )”
則相當於
“$(patsubst %<suffix>,%<replacement>,$(var))”。

例如有:objects = foo.o bar.o baz.o,
那麼,“$(objects:.o=.c)”和“$(patsubst %.o,%.c,$(objects))”是一樣的。

$(strip <string> )

名稱:去空格函式——strip。
功能:去掉<string>字串中開頭和結尾的空字元。
返回:返回被去掉空格的字串值。
示例:

$(strip a b c )

把字串“a b c ”去到開頭和結尾的空格,結果是“a b c”。

$(findstring <find>,<in> )

名稱:查詢字串函式——findstring。
功能:在字串<in>中查詢<find>字串。
返回:如果找到,那麼返回<find>,否則返回空字串。
示例:

$(findstring a,a b c)
$(findstring a,b c)

第一個函式返回“a”字串,第二個返回“”字串(空字串)

$(filter <pattern...>,<text> )

名稱:過濾函式——filter。
功能:以<pattern>模式過濾<text>字串中的單詞,保留符合模式<pattern>的單詞。可以有多個模式。
返回:返回符合模式<pattern>的字串。
示例:

sources := foo.c bar.c baz.s ugh.h
foo: $(sources)
cc $(filter %.c %.s,$(sources)) -o foo

$(filter %.c %.s,$(sources))返回的值是“foo.c bar.c baz.s”。

$(filter-out <pattern...>,<text> )

名稱:反過濾函式——filter-out。
功能:以<pattern>模式過濾<text>字串中的單詞,去除符合模式<pattern>的單詞。可以有多個模式。
返回:返回不符合模式<pattern>的字串。
示例:

objects=main1.o foo.o main2.o bar.o
mains=main1.o main2.o

$(filter-out $(mains),$(objects)) 返回值是“foo.o bar.o”。

$(sort <list> )

名稱:排序函式——sort。
功能:給字串<list>中的單詞排序(升序)。
返回:返回排序後的字串。
示例:$(sort foo bar lose)返回“bar foo lose” 。
備註:sort函式會去掉<list>中相同的單詞。

$(word <n>,<text> )

名稱:取單詞函式——word。
功能:取字串<text>中第<n>個單詞。(從一開始)
返回:返回字串<text>中第<n>個單詞。如果<n>比<text>中的單詞數要大,那麼返回空字串。
示例:$(word 2, foo bar baz)返回值是“bar”。

$(wordlist <s>,<e>,<text> )

名稱:取單詞串函式——wordlist。
功能:從字串<text>中取從<s>開始到<e>的單詞串。<s>和<e>是一個數字。
返回:返回字串<text>中從<s>到<e>的單詞字串。如果<s>比<text>中的單詞數要大,那麼返回空字串。如果<e>大於<text>的單詞數,那麼返回從<s>開始,到<text>結束的單詞串。
示例: $(wordlist 2, 3, foo bar baz)返回值是“bar baz”。

$(words <text> )

名稱:單詞個數統計函式——words。
功能:統計<text>中字串中的單詞個數。
返回:返回<text>中的單詞數。
示例:$(words, foo bar baz)返回值是“3”。
備註:如果我們要取<text>中最後的一個單詞,我們可以這樣:$(word $(words <text> ),<text> )。

$(firstword <text> )

名稱:首單詞函式——firstword。
功能:取字串<text>中的第一個單詞。
返回:返回字串<text>的第一個單詞。
示例:$(firstword foo bar)返回值是“foo”。
備註:這個函式可以用word函式來實現:$(word 1,<text> )。

以上,是所有的字串操作函式,如果搭配混合使用,可以完成比較複雜的功能。這裡,舉一個現實中應用的例子。我們知道,make使用“VPATH”變數來指定“依賴檔案”的搜尋路徑。於是,我們可以利用這個搜尋路徑來指定編譯器對標頭檔案的搜尋路徑引數CFLAGS,如:

override CFLAGS += $(patsubst %,-I%,$(subst :, ,$(VPATH)))

如果我們的“$(VPATH)”值是“src:../headers”,那麼“$(patsubst %,-I%,$(subst :, ,$(VPATH)))”將返回“-Isrc -I../headers”,這正是cc或gcc搜尋標頭檔案路徑的引數。


三、檔名操作函式

下面我們要介紹的函式主要是處理檔名的。每個函式的引數字串都會被當做一個或是一系列的檔名來對待。

$(dir <names...> )

名稱:取目錄函式——dir。
功能:從檔名序列<names>中取出目錄部分。目錄部分是指最後一個反斜槓(“/”)之前的部分。如果沒有反斜槓,那麼返回“./”。
返回:返回檔名序列<names>的目錄部分。
示例: $(dir src/foo.c hacks)返回值是“src/ ./”。

$(notdir <names...> )

名稱:取檔案函式——notdir。
功能:從檔名序列<names>中取出非目錄部分。非目錄部分是指最後一個反斜槓(“/”)之後的部分。
返回:返回檔名序列<names>的非目錄部分。
示例: $(notdir src/foo.c hacks)返回值是“foo.c hacks”。

$(suffix <names...> )

名稱:取字尾函式——suffix。
功能:從檔名序列<names>中取出各個檔名的字尾。
返回:返回檔名序列<names>的字尾序列,如果檔案沒有後綴,則返回空字串。
示例:$(suffix src/foo.c src-1.0/bar.c hacks)返回值是“.c .c”。

$(basename <names...> )

名稱:取字首函式——basename。
功能:從檔名序列<names>中取出各個檔名的字首部分。
返回:返回檔名序列<names>的字首序列,如果檔案沒有字首,則返回空字串。
示例:$(basename src/foo.c src-1.0/bar.c hacks)返回值是“src/foo src-1.0/bar hacks”。

$(addsuffix <suffix>,<names...> )

名稱:加字尾函式——addsuffix。
功能:把字尾<suffix>加到<names>中的每個單詞後面。
返回:返回加過後綴的檔名序列。
示例:$(addsuffix .c,foo bar)返回值是“foo.c bar.c”。

$(addprefix <prefix>,<names...> )

名稱:加字首函式——addprefix。
功能:把字首<prefix>加到<names>中的每個單詞後面。
返回:返回加過字首的檔名序列。
示例:$(addprefix src/,foo bar)返回值是“src/foo src/bar”。

$(join <list1>,<list2> )

名稱:連線函式——join。
功能:把<list2>中的單詞對應地加到<list1>的單詞後面。如果<list1>的單詞個數要比<list2>的多,那麼,<list1>中的多出來的單詞將保持原樣。如果<list2>的單詞個數要比<list1>多,那麼,<list2>多出來的單詞將被複制到<list2>中。
返回:返回連線過後的字串。
示例:$(join aaa bbb , 111 222 333)返回值是“aaa111 bbb222 333”。



四、foreach 函式


foreach函式和別的函式非常的不一樣。因為這個函式是用來做迴圈用的,Makefile中的foreach函式幾乎是仿照於Unix標準Shell(/bin/sh)中的for語句,或是C-Shell(/bin/csh)中的foreach語句而構建的。它的語法是:



$(foreach <var>,<list>,<text> )



這個函式的意思是,把引數<list>中的單詞逐一取出放到引數<var>所指定的變數中,然後再執行<text>所包含的表示式。每一次<text>會返回一個字串,迴圈過程中,<text>的所返回的每個字串會以空格分隔,最後當整個迴圈結束時,<text>所返回的每個字串所組成的整個字串(以空格分隔)將會是foreach函式的返回值。



所以,<var>最好是一個變數名,<list>可以是一個表示式,而<text>中一般會使用<var>這個引數來依次列舉<list>中的單詞。舉個例子:



names := a b c d

files := $(foreach n,$(names),$(n).o)



上面的例子中,$(name)中的單詞會被挨個取出,並存到變數“n”中,“$(n).o”每次根據“$(n)”計算出一個值,這些值以空格分隔,最後作為foreach函式的返回,所以,$(files)的值是“a.o b.o c.o d.o”。



注意,foreach中的<var>引數是一個臨時的區域性變數,foreach函式執行完後,引數<var>的變數將不在作用,其作用域只在foreach函式當中。





五、if 函式


if函式很像GNU的make所支援的條件語句——ifeq(參見前面所述的章節),if函式的語法是:



$(if <condition>,<then-part> )



或是



$(if <condition>,<then-part>,<else-part> )



可見,if函式可以包含“else”部分,或是不含。即if函式的引數可以是兩個,也可以是三個。<condition>引數是if的表示式,如果其返回的為非空字串,那麼這個表示式就相當於返回真,於是,<then-part>會被計算,否則<else-part>會被計算。



而if函式的返回值是,如果<condition>為真(非空字串),那個<then-part>會是整個函式的返回值,如果<condition>為假(空字串),那麼<else-part>會是整個函式的返回值,此時如果<else-part>沒有被定義,那麼,整個函式返回空字串。



所以,<then-part>和<else-part>只會有一個被計算。





六、call函式


call函式是唯一一個可以用來建立新的引數化的函式。你可以寫一個非常複雜的表示式,這個表示式中,你可以定義許多引數,然後你可以用call函式來向這個表示式傳遞引數。其語法是:



$(call <expression>,<parm1>,<parm2>,<parm3>...)



當make執行這個函式時,<expression>引數中的變數,如$(1),$(2),$(3)等,會被引數<parm1>,<parm2>,<parm3>依次取代。而<expression>的返回值就是call函式的返回值。例如:

reverse = $(1) $(2)

foo = $(call reverse,a,b)



那麼,foo的值就是“a b”。當然,引數的次序是可以自定義的,不一定是順序的,如:



reverse = $(2) $(1)

foo = $(call reverse,a,b)



此時的foo的值就是“b a”。





七、origin函式
origin函式不像其它的函式,他並不操作變數的值,他只是告訴你你的這個變數是哪裡來的?其語法是:



$(origin <variable> )



注意,<variable>是變數的名字,不應該是引用。所以你最好不要在<variable>中使用“$”字元。Origin函式會以其返回值來告訴你這個變數的“出生情況”,下面,是origin函式的返回值:



“undefined”

如果<variable>從來沒有定義過,origin函式返回這個值“undefined”。



“default”

如果<variable>是一個預設的定義,比如“CC”這個變數,這種變數我們將在後面講述。



“environment”

如果<variable>是一個環境變數,並且當Makefile被執行時,“-e”引數沒有被開啟。



“file”

如果<variable>這個變數被定義在Makefile中。



“command line”

如果<variable>這個變數是被命令列定義的。



“override”

如果<variable>是被override指示符重新定義的。



“automatic”

如果<variable>是一個命令執行中的自動化變數。關於自動化變數將在後面講述。



這些資訊對於我們編寫Makefile是非常有用的,例如,假設我們有一個Makefile其包了一個定義檔案Make.def,在Make.def中定義了一個變數“bletch”,而我們的環境中也有一個環境變數“bletch”,此時,我們想判斷一下,如果變數來源於環境,那麼我們就把之重定義了,如果來源於Make.def或是命令列等非環境的,那麼我們就不重新定義它。於是,在我們的Makefile中,我們可以這樣寫:



ifdef bletch

ifeq "$(origin bletch)" "environment"

bletch = barf, gag, etc.

endif

endif



當然,你也許會說,使用override關鍵字不就可以重新定義環境中的變量了嗎?為什麼需要使用這樣的步驟?是的,我們用override是可以達到這樣的效果,可是override過於粗暴,它同時會把從命令列定義的變數也覆蓋了,而我們只想重新定義環境傳來的,而不想重新定義命令列傳來的。





八、shell函式


shell函式也不像其它的函式。顧名思義,它的引數應該就是作業系統Shell的命令。它和反引號“`”是相同的功能。這就是說,shell函式把執行作業系統命令後的輸出作為函式返回。於是,我們可以用作業系統命令以及字串處理命令awk,sed等等命令來生成一個變數,如:



contents := $(shell cat foo)



files := $(shell echo *.c)



注意,這個函式會新生成一個Shell程式來執行命令,所以你要注意其執行效能,如果你的Makefile中有一些比較複雜的規則,並大量使用了這個函式,那麼對於你的系統性能是有害的。特別是Makefile的隱晦的規則可能會讓你的shell函式執行的次數比你想像的多得多。





九、控制make的函式


make提供了一些函式來控制make的執行。通常,你需要檢測一些執行Makefile時的執行時資訊,並且根據這些資訊來決定,你是讓make繼續執行,還是停止。



$(error <text ...> )



產生一個致命的錯誤,<text ...>是錯誤資訊。注意,error函式不會在一被使用就會產生錯誤資訊,所以如果你把其定義在某個變數中,並在後續的指令碼中使用這個變數,那麼也是可以的。例如:



示例一:

ifdef ERROR_001

$(error error is $(ERROR_001))

endif



示例二:

ERR = $(error found an error!)

.PHONY: err

err: ; $(ERR)



示例一會在變數ERROR_001定義了後執行時產生error呼叫,而示例二則在目錄err被執行時才發生error呼叫。



$(warning <text ...> )



這個函式很像error函式,只是它並不會讓make退出,只是輸出一段警告資訊,而make繼續執行。

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

相關推薦

Linux makefile 教程 非常詳細,且易懂

最近在學習Linux下的C程式設計,買了一本叫《Linux環境下的C程式設計指南》讀到makefile就越看越迷糊,可能是我的理解能不行。             於是google到了以下這篇文章。通俗易懂。然後把它貼出來,方便學習。            後記,看完發現

Linux makefile 教程 非常詳細,且易懂 ——親身實踐,轉載

隱含規則————在我們使用Makefile時,有一些我們會經常使用,而且使用頻率非常高的東西,比如,我們編譯C/C++的源程式為中間目標檔案(Unix下是[.o]檔案,Windows下是[.obj]檔案)。本章講述的就是一些在Makefile中的“隱含的”,早先約定了的,不需要我們再寫出來的規則。“隱含規則”

Linux makefile教程 非常詳細,且易懂

隱含規則 ———— 在我們使用Makefile時,有一些我們會經常使用,而且使用頻率非常高的東西,比如,我們編譯C/C++的源程式為中間目標檔案(Unix下是[.o]檔案,Windows下是[.obj]檔案)。本章講述的就是一些在Makefile中的“隱含的”,早先約定了的,不需要我們再寫出來的規則。

(轉)Linux makefile 教程 非常詳細,且易懂

隱含規則 ———— 在我們使用Makefile時,有一些我們會經常使用,而且使用頻率非常高的東西,比如,我們編譯C/C++的源程式為中間目標檔案(Unix下是[.o]檔案,Windows下是[.obj]檔案)。本章講述的就是一些在Makefile中的“隱含的”,早先約定了的,不需要我們再寫出來的規則。

Linux makefile 教程

使用條件判斷 —————— 使用條件判斷,可以讓make根據執行時的不同情況選擇不同的執行分支。條件表示式可以是比較變數的值,或是比較變數和常量的值。 一、示例 下面的例子,判斷$(CC)變數是否“gcc”,如果是的話,則使用GNU函式編譯目標。 libs_for_gcc = -lgnu normal_lib

Weblogic12c for Linux安裝教程

weblogic linux Weblogic for Linux軟件安裝流程3.1 主機環境要求本次環境使用一臺CentOS6.5服務器安裝weblogic12c,在同一臺主機上運行管理服務器和受管理服務器,共建立兩臺受管理服務器new_ManagedServer_1、new_ManagedServ

linux基礎教程---設置文件的主人、組別

post 基礎 -s dsm track pos data- chmod pre 我們在操作linux的是要告訴文件是屬於哪個主人的,哪個組別的。這樣我們就須要知道該怎樣設置“: 設置文件的主人、組別 chown: change owner >cho

linux基礎教程---內容操作

article linu 單位 src 輸出內容 lin ont name con 一、尋找文件裏的指定內容 尋找文件裏的指定內容,輸出內容所在行的所有信息 grep 被搜索內容 文件路徑名 >grep var

Linux系列教程(五)——Linux鏈接命令和權限管理命令

密碼 mission pos link 掩碼 Owner 最大的 linux系統 passwd   前一篇博客我們講解了Linux文件和目錄處理命令,還是老生常淡,對於新手而言,我們不需要完全記住命令的詳細語法,記住該命令能完成什麽功能,然後需要的時候去查就好了,用的多了我

Linux系列教程(六)——Linux文件搜索命令

www. 講解 -i linux鏈接 /tmp 任務 html 幫助文檔 大於   前一篇博客我們講解了Linux鏈接命令和權限管理命令, 通過 ln -s 鏈接名 表示創建軟鏈接,不加-s表示創建硬鏈接;還有三個更改權限的命令,chmod命令可以更改文件或目錄權限,ch

Linux系列教程(九)——Linux常用命令之網絡和關機重啟命令

route 註意 端口號 post rac pos 名稱 window ebo   前一篇博客我們講解了Linux壓縮和解壓縮命令,使用的最多的是tar命令,因為現在很多源碼包都是.tar.gz的格式,通過 tar -zcvf 能完成解壓。然後對於.zip格式的文件,使用g

Linux系列教程(十五)——Linux用戶和用戶組管理之用戶管理命令

總結 usr 而且 ron 初始 切換 密碼規則 一個 郵箱目錄   上篇博客我們介紹了用戶管理的相關配置文件,包括用戶信息文件/etc/passwd,用戶密碼文件/etc/shadow;然後介紹了用戶組信息文件/etc/group,用戶組密碼文件/etc/gshadow。

Linux系列教程(十七)——Linux權限管理之文件系統系統屬性chattr權限和sudo命令

系統屬性 brush 選項 all 好的 幫助 博客 簡單 命令   上篇博客我們介紹了權限管理的ACL權限,通過設定 ACL 權限,我們為某個用戶指定某個文件的特定權限。這篇博客我們將介紹權限管理中用的比較多的兩個命令 chattr 和 sudo 。 1、設定文件系統

Linux系列教程(十九)——Linux文件系統管理之手工分區

image u盤 true 掛載 但是 常用 選項 光盤 幫助   上篇博客我們首先介紹了硬盤為什麽要分區,以及Linux系統的幾種分區類型,然後介紹了Linux系統幾個常用的文件系統命令,最後講解了掛載命令,並通過實例演示了如何掛載光盤和U盤。   本篇博客我們將介紹l

Linux系列教程(二十二)——Linux的bash變量

自定義變量 bash 可執行 pre 技術 文件名 使用 什麽是 環境變量   上篇博客我們介紹了bash的一些基本功能,這是我們平時操作最頻繁的。本篇博客我們介紹bash的變量,為後面編寫shell腳本做鋪墊。 1、什麽是變量   變量是計算機內存的單元,其中存放的值

《Unix&Linux大小教程》學習筆記6——Unix文件系統

文件類型 src pos strong ron 輸出 lin post 二進制文件 1:Unix文件類型——3種 普通文件(常規文件):文本文件(純文本、腳本、源程序、配置文件、html等)、二進制文件(多媒體文件、數據庫等) 目錄:用於組織文件 偽文件:不存儲數據,目的是

Linux查看系統版本命令 linux學習教程

mil 命令 linux 內核版本 linux學習 font strong style cat 一、查看Linux內核版本命令方法一:cat /proc/version用法:[root@S-CentOS home]# cat /proc/version方法二:uname -

Linux——makefile編寫

另一個 arch 運用 大量 技術 公司 的人 16px sdn 以前對makefile的編寫,限於剛開始接觸,我都比較局限一些死板的格式,有時候就會顯得有些繁瑣。在進一步了解一些系統編譯和鏈接的知識後,對makefile編寫流程有了一些新的認識,所以來此梳理梳理,方便更靈

Linux 基礎教程 26-基礎網絡配置

如果 普通用戶 任務 名稱 需要 str vim編輯器 兩種 ade 基本配置 ? ? 要想上網,計算機需要有專門的網絡連接設備,即網絡接口卡或者網卡。網卡按照與計算機主機的連接方式可以分為PCI網卡、ISA網卡及無線網卡(USB網卡)等。在Linux中可以使用命令lspc

Linux 基礎教程 29-tcpdump命令-1

會有 才會 由於 以太網 這一 什麽是 制造商 unknown 文章 什麽是tcpdump ? ? 在Linux中輸入命令man tcpdump給出的定義如下所示: tcpdump - 轉儲網絡上的數據流 是不是感覺很懵?我們用通俗、形象、學術的表達方式來全方位描述tcpd