Makefile整理筆記

1.隱晦規則(自動推導):
指定一個目標爲.o文件時後面的依賴列表自動會添加本身的.c文件
即:
command.o : command.c defs.h command.h 與command.o : defs.h command.h等價
表示command.o目標由頭文件defs.h command.h和command.c生成

2. .PHONY : clean作用:
eg:
$ cat -n Makefile1
clean:
    rm -f app
$ cat -n Makefile2
.PHONY: clean
clean:
    rm -f app
兩個makefile文件,如果當前目錄下存在一個clean的文件會導致因爲存在與Makefile1中一個目標爲clean同名的文件而報錯,原因是因爲
Makefile會根據文件的更新時間來判斷文件是否更新(make),當輸入Makefile時,首先判斷最終生成的目標爲clean,而當前目錄下存在
這個文件時由於沒有更新所以makefile會判斷爲文件沒有修改過所以不會進行編譯,從而報錯:make: 'clean' is up to date
而在目標前一行添加.PHONY會優化這個問題,.PHONY是個僞目標文件,表示不會生成一個文件clean只是單純的一個僞目標。

3.makefile的默認目標一般是第一個目標也是最終的目標,所以一般不要將清空目標放在第一個(一般最後)

4.-號
eg:
    ...
    ...
.PHONY : clean
clean :
    -rm $(obj)
    ...
    ...
-號的作用是在make clean時即使有些文件會出現問題,但是不會立即因爲錯誤返回而後面的指令沒有執行,它會使得繼續做後面的事情。
無論這條命令執行的成功還是失敗都認爲是成功。

5.可以使用任意名稱來書寫Makefile,但是make時需要通過-f或者--file參數來制定
eg:
    make -f Make.Linux 
    make --file Make.AIX
    
6.makefile引用別的makefile通常用include
eg:
    include foo.make a.mk b.mk c.mk e.mk f.mk
這些文件如果沒有以相對路徑或者絕對路徑指定的話,會首先在當前的目錄下查找。

7.VPATH與vpath區別
都是指定一些目錄去尋找依賴文件和目標文件
VPATH後面一般加相對路徑的路徑,多個以:區分
eg:
    VPATH = src:../headers
vpath有三個用法:
1、vpath <pattern> <directories>
爲符合模式<pattern>的文件指定搜索目錄<directories>。用方法中的<pattern>需要包含“%”字符。“%”的意思是匹配零或若干字符。
2、vpath <pattern>
清除符合模式<pattern>的文件的搜索目錄。
3、vpath
清除所有已被設置好了的文件搜索目錄
eg:
    vpath %.h ../headers 該語句表示,要求 make 在“../headers”目錄下搜索所有以“.h”結尾的文件。
    
8.僞目標一般沒有依賴文件,可以將多個目標作爲最終(第一個爲目標標籤)的依賴文件
eg:
all: app1 app2 ...
    ...
    ...
app1: app1.c app1.h
    ...
    ...
app2: app2.c app2.h
    ...
    ...

9.多個目標依賴相同的文件時可以在:前面填入多個目標,make每一個目標的時候都執行一樣的操作

10.過濾函數—filter
$(filter PATTERN…,TEXT) 
函數功能:過濾掉字串“TEXT”中所有不符合模式“PATTERN”的單詞,保留所有符合此模式的單詞。可
以使用多個模式。模式中一般需要包含模式字符“%”。存在多個模式時,模式表達式之間使用空格分
割。
返回值:空格分割的“TEXT”字串中所有符合模式“PATTERN”的字串。 
函數說明:“filter”函數可以用來去除一個變量中的某些字符串。
eg:
sources := foo.c bar.c baz.s ugh.h 
    foo: $(sources) 
    cc $(filter %.c %.s,$(sources)) -o foo 
使用“$(filter %.c %.s,$(sources))”的返回值給 cc 來編譯生成目標“foo”,函數返回值爲“foo.c 
bar.c baz.s”

11.makefile的靜態模式
形式爲<targets ...>: <target-pattern>: <prereq-patterns ...>
eg:
objects = foo.o bar.o
all: $(objects)
$(objects): %.o: %.c
  $(CC) -c $(CFLAGS) $< -o $@
