国产成人精品999视频&日本一区二区亚洲人妻精品&久久久精品国产99久久精&99热这里只有成人精品国产&精品国产剧情av一区二区&成人亚洲精品久久久久app&国产精品美女高潮抽搐A片

make 備忘清單

包含 最重要概念、函數(shù)、方法等的 make 備忘單。 初學(xué)者的完整快速參考。

Makefile 入門

示例

a.txt: b.txt c.txt
	cat b.txt c.txt > a.txt

工作流程

  • 讀入所有的 Makefile
  • 讀入被 include 的其它 Makefile。
  • 初始化文件中的變量。
  • 推導(dǎo)隱晦規(guī)則,并分析所有規(guī)則。
  • 為所有的目標(biāo)文件創(chuàng)建依賴關(guān)系鏈。
  • 根據(jù)依賴關(guān)系,決定哪些目標(biāo)要重新生成。
  • 執(zhí)行生成命令。

文件命令

make命令會以 GNUmakefile(不推薦使用)、makefile、Makefile(推薦使用)的順序查找當(dāng)前目錄下的文件。

自定義文件路徑

$ make target -f FILE

我們可以使用 -f FILE 來指定makefile文件的路徑

隱式生成

如果文件夾中沒有 makefile 文件,只有 main.c 源文件,那么我們可以使用 make main.o 隱式生成鏈接文件

$ make main.o
# 實際執(zhí)行: cc    -c -o main.o main.c

規(guī)則

TARGET: PREREQUISITES
  COMMAMD
...
  • target: 規(guī)則的目標(biāo)。目標(biāo)可以是規(guī)則的動作(如 clean 等),也可以是目標(biāo)文件或者最后的可執(zhí)行文件。
  • prerequisites: 規(guī)則的依賴。生成規(guī)則目標(biāo)文件所需要的文件名列表(通常一個目標(biāo)依賴于一個或者多個文件)。
  • command: 規(guī)則的命令行。規(guī)則要執(zhí)行的動作(任意的 shell 命令或者在 shell 下執(zhí)行的程序)。命令需要以 tab 鍵開頭
$ make [TARGET ...]

$ make        # 沒有參數(shù)首先運行 TARGET
$ make help   # 顯示可用目標(biāo)
$ make dist   # 從當(dāng)前目錄制作一個發(fā)布存檔
$ make check  # 無需安裝的單元測試

清空目標(biāo)文件

.PHONY: clean
clean:
  rm *.o temp

.PHONY 內(nèi)置命令將排除 clean 文件,不會因為當(dāng)前目錄中因為有 clean 文件而不會不執(zhí)行 clean 偽目標(biāo)

clean 從來都是放在文件的最后

注釋

makefile 文件的注釋與 bash 腳本一致

# 這是一個注釋
main.o : main.c
	cc -c main.c

換行 \

# 這是一個注釋
main.o : main.c
	cc -c \
	main.c

引用其它的 Makefile

include 關(guān)鍵字可以把別的 Makefile 包含進來。這樣使用 make 運行的時候就會

# makefile
include foo.make

如果你想讓 make 不理那些無法讀取的文件,并且繼續(xù)執(zhí)行。

-include <filename>

變量

賦值符

在執(zhí)行時擴展,允許遞歸擴展

VARIABLE = value

在聲明時擴展

可以防止遞歸,并且只能引用之前聲明過的變量

VARIABLE := value

只有在該變量為空時才設(shè)置值

VARIABLE ?= value

將值追加到變量的尾端

VARIABLE += value

override

如果變量前不指定 override,那么命令行中指定的變量可以對 Makefile 中的變量重新定義。

# 不會重新定義
override VARIABLE = value
override VARIABLE := value
override VARIABLE ?= value
override VARIABLE += value
override define
  #...
endef

變量

需要使用 $() 或者 ${} 對變量進行引用

file = main.c

run:
	clang -o hello ${file}

避免遞歸變量

