Makefile速查筆記

Makefile速查筆記

 

Makefile中的幾個調試方法

一. 使用 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

Make 介紹

Makefile 的基本規則就是:ide

target ...: prerequirements ... command ... ...

其中 target 是目標文件,能夠有多個,能夠是 .o 文件或者是可執行問價,甚至能夠是一個標籤。
Prerequisites 是先決條件,能夠是文件,也能夠是另外一個 target。
這就組成了一個依賴關係target 的先決條件定義在 prerequisites 中,而其生成規則又是由 command 決定的。若是包含多個規則的話,那麼第一條規則就是整個 Makefile 的默認規則函數


Make 的工做流程

  1. 在當前目錄中查找 Makefile 或者 makefile 文件
  2. 將文件中第一條規則做爲默認規則
  3. 若是目標不存在,則尋找對應的 .o 文件
  4. 若是 .o 文件不存在,則尋找 .o 的依賴關係以生成它

Makefile 有不少默認的生成規則,可是本文咱們不關心,由於絕大部分狀況下,咱們是須要自行寫規則的。這便於自定義、便於移植、便於交叉編譯、便於調試。ui


Makefile 中的變量

變量的定義和調用格式:

name = value    # 注意變量的值是容許空格的 $(name)

變量值的部分可使用換行符 "\" 來作假換行,將兩行內容鏈接成一行,從而縮短 Makefile 文件的寬度。

Makefile 綜述

Makefile 裏面都有啥?

文件指示:在一個 Makefile 裏面能夠制定另外一個 makefile,相似於 C 的 include

Makefile 還能夠作條件包含動做,相似於 #if。Makefile 能夠定一個變量爲一個多行的命令。

Makefile 裏面只有行註釋而沒有段註釋。註釋採用 # 開頭。若是要使用 # 字符,則須要轉義,寫成 「\#」。

Makefile 規則內容裏全部的 shell 命令都要以製表符 Tab 開頭,注意,空格符是不行的。

默認的 make 文件名爲:GNUmakefilemakefileMakefile,當敲入 make 命令時,會自動搜尋這幾個文件。約定俗成使用最後一個。

引用其餘 Makefile

語法:

include filename ... # 不容許 include 失敗 -include filename ... # 容許 include 失敗

能夠包含路徑或者通配符,一行能夠包含多個文件。

若是未指定絕對路徑或者相對路徑,那麼 make 會按照一下的順序去尋找:

  1. 當前目錄
  2. 制定 make 時,在 -I 或者 --include-dir 的參數下尋找
  3. <prefix>/include(通常是 /usr/local/bin 或 /usr/include

建議仍是手動指定吧,自動搜尋意外可能太多了。

環境變量 MAKEFILES

這裏主要是要提醒:不要設置這個環境變量,不然會影響全局的 make include 動做。

Make 的幾個工做方法

通配符

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,而只是把過程打印出來。


嵌套執行 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))之類的寫法。


override

在命令行調用 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>)


for 循環

$(foreach <var>, <list>, <text>)
這實際上是一個函數,做用是:將 list 的單詞逐一取出,放到 var 指定的變量中,而後執行 text 的表達式。返回值則是 text 的最終執行值。


Shell 函數

執行 shell 命令,而且將 stdout 做爲返回值返回,如:
contents := $(shell ls -la)


控制 make 輸出

$(error <text ...>)
$(warning <text ...>)
這也同時是調試和定位 make 的好方法。


判斷文件是否存在

ifeq ($(FILE), $(wildcard $(FILE))) ... endif

 

================= End

相關文章
相關標籤/搜索