上面的例子中,指明瞭我們的目標從$object中獲取,“%.o”表明要所有以“.o”結尾的目標,也就是
“foo.o bar.o”,也就是變量$object集合的模式,而依賴模式“%.c”則取模式“%.o”的“%”,也就是
“foo bar”,併爲其加下“.c”的後綴,於是,我們的依賴目標就是“foo.c bar.c”。而命令中的“$<”
和“$@”則是自動化變量(見[makefile筆記]之七),“$<”表示所有的依賴目標集(也就是 “foo.c bar.c”),
“$@”表示目標集(也就是“foo.o bar.o”)。
相當於執執行了:
    $(CC) -c foo.c -o foo.o
    $(CC) -c bar.c -o bar.

12.字符串處理函數-subst
$(subst FROM,TO,TEXT)
功能:將TEXT中的東西從FROM變爲TO
返回:函數返回被替換過後的字符串。
eg:
TARGETS =    111.cpp 222.cpp 333.cpp
OTARGETS= $(subst cpp,o,$(TARGETS))
LTARGETS= $(subst cpp,lo,$(TARGETS))
%.o: %.cpp
    g++    -c -o $@    $<
all: objs libs

13.使用編譯器 -M 自動生成依賴選項
注意:這個是編譯器的編譯選項推導出來的輸出效果不是makefile的語法。
在make時編譯器會自動生成對應的依賴關係
eg:
cc -M app.c 等價於:app.o :app.c app.h defs.h
如果使用的是GNU的C/C++編譯器需要使用-MM選項,否則會將一些標準的庫的頭文件包含進來
eg:
如果gcc -MM main.c的輸出是main.o: main.c defs.h則gcc -M main.c 的輸出可能就是:
main.o: main.c defs.h /usr/include/stdio.h /usr/include/features.h \
/usr/include/sys/cdefs.h /usr/include/gnu/stubs.h \
/usr/lib/gcc-lib/i486-suse-linux/2.95.3/include/stddef.h \
/usr/include/bits/types.h /usr/include/bits/pthreadtypes.h \
/usr/include/bits/sched.h /usr/include/libio.h \
/usr/include/_G_config.h /usr/include/wchar.h \
/usr/include/bits/wchar.h /usr/include/gconv.h \
/usr/lib/gcc-lib/i486-suse-linux/2.95.3/include/stdarg.h \
/usr/include/bits/stdio_lim.h

14.替換操作$(sources:.c=.d)
“.c=.d”的意思是做一個替換,把變量$(sources)所有[.c]的字串都替換成[.d]

15.@符號:同步放在字符命令行前,這個命令不會被make顯示出來
eg:
    @echo 正在編譯 XXX 模塊...... 其顯示的結果爲:正在編譯 XXX 模塊......
    
16.-n 或者 --just-print參數
在make時使用以上某個參數只會顯示命令,但是不會執行,一般用於調試

17.-s 或者 --slient參數
全面禁止命令的顯示

18. ;號使用在兩條命令之間
當某條命令依賴於上一條命令所產生的結果時不能將兩條命令分成兩行書寫,應該使用;號隔開
並且將其寫在同一行
eg:
exec:
    cd /home/vmuser
    pwd
執行cd的結果沒有作用,pwd打印當前的makefile路徑
exec:
    cd /home/vmuser;pwd
這樣pwd會打印cd作用後的路徑也就是/home/vmuser

19.-i 或者 --ignore-errors參數
在使用make時添加上面的參數時,本makefile中的所有命令都會忽略錯誤。如果一個規則以.IGNORE作爲目標的,那這個規則中的所有命令
都會被忽略錯誤。
eg:
clean:clean2    
clean2 :
.IGNORE:
    rm kak.o    
執行make clean,當前目錄下沒有kak.o文件,當添加.IGNORE目標的時候運行make clean不會發生錯誤,不添加時會由於rm操作不存在的文
件而報錯。
    
20.-k 或者 --keep-going參數
如果規則中命令出錯了,那麼就終止該規則的執行,但繼續執行其他規則。

