【作業系統】Makefile
阿新 • • 發佈:2022-03-16
make 是一個根據指定的 Shell 命令進行構建的工具——你規定要構建哪個檔案、它依賴哪些原始檔,當那些檔案有變動時,如何重新構建它。
Makefile 格式
<target> : <prerequisites>
[tab] <commands>
目標
- 目標可以是一個檔名,也可以是多個檔名,之間用空格分隔;除了檔名,目標還可以是某個操作的名字。
- 如果 make 命令執行時沒有指定目標,預設會執行 Makefile 檔案的第一個目標。
- 偽目標
.PHONY
:宣告某個“偽目標”後,make 就不會去檢查是否存在一個叫做“偽目標”的檔案,也不會檢查其依賴的修改時間,每次執行都執行對應的命令。
依賴
- 前置檔案(依賴)通常是一組檔名,之間用空格分隔。
- 指定了"目標"是否重新構建的判斷標準:只要有一個前置檔案不存在,或者有過更新(前置檔案的 last modification 時間戳比目標的時間戳新),"目標"就需要重新構建。
- 依賴可以省略。
all: test.txt
echo hello
test.txt:
echo world > test.txt
若當前目錄中沒有 test.txt,在 Shell 中執行 make
將會先執行 echo world > test.txt
,隨後執行 echo hello
。
規則
-
規則是構建"目標"的具體指令。
-
每行命令在一個單獨的 Shell 中執行,這些 Shell 之間沒有繼承關係;若想讓命令間有繼承關係:
-
將兩行命令寫在一行,中間用分號分隔;
-
或在換行符前加反斜槓轉義;
all: mkdir a; cd a; \ touch b;
-
或使用
.ONESHELL:
命令,Mac 自帶 Make 3.81 不支援.ONESHELL:
,需要:-
brew instal make
。 -
open ~/zshrc
。 - 在
export PATH
中新增/usr/local/bin
和/usr/local/opt/make/libexec/gnubin
,使用:
分隔,如:export PATH=/usr/local/bin:/usr/local/opt/make/libexec/gnubin:$PATH
。
-
-
-
每行命令之前必須有一個
[tab]
.RECIPEPREFIX
宣告。
.RECIPEPREFIX=>
.ONESHELL:
all:
>mkdir a
>cd a
>touch b
Makefile 語法
回聲
- 正常情況下,make 會列印每條命令,然後再執行,這就叫做回聲(echoing)。
- 在命令的前面加上
@
,就可以關閉回聲。
萬用字元
- 用來指定一組符合條件的檔名。
- Makefile 的萬用字元與 Bash 一致,主要有星號
*
、問號?
和[...]
。- 萬用字元
?
:匹配一個任意字元。 - 萬用字元
*
: 匹配0個或任意多個字元,也就是可以匹配任何內容。- 例:對於檔案 foo, foo1, foo2, foo10, bar:
-
rm foo?
刪除 foo1 和 foo2。 -
rm foo*
刪除除bar
外的所有檔案。
- 萬用字元
[ ]
:匹配中括號中任意一個字元。[-]
代表範圍,[^]
代表邏輯非。- 例:
[abc]
匹配a
或b
或c
;[a-z]
匹配所有小寫字母;[^0-9]
匹配一個不是數字的字元。
- 例:
- 萬用字元
模式匹配
- make 命令允許對檔名,進行類似正則運算的匹配,主要用到的匹配符是
%
。 - 使用匹配符
%
,可以將大量同類型的檔案,只用一條規則就完成構建。 - 咕咕咕~
變數和賦值
賦值:
-
VAR=value
:在執行時(引用時)擴充套件,允許遞迴擴充套件。varA = hi varB = $(varA) varA = hello all: @echo $(varB) # 輸出 hello
-
VAR:=value
:在定義時(賦值時)擴充套件。varA := hi varB := $(varA) varA := hello all: @echo $(varB) # 輸出 hi
-
VAR?=value
:只有在該變數為空時才設定值。 -
VAR+=value
:將值追加到變數的尾端。
呼叫:
- 變數需要放在
$( )
之中。 - 呼叫 Shell 變數,需要在美元符號前,再加一個美元符號,如
$$HOME
。
內建變數
-
$(CC)
指向當前使用的編譯器。 -
$(MAKE)
指向當前使用的 make 工具。
自動變數
-
$@
:指代當前“目標”。 -
$<
:指代第一個“依賴”。 -
$?
:指代比“目標”新的所有“依賴”。 -
$^
:指代所有“依賴”。 -
$*
:指代匹配符%
匹配的部分。 -
$(@D)
:指向$@
的目錄名。 -
$(@F)
:指向$@
的檔名。 -
$(<D)
:指向$<
的目錄名。 -
$(<F)
:指向$<
的檔名。
判斷和迴圈
判斷:
- 使用
ifeq
、else
和endif
,沒有縮排。
all:
ifeq ($(CC),gcc)
@echo hi
else
@echo hello
endif
# 輸出 hello
- 使用 Bash 語法,有縮排。
.ONESHELL:
all:
@if [ 1 == 2 ]
@then
@echo hi
@else
@echo hello
@fi
# 輸出 hello
迴圈:
.ONESHELL:
LIST = one two three
all:
@for i in $(LIST)
@do
@echo $$i;
@done
函式
-
呼叫方法:
$(function arguments)
或${function arguments}
。 -
內建函式:咕咕咕~