# 這樣會使變量陷入無窮遞歸
A = $(B)
B = $(A)

x := foo
y := $(x) bar
x := later

# 等價于
# x = later
# y = foo bar

Shell 變量

如果要使用 Shell 變量,需要在之前加上 $

run:
	echo $$HOME

定義多行變量

define foo
echo foo
echo bar
endef

run:
	${foo}

自動變量

$@

$@:指代當(dāng)前目標(biāo),即 Make 命令當(dāng)前構(gòu)建的那個目標(biāo)

foo:
	touch $@

$ make foo
# $@ 就是指的這里的 foo

$<

$< 指代第一個前置條件。比如,規(guī)則為 t: p1 p2,那么 $< 就指代 p1

a.md: b.md c.md
  cp $< $@

使用 make a.md,相當(dāng)于以下寫法

a.md: b.md c.md
    cp b.md a.md 

$^

$^ 指代所有的前置條件,去除重復(fù)項

a.md: b.md c.md
  echo $^

$+

$^ 指代所有的前置條件,不會去除重復(fù)項

a.md: b.md c.md c.md
	echo $+

$?

$? 指代更新的依賴,只有最近更新過的依賴才會引用

a.md: b.md c.md c.md
	cat $? > a.md

$*

$* 指代匹配符匹配的部分

main.o: main.c
	clang -o $* $*.c

$ make main
# 此時 cc  main.c -o main

$%

$%: 僅當(dāng)目標(biāo)是函數(shù)庫文件中,表示規(guī)則中的目標(biāo)成員名

  • windows 中是 .lib 文件
  • unix 中是 .a 文件

內(nèi)置命名變量的參數(shù)

這些變量都是相關(guān)下面的命令的參數(shù)。如果沒有指明其默認(rèn)值,那么其默認(rèn)值都是空。