21. exports
用法export <variable ...>
用於將變量傳遞給下級的makefile,其中SHELL與MAKEFLAGS兩個變量不需要exports就可以傳遞到下一級makefile中,如果不想將上層的系
統級環境(MAKEFIAGS)傳遞給下一級可以這樣操作:
subsystem:
    cd subdir && $(MAKE) MAKEFLAGS=
其中$(MAKE)中是個變量的形式,其目的就是我們可以改變這個變量來添加make的一些參數以減少維護的工作量。

22.-w 或者 --print-directory參數
用於在調用下級makefile是用於輸出當前工作目錄的信息,例如下級的makefile目錄是/home/vmuser,如果我們使用make -w來執行的話,
當進入該目錄時,我們會看見make: Entering directory `/home/vmuser'.離開時make: Leaving directory `/home/vmuser'
注意:當使用-C參數指定make下級makefile時,-w參數會自動打開,如果參數中有使用-s(--slient)即全面禁止命令的顯示或者是
--no-print-directory那麼-w總是會失效。

23.define .... endef定義命令包
define 指示符後面跟的是變量的名字,而重起一行定義變量的值,定義是以 endef 關鍵字結束。其工作方式和“=”操作符一樣。變量的
值可以包含函數、命令、文字,或是其它變量。 因爲命令需要以[Tab]鍵開頭, 所以如果你用 define 定義的命令變量中沒有以[Tab]鍵
開頭,那麼 make 就不會把其認爲是命令。
eg:
define two_commands
echo 1111111111111
echo 22222222222
endef
相當於two_commands = echo 1111111111111;echo 22222222222
可以直接調用$(two_commands)

24. “=”、“:=”、“?=” 、“+=”
eg:
y := $(x) bar
x := foo
其y的值爲bar
y = $(x) bar
x = foo
其y的值爲foo bar
因爲=以使用後面加載的變量來定義,而:=只能使用前面定義好了的變量
eg:
FOO ?= bar
其含義是,如果FOO沒有被定義過,那麼變量FOO的值就是“bar”,如果FOO先前被定義過,那麼這條語將什麼也不做,其等價於:
ifeq ($(origin FOO), undefined)
FOO = bar
endif
eg:
objects = main.o foo.o bar.o utils.o
objects += another.o
$(objects)的值變成“main.o foo.o bar.o utils.o another.o”,如果變量之前沒有定義過,那麼, “+=”會自動變成“=”。

25. #號使用
#一般是一個註釋符號,也可以用來表示變量的終止符號
eg:
dir := /home/dir #end
sub := /home/vmuser
print:
    @echo $(dir)$(sub)
這裏在定義兩個變量,將第一個變量值設置爲“/home/dir”,並且加一個空格然後加上了一個#end註釋,make print的時候顯示:
“/home/dir /home/vmuser”,其中兩個字符串之間有個空格,這個要注意在定義變量的時候最好注意#註釋的是否合理。如果下文使用
newdir := $(dir)/work 時會導致newdir的值/home/dir /work導致使用時出現問題!
eg:
nullstring :=
space := $(nullstring) # end of the line
nullstring是一個Empty類型的變量,先用一個Empty變量來標明變量的值開始了,而後面採用“#”註釋符來表示變量定義的終止,這樣,
我們可以定義出其值是一個空格的變量。

26.override
在定義變量時在變量名前添加這個關鍵字使得可以通過make命令鍵入時在make後面添加對這個變量的更改語句,更改後的內容將作用在
makefile中。僅限於override定義的變量。
eg:
override CFLAGS = -Wall –g
在make時命令行寫入的是 make CFLAGS=-O2  此時在makefile中使用$(CFLAGS)就是-Wall –g -O2

27.目標變量
用法:
<target ...> : <variable-assignment>
<target ...> : overide <variable-assignment>
類似override可以將某些變量加以追加,在目標後的依賴出添加對應的操作使得在整個目標規則中變量以variable-assignment操作的值存在
eg:
cflags = -wall
auto: cflags += -o    
auto: 
    @echo $(cflags)
auto1:
    @echo $(cflags)
make auto 得到的結果是-wall -o,而make auto1的結果是-wall。可知只有在對應目標的規則(auto)中cflags的值才經過了+= -o操作,
在規則以外且沒有定義這個目標變量的目標內如auto1內不會改變這個變量的值還是爲-wall。

未完待更新。。。


 

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