一. 使用 info/warning/error 增長調試信息php
a. $(info "some text")
打印 "some text", 可是不能打印當前makefile文件名和行號.git
b. $(warning "some text")
打印 "some text", 並打印當前makefile文件名和行號.github
c. $(error "error: this will stop the compile")
包含warning的功能,同時會中斷makefile的執行並退出。shell
二. 使用echo增長調試信息(echo只能在target:後面的語句中使用,且前面是個TAB)segmentfault
a. @echo "SHELL ($(SHELL))"安全
全文中尖括號部分表示變量。本文地址:http://www.javashuo.com/article/p-aaofsoxf-gb.htmlruby
Makefile 的基本規則就是:ide
target ...: prerequirements ... command ... ...
其中 target
是目標文件,能夠有多個,能夠是 .o
文件或者是可執行問價,甚至能夠是一個標籤。Prerequisites
是先決條件,能夠是文件,也能夠是另外一個 target。
這就組成了一個依賴關係
:target
的先決條件定義在 prerequisites
中,而其生成規則又是由 command 決定的。若是包含多個規則的話,那麼第一條規則就是整個 Makefile 的默認規則
。函數
Makefile
或者 makefile
文件.o
文件.o
文件不存在,則尋找 .o
的依賴關係以生成它Makefile 有不少默認的生成規則,可是本文咱們不關心,由於絕大部分狀況下,咱們是須要自行寫規則的。這便於自定義、便於移植、便於交叉編譯、便於調試。ui
變量的定義和調用格式:
name = value # 注意變量的值是容許空格的 $(name)
變量值的部分可使用換行符 "\
" 來作假換行,將兩行內容鏈接成一行,從而縮短 Makefile 文件的寬度。
文件指示:在一個 Makefile 裏面能夠制定另外一個 makefile,相似於 C 的 include
Makefile 還能夠作條件包含動做,相似於 #if
。Makefile 能夠定一個變量爲一個多行的命令。
Makefile 裏面只有行註釋而沒有段註釋。註釋採用 #
開頭。若是要使用 #
字符,則須要轉義,寫成 「\#
」。
Makefile 規則內容裏全部的 shell 命令都要以製表符 Tab
開頭,注意,空格符是不行的。
默認的 make 文件名爲:GNUmakefile
, makefile
, Makefile
,當敲入 make
命令時,會自動搜尋這幾個文件。約定俗成使用最後一個。
語法:
include filename ... # 不容許 include 失敗 -include filename ... # 容許 include 失敗
能夠包含路徑或者通配符,一行能夠包含多個文件。
若是未指定絕對路徑或者相對路徑,那麼 make 會按照一下的順序去尋找:
<prefix>/include
(通常是 /usr/local/bin
或 /usr/include
)建議仍是手動指定吧,自動搜尋意外可能太多了。
這裏主要是要提醒:不要設置這個環境變量,不然會影響全局的 make include 動做。
Make 支持三個通配符:*, ?, [...]
。能夠用在規則中,也能夠用在變量中。
僞目標就是 Makefile 裏面頗爲常見的 .PHONY
標識,好比:".PHONY: clean
",表示這個規則名並不表明一個真實存在的、須要生成的文件名,而只是一條純粹的規則。
除了 make clean
以外,僞目標還有另外一種使用場景,就是一個 make 動做,實際上生成了多個目標。好比:
.PHONY: all all: exe install # 包含了生成目標文件,以及安裝動做
規則的冒號前面能夠有多個 target,表示多個 target 共用這條規則。
若是咱們使用中規中矩的 makefile 寫法,那麼對於每一個源文件都要好好寫頭文件依賴關係,從而在頭文件更新的時候,能夠自動從新編譯依賴於這個頭文件的源文件。
這實在是太麻煩了。好在 gcc
裏有一個 -MM
(注意不是 「-M」) 的選項,能夠分析出 .c
文件依賴的頭文件而且打印出來。所以製做 Makefile 的時候,就能夠利用這一特性自動生成依賴。
實現方法有不少,這裏貼出我本身使用的例子,也能夠參見個人工程代碼:
EXCLUDE_C_SRCS =# C_SRCS = $(filter-out $(EXCLUDE_C_SRCS), $(wildcard *.c)) C_OBJS = $(C_SRCS:.c=.o) $(C_OBJS): $(C_OBJS:.o=.c) $(CC) -c $(CFLAGS) $*.c -o $*.o @$(CC) -MM $(CFLAGS) $*.c > $*.d @mv -f $*.d $*.d.tmp @sed -e 's|.*:|$*.o:|' < $*.d.tmp > $*.d @sed -e 's/.*://' -e 's/\\$$//' < $*.d.tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $*.d @rm -f $*.d.tmp
這裏的命令,指的是在 Makefile 規則裏的 「command」 部分。
將 「@
」 放在一條命令的前面,表示實際執行的時候,不打印這條命令語句,能夠節省屏幕內容,減小垃圾信息(特別是個人自動生成依賴的命令,調通了以後,那就是一堆無用信息)。若是將 「-
」 放在命令前面,則表示無視這條命令的返回值是否爲成功(0).
若是上一條命令的結果須要用於下一條命令時,須要將這些命令寫在一行中。建議用 「\
」 分開。這最典型的是 cd
命令及其以後的一連串命令。
Make 的時候加上 -n
選項或 --just-print
選項,則表示不執行 make,而只是把過程打印出來。
在 Makefile 裏能夠到另外一個目錄下執行 make,執行方式相似於普通的命令調用,但特別的是,make 能夠識別出這是一條嵌套 make 指令,從而在 shell 中打印出 「專項哪里哪里 make」 的提示語法爲:
subsystem: $(MAKE) -C subdir
這個作法的主要好處是能夠向下級 Makefile 傳遞變量或者語法:
export VARIABLE ... # 將相應變量變成當前 make 操做的全局變量
也惡意直接指定變量的值:
export VARIABLE = value
若是要傳遞全部變量(不推薦),直接寫 export
就好。
注意由兩個系統變量 SHELL
和 MAKEFLAGS
是永遠傳遞的。
此外還有一個全局變量 MAKELEVEL
用來表示當前的嵌套層數。
命令包相似於宏、子函數等等。使用 define
來定義,以 endif
結束,好比:
define run-yacc yacc $(firstword $^) mv y.tab.c $@ endif
注意若是是命令的話,須要以製表符
開頭。調用這個命令包的方式爲:$(run-yacc)
變量定義時必須賦值,至少賦一個空值(只有等號,等號右邊什麼都沒有)
使用變量的時候雖然不強制、可是爲了安全起見,應該使用括號或者打括號把變量包含起來。若是要使用字符 "$
",則使用 "$$
" 來轉義
賦值時,等號右側能夠有未定義的變量,而且在其實際使用時才展開變量的內容。但這可能會致使循環引用。爲了不這一點,可使用 ":=
" 符號來避免使用未定義的變量
"+=
" 的做用是 「追加」 值。若是右側有變量未定義,則等價於 「:=
」
"?=
" 的做用是:若是等號左側的變量未定義,則使用等號右邊內容定義,即:
ifeq ($(some_var), undefined) some_var = some_val endif
另外:$@
表示當前規則的編譯目標$^
表示當前規則的全部依賴文件$$<
表示當前規則的第一個依賴。
NULL_STR :=# SPACE_STR := $(NULL_STR) # end of line
注意第二行的註釋與 「)」 之間是包含一個空格的。註釋的 「#」 必須有,不然不會定義一個空格出來。
第一個方式爲:$(var: .o = .c)
,意思是將等號左邊的字符換成右邊的字符
第二個方式爲所謂的 「靜態模式」:$(var: %.o = %.c)
這很相似於指針,只是地址值變成了變量值。能夠用變量值生成變量名,好比:a := $($(var))
或者是 $($(var)_$(idx))
之類的寫法。
在命令行調用 make 時,能夠直接指定某個變量的全局值,使得它在整個 make 的過程當中一直不變。爲了防止這個特性,可使用這個關鍵字來處理:override <variable> = <value>
等號也能夠用 :=
和 ?=
若是某條約束裏面不想使用已經定義了的全局變量,能夠這樣寫:
prog: CFLAGS = -g prog: a.o b.o $(CC) $(CFLAGS) a.o b.o
<條件語句>
<true 執行語句> else <false 執行語句> endif
其中條件語句有四種情形:
一、表示是否相等
ifeq (<arg1>, <arg2>) # 推薦 ifeq '<arg1>' '<arg2>' ifeq "<arg1>" "<arg2>"
二、表示是否不等,上面的 ifeq 換成 ifneq
三、ifdef
四、ifndef
Make 的全部函數都是內置函數,不能本身定義(命令包除外)。下面列出經常使用的函數,若是看不懂再詳細查閱。
$(subst <from>, <to>, <text>)
$(patsubst <pattern>, <replacement>, <text>)
$(strip <string>)
$(findstring <find>, <in>)
$(filter-out <pattern_or_string>, <text>)
$(sort <list>)
$(word <n>, <text>)
$(wordlist <n_start>, <n_end>, <text>)
$(words <text>)
$(dir <names ...>)
$(notdir <names ...>)
$(suffix <names ...>)
$(addsuffix <suffix>, <names ...>)
加先後綴在動態建立局部變量頗有用$(addprefix <prefix>, <names ...>)
$(join <list1>, <list2>)
$(foreach <var>, <list>, <text>)
這實際上是一個函數,做用是:將 list
的單詞逐一取出,放到 var
指定的變量中,而後執行 text
的表達式。返回值則是 text
的最終執行值。
執行 shell 命令,而且將 stdout 做爲返回值返回,如:contents := $(shell ls -la)
$(error <text ...>)
$(warning <text ...>)
這也同時是調試和定位 make 的好方法。
ifeq ($(FILE), $(wildcard $(FILE))) ... endif
================= End