:-:-
ARFLAGS函數(shù)庫打包程序AR命令的參數(shù)。默認(rèn)值是 rv
ASFLAGS匯編語言編譯器參數(shù)。(當(dāng)明顯地調(diào)用 .s.S 文件時)
CFLAGSC 語言編譯器參數(shù)。
CXXFLAGSC++ 語言編譯器參數(shù)。
COFLAGSRCS 命令參數(shù)。
CPPFLAGSC 預(yù)處理器參數(shù)。( CFortran 編譯器也會用到)。
FFLAGSFortran 語言編譯器參數(shù)。
GFLAGSSCCS get 程序參數(shù)。
LDFLAGS鏈接器參數(shù)。(如:ld
PFLAGSPascal 語言編譯器參數(shù)。
LFLAGSLex 文法分析器參數(shù)。
RFLAGSRatfor 程序的 Fortran 編譯器參數(shù)。
YFLAGSYacc 文法分析器參數(shù)。

內(nèi)置已命名的變量

:-:-
AR函數(shù)庫打包程序。默認(rèn)命令是 ar
AS匯編語言編譯程序。默認(rèn)命令是 as
CCC 語言編譯程序。默認(rèn)命令是 cc
CXXC++ 語言編譯程序。默認(rèn)命令是 g++
CO從 RCS 文件中擴展文件程序。默認(rèn)命令是 co
CPPC 程序的預(yù)處理器(輸出是標(biāo)準(zhǔn)輸出設(shè)備)。默認(rèn)命令是 $(CC) –E
FCFortran 和 Ratfor 的編譯器和預(yù)處理程序。默認(rèn)命令是 f77
GET從 SCCS 文件中擴展文件的程序。默認(rèn)命令是 get
LEXLex 方法分析器程序(針對于 C 或 Ratfor)。默認(rèn)命令是 lex
PCPascal 語言編譯程序。默認(rèn)命令是 pc
YACCYacc 文法分析器(針對于 C 程序)。默認(rèn)命令是 yacc
YACCRYacc 文法分析器(針對于 Ratfor 程序)。默認(rèn)命令是 yacc –r
MAKEINFO轉(zhuǎn)換 Texinfo 源文件(.texi)到 Info 文件程序。默認(rèn)命令是 makeinfo
TEX從 TeX 源文件創(chuàng)建TeX DVI文件的程序。默認(rèn)命令是 tex
TEXI2DVI從 Texinfo 源文件創(chuàng)建 TeX DVI 文件的程序。默認(rèn)命令是 texi2dvi
WEAVE轉(zhuǎn)換 Web 到 TeX 的程序。默認(rèn)命令是 weave
CWEAVE轉(zhuǎn)換 C Web 到 TeX 的程序。默認(rèn)命令是 cweave
TANGLE轉(zhuǎn)換 Web 到 Pascal 語言的程序。默認(rèn)命令是 tangle
CTANGLE轉(zhuǎn)換 C Web 到 C。默認(rèn)命令是 ctangle
RM刪除文件命令。默認(rèn)命令是 rm –f

內(nèi)置的變量

run:
	${CC} -o main main.c

書寫規(guī)則

文件搜尋(vpath

如果沒有指定 vpath 變量,make 只會在當(dāng)前的目錄中去尋找依賴文件和目標(biāo)文件。否則,如果當(dāng)前目錄沒有,就會到指定的目錄中去尋找

:-:-
vpath <pattern> <directories>為符合模式 <pattern> 的文件指定搜索目錄 <directories>
vpath <pattern>清除符合模式 <pattern> 的文件的搜索目錄。
vpath清除所有已被設(shè)置好了的文件搜索目錄

%

  • vpath 使用方法中的 <pattern> 需要包含 % 字符。% 的意思是匹配零或若干字符(類似于通配符),并且引用規(guī)則是需要使用自動變量
vpath %.c dist
TARGET = hello
OBJ = bar.o foo.o

$(TARGET): $(OBJ)
	$(CC) -o $@ $^

%.o: $.c
	$(CC) -o $< -o #@

通配符

*

*:與 linux 系統(tǒng)下的一樣

# 清除所有 .o 結(jié)尾的文件
clean:
    rm -f *.o

~

~:在 linux 或 mac 下表示用戶目錄,win 下表示 HOME 環(huán)境變量

run:
    ls ~

?

?: 與在 linux 等類似,可以匹配單個字符

run:
	ls -ll packag?.json

靜態(tài)模式

TARGET: PREREQUISITES :PREREQUISITES
  COMMAMD
#...
  • target 定義了一系列的目標(biāo)文件
  • 第一個 prerequisites 是指明了 target 的模式,也就是的目標(biāo)集模式。
  • 第二個 prerequisites 是目標(biāo)的依賴模式,它對第一個 prerequisites 形成的模式再進行一次依賴目標(biāo)的定義
objects = foo.o main.o

$(objects): %.o: %.c
	$(CC) -c $(CFLAGS) $< -o $@

相當(dāng)于:

foo.o : foo.c
    $(CC) -c $(CFLAGS) foo.c -o foo.o
main.o : main.c
    $(CC) -c $(CFLAGS) main.c -o main.o

偽目標(biāo)

  • 偽目標(biāo)并不是一個文件,只是一個標(biāo)簽。只有通過顯式地指明這個目標(biāo)才能讓其生效
  • 使用 .PHONY 來顯式地指明目標(biāo)是 偽目標(biāo)
.PHONY : clean
clean :
    rm *.o temp

約定俗成的規(guī)則

:-:-
all該偽目標(biāo)是所有目標(biāo)的目標(biāo),一般用于編譯所有的目標(biāo)
clean該偽目標(biāo)用于刪除所有由 make 創(chuàng)建的文件
install該偽目標(biāo)用于安裝已編譯好的程序,即將目標(biāo)執(zhí)行文件拷貝到指定目標(biāo)中
print該偽目標(biāo)用于例出改變過的源文件
tar該偽目標(biāo)用于把源程序打包備份為 tar 文件
dist該偽目標(biāo)用于創(chuàng)建壓縮文件,一般將 tar 文件壓成 Z 或 gz 文件
TAGS該偽目標(biāo)用于更新所有的目標(biāo),以備完整地重編譯使用
check/test這兩個偽目標(biāo)用于測試 makefile 的流程

命令

回聲(@

正常情況下,make會打印每條命令,然后再執(zhí)行,這就叫做回聲(echoing)

all:
  # 會有命令執(zhí)行顯示
	echo Hello, world

all:
  # 不會有命令執(zhí)行的顯示
	@echo Hello, world

顯示命令、禁止命令

顯示命令

如果我們只希望顯示命令,而不希望執(zhí)行命令,可以使用 -n 或者 --just-print

$ make all --just-print 
$ make all -n 

禁止命令

-s--silent--quiet@ 一樣,用于禁止回聲

$ make all -s 

執(zhí)行命令

使用 tab 及換行

exec:
    cd /home/hchen
    pwd

使用 ;

exec:
    cd /home/hchen; pwd

make 參數(shù)

:-:-
-b,-m忽略和其它版本make的兼容性
-B(--always-make) 認(rèn)為所有的目標(biāo)都需要重編譯
-C <dir>(--directory=<dir>) 指定讀取makefile的目錄
-e(--environment-overrides) 指明環(huán)境變量的值覆蓋 makefile 中定義的變量的值
-f=<file>指定需要執(zhí)行的makefile
-h顯示幫助信息
-i(--ignore-errors)在執(zhí)行時忽略所有的錯誤
-I <dir>(--include-dir=<dir>) 指定一個被包含 makefile 的搜索目標(biāo)
-j [<nums>](--jobs[=<jobsnum>])指同時運行命令的個數(shù)
-k(--keep-going)出錯也不停止運行
-l <load>--load-average[=<load>]-max-load[=<load>] 指定make運行命令的負(fù)載
-n(--just-print, --dry-run, --recon) 僅輸出執(zhí)行過程中的命令序列,但不執(zhí)行
-o <file>(--old-file=<file>, --assume-old=<file>)不重新生成的指定的 <file>,即使目標(biāo)的依賴文件新于它
-p(--print-data-base) 輸出 makefile 中的所有數(shù)據(jù),包括所有的規(guī)則和變量
-q(--question) 不運行命令,也不輸出。僅僅是檢查所指定的目標(biāo)是否需要更新
-r(--no-builtin-rules) 禁止 make 使用任何隱含規(guī)則
-R(--no-builtin-variabes) 禁止 make 使用任何作用于變量上的隱含規(guī)則
-s(--silent,--quiet) 在命令運行時不輸出命令的輸出
-S(--no-keep-going, --stop) 取消“-k”選項的作用
-t--touch 相當(dāng)于 UNIX 的 touch 命令,只是把目標(biāo)的修改日期變成最新的,也就是阻止生成目標(biāo)的命令運行
-v(--version) 輸出 make 程序的版本、版權(quán)等關(guān)于 make 的信息
-w(--print-directory) 輸出運行 makefile 之前和之后的信息。--no-print-directory 可以禁止 -w
-W <file>--what-if=<file>, --new-file=<file>, --assume-file=<file> 假定目標(biāo) <file> 需要更新,如果和 -n 選項使用,那么這個參數(shù)會輸出該目標(biāo)更新時的運行動作
--warn-undefined-variables只要 make 發(fā)現(xiàn)有未定義的變量,那么就輸出警告信息

-debug[=<options>]

輸出 make 的調(diào)試信息。下面是 <options>的取值:

options:-
aall,輸出所有的調(diào)試信息
bbasic,只輸出簡單的調(diào)試信息。即輸出不需要重編譯的目標(biāo)
vverbose,包括 b 的信息。輸出包括 makefile 被解析的信息,不需要被重編譯的依賴文件等
iimplicit,輸出所有的隱含規(guī)則
jjobs,輸出執(zhí)行規(guī)則中命令的詳細(xì)信息,如命令的 PID、返回碼等
mmakefile,輸出 make 讀取 makefile,更新 makefile,執(zhí)行 makefile 的信息

make 的退出碼

:-:-
0成功執(zhí)行
1運行時出現(xiàn)錯誤
2使用了 -q 選項,并且一些目標(biāo)不需要更新

判斷和循環(huán)

單分支條件判斷

  • ifeq 的意思表示條件語句的開始,表達式包含兩個參數(shù),如果相同則為真。
  • ifneq 的意思表示條件語句的開始,表達式包含兩個參數(shù),如果不同則為真。
  • else 表示條件表達式為假的情況。
  • endif 表示一個條件語句的結(jié)束,任何一個條件表達式都應(yīng)該以 endif 結(jié)束。
run:
ifeq ($(CC), cc)
	$(CC) -o foo foo.c
else
	$(CC) -o bar bar.c
endif

多分支條件判斷

ifneq 語法

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

ifeq 語法

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

ifdef

ifdef <variable-name>

ifdef 會根據(jù) variable-name 判斷,如果為空則為真

bar =
foo = $(bar)
ifdef foo
    frobozz = yes
else
    frobozz = no
endif

run:
	echo $(frobozz)

ifndef 則和 ifdef 是相反的意思

for 循環(huán)

LIST = one two three
all:
	for i in $(LIST); do \
	    echo $$i; \
	done

函數(shù)

字符串處理函數(shù) - 替換函數(shù)(subst)

把字串 <text> 中的 <from> 字符串替換成 <to> 。

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

示例

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

字符串處理函數(shù) - 模式字符串替換函數(shù)(patsubst)

查找 <text> 中的單詞(單詞以空格、Tab或回車換行分隔)是否符合模式 <pattern>。匹配,則以 <replacement> 替換。

$(patsubst <pattern>,<replacement>,<text>)
  • 示例
$(patsubst %.c,%.o,x.c.c bar.c)

把字串 x.c.c bar.c 符合模式 %.c 的單詞替換成 %.o ,返回結(jié)果是 x.c.o bar.o

字符串處理函數(shù) - 去空格函數(shù)(strip)

去掉 字串中開頭和結(jié)尾的空字符。

$(strip <string>)

示例

$(strip a b c )

把字串 a b c 去掉開頭和結(jié)尾的空格,結(jié)果是 a b c。

字符串處理函數(shù) - 查找字符串函數(shù)(findstring)

在字串 <in> 中查找 <find> 字串。

$(findstring <find>,<in>)

示例:

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

第一個函數(shù)返回 a 字符串,第二個返回空字符串

字符串處理函數(shù) - 過濾函數(shù)(filter)

以 <pattern> 模式過濾 <text> 字符串中的單詞,保留符合模式 <pattern> 的單詞??梢杂卸鄠€模式。

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

示例

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

字符串處理函數(shù) - 反過濾函數(shù)(filter-out)

以 <pattern> 模式過濾 <text> 字符串中的單詞,去除符合模式 <pattern> 的單詞。可以有多個模式。

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

示例:

objects=main1.o foo.o main2.o bar.o
mains=main1.o main2.o
$(filter-out $(mains),$(objects)) 
# 返回值是 foo.o bar.o 。

字符串處理函數(shù) - 排序函數(shù)(sort)

給字符串 <list> 中的單詞排序(升序)。

$(sort <list>)
  • 示例:$(sort foo bar lose) 返回 bar foo lose
  • 注意:sort 函數(shù)會去掉 <list> 中相同的單詞

字符串處理函數(shù) - 取單詞函數(shù)(word)

取字符串 <text> 中第 <n> 個單詞。(從一開始)

$(word <n>,<text>)

示例:$(word 2, foo bar baz) 返回值是 bar

字符串處理函數(shù) - 取單詞串函數(shù)(wordlist)

  • 從字符串 <text> 中取從 <s> 開始到 <e> 的單詞串。<s> 和 <e> 是一個數(shù)字。
$(wordlist <ss>,<e>,<text>)

示例:$(wordlist 2, 3, foo bar baz) 返回值是 bar baz。

字符串處理函數(shù) - 單詞個數(shù)統(tǒng)計函數(shù)(words)

  • 統(tǒng)計 <text> 中字符串中的單詞個數(shù)。
$(words <text>)
  • 示例:$(words, foo bar baz) 返回值是 3。

字符串處理函數(shù) - 首單詞函數(shù)(firstword)

  • 取字符串 <text> 中的第一個單詞。
$(firstword <text>)
  • 示例:$(firstword foo bar) 返回值是 foo

文件名操作函數(shù)

取目錄函數(shù)(dir)

從文件名序列 <names> 中取出目錄部分。目錄部分是指最后一個反斜杠(/)之前的部分。如果沒有反斜杠,那么返回 ./。

$(dir <names...>)

$(dir src/foo.c hacks) 
#返回值是 src/ ./

取文件函數(shù)(notdir)

從文件名序列 <names> 中取出非目錄部分。非目錄部分是指最後一個反斜杠(/)之后的部分。

$(notdir <names...>)

$(notdir src/foo.c hacks)
# 返回值是 foo.c hacks

取后綴函數(shù)(suffix)

從文件名序列 <names> 中取出各個文件名的后綴

$(suffix <names...>)

$(suffix src/foo.c src-1.0/bar.c hacks)
# 返回值是 .c .c

取前綴函數(shù)(basename)

從文件名序列 <names> 中取出各個文件名的前綴部分。

$(basename <names...>)

$(basename src/foo.c src-1.0/bar.c hacks) 
# 返回值是 src/foo src-1.0/bar hacks

加后綴函數(shù)(addsuffix)

把后綴 <suffix> 加到 <names> 中的每個單詞后面

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

$(addsuffix .c,foo bar)
# 返回值是 foo.c bar.c 

加前綴函數(shù)(addprefix)

把前綴 <prefix> 加到 <names> 中的每個單詞前面。

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

$(addprefix src/,foo bar)
# 返回值是 src/foo src/bar 。

連接函數(shù)(join)

把 <list2> 中的單詞對應(yīng)地加到 <list1> 的單詞后面。

$(join <list1>,<list2>)

$(join aaa bbb , 111 222 333)
# 返回值是 aaa111 bbb222 333 。

其它函數(shù)

foreach 函數(shù)

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

# $(name) 中的單詞會被挨個取出,并存到變量 n 中,
# $(n).o 每次根據(jù) $(n) 計算出一個值,這些值以空格分隔,最后作為 foreach 函數(shù)的返回
names := a b c d
files := $(foreach n,$(names),$(n).o)
run:
	echo $(files)

if 函數(shù)

與之前的條件語句——ifeq 類似

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

call 函數(shù)

call 函數(shù)是唯一一個可以用來創(chuàng)建新的參數(shù)化的函數(shù)。

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

reverse =  $(2) $(1)

foo = $(call reverse,a,b)

run:
	echo $(foo)
# b a

shell 函數(shù)

使用操作系統(tǒng) Shell 的命令

contents := $(shell cat foo)
files := $(shell echo *.c)

控制 make 的函數(shù)

$(error <text ...>)
# and
$(warning <text ...>)

origin 函數(shù)

$(origin <variable>)

origin 函數(shù)用于告訴這個變量的從何而來

:-:-
undefined如果 <variable> 未定義,返回 undefined
default如果 <variable> 是默認(rèn)的,如 CC
environment如果 <variable> 是環(huán)境變量,并且當(dāng) Makefile 執(zhí)行時,-e 參數(shù)沒有被打開
file如果 <variable> 這個變量被定義在 Makefile 中。
command line如果 <variable> 這個變量是被命令行定義的。
override如果 <variable> 是被 override 指示符重新定義的。
automatic如果 <variable> 是一個命令運行中的自動化變量