makefile 入門基礎(chǔ)知識

一.makefile格式

1.makefile 文件一般命名 為makefile 即可送淆,放在目錄下面税产,直接調(diào)出 terminal ,輸入make 即會執(zhí)行makefile文件的第一個命令,如果需要執(zhí)行制定的命令xxx可以 make xxx.
2.makefile 文件的基本語法:

1.目標

<target>:<prerequisites>
<table><commands>
解釋:target 部分叫目標辟拷,也就是make 執(zhí)行的xxx撞羽;prerequisties 叫著前置條件;第二行必須用table鍵起衫冻,緊接著是具體的執(zhí)行命令诀紊。target 是必須的;prequisites隅俘,和command是可選的邻奠,但是兩者必須有一個。每條指令的意思
例如:

new:
    touch a.txt
2.偽目標

如果在當前目錄下已經(jīng)存在 文件,并且文件名(new)和目標(new)是一致的時候,使用make new命令時,并不會執(zhí)行指令.例如下面的輸出,顯示new 已經(jīng)是最新的,并不執(zhí)行new的指令.


輸出結(jié)果.png

為了避免對已經(jīng)存在和目標相同的文件,而不執(zhí)行目標的情況,有一種叫"偽目標"的語法出現(xiàn)了.寫法如下

.PHONY: new
new:
    touch new

這樣每次執(zhí)行make new ,都會執(zhí)行.如下:


偽目標結(jié)果.png
3.前置條件

前置條件通常是一組文件名为居,以空格分開碌宴。他指定目標是否需要重新構(gòu)建的標準.
1.前置條件如果是空,則每次都會觸發(fā);
2.有一個或者多個前置條件的,只需要有一個前置條件不存在,或者有更新過(通常根據(jù)lastmodification的時間戳比目標的時間戳新)蒙畴,目標就會重新構(gòu)建唧喉。
例如:

result.txt:a.txt
    cp a.txt result.txt 
a.txt:
    echo "這是A" > a.txt

開始時候,沒有創(chuàng)建任何文件忍抽,輸出一下內(nèi)容:

/media/leonzhu/document/工作文檔/makefile$ make
echo "這是A" > a.txt
cp a.txt result.txt 

修改下makefile的 內(nèi)容八孝,連續(xù)再次執(zhí)行make 指令,由于a.txt 沒有任何改動鸠项,所以這次目標不會執(zhí)行

result.txt:a.txt
    cp a.txt result.txt 
a.txt:
    echo "這是B" > a.txt

輸出結(jié)果:

/media/leonzhu/document/工作文檔/makefile$ make
make: 'result.txt' is up to date.

查看result.txt 文件干跛,可知里面的內(nèi)容并沒有改變成B.


image.png
4.命令

命令默認是用table鍵開頭,緊接著由一行或多行的Shell命令組成命令.

  • 如果不想用table開頭怎么辦?
  • 如果需要執(zhí)行多個命令怎么辦?
  • 如果需要使用上條命令的值怎么辦?

1.考慮到用table鍵開頭,空格可能不習(xí)慣.可以采用

.RECIPEPREFIX = >
all:
>touch all

這里的 > 指的是自己想代替table鍵的字符,理論上可以采用單個任意的非定義的特殊字符.例如"<",")"等等.

2.執(zhí)行多條命令:

.RECIPEPREFIX =>
.PHONY:all
all:
>touch all
>echo "ddasfaafdsa" > all

先創(chuàng)建 all 文件,再往文件里面寫入一些字符串"ddasfaafdsa".
需要注意的是,每一行的命令都是在單獨的shell中執(zhí)行,這些命令之間沒有繼承關(guān)系.
3.獲取前條指令的值的方法,有三種:

  • 1 把多條命令寫在一行中,用分號(;)隔開
var-kept:
    export foo="foood";echo "foo=[$$foo]";export foo2=$$foo"dd";echo "foo2=[$$foo2]"

輸出結(jié)果:


;輸出結(jié)果.png
  • 2 用連接符[;\],下條指令按正常格式換行.
var-kept:
    export foo="foood";\
    echo "foo=[$$foo]";\
    export foo2=$$foo"dd";\
    echo "foo2=[$$foo2]"

輸出結(jié)果:


;\連接符結(jié)果
  • 3 使用 .ONESHELL:
.ONESHELL:
var-kept:
    export foo="foood"
    echo "foo=[$$foo]"
    export foo2=$$foo"dd"
    echo "foo2=[$$foo2]"

輸出結(jié)果:


.ONESHELL:結(jié)果

二.makefile 文件語法

2.1 注釋

注釋用# 表示.

2.2 回聲

正常情況下,makefile會在控制臺打印每一條命令,這叫回聲.在第一行命令前增加 @ 符號,就可以關(guān)閉回聲,這樣就不會打印命令.
回聲:

.ONESHELL:
var-kept:
    # 這是注釋
    export foo="foood"
    echo "foo=[$$foo]"
    export foo2=$$foo"dd"
    echo "foo2=[$$foo2]"

輸出結(jié)果:


回聲輸出結(jié)果

沒錯,最后的輸出結(jié)果把所有的命令都輸出了,甚至是注釋文件都出來了.

關(guān)閉回聲的做法

.ONESHELL:
var-kept:
    @# 這是注釋
    export foo="foood"
    echo "foo=[$$foo]"
    export foo2=$$foo"dd"
    echo "foo2=[$$foo2]"
關(guān)閉回聲結(jié)果

2.3 通配符

通配符(wildcard)用來指定一組符合條件的文件名。Makefile 的通配符與 Bash 一致祟绊,主要有星號(*)楼入、問號(?)和 [...] 牧抽。比如嘉熊, *.o 表示所有后綴名為o的文件。

clean:
        rm -f *.o

2.4 模式匹配

makefile可以用% 來匹配makefile 文件中的目標.%表示任何非空字符串. % 和通配符中的* 的區(qū)別在于他們使用的作用域不一樣:* 指的運用在系統(tǒng)中,而%運用在makefile文件中.
例如:對于模式規(guī)則“%.o : %.c”扬舒,它表示的含義是:所有的.o文件依賴于對應(yīng)的.c文件阐肤。我們可以使用模式規(guī)則來定義隱含規(guī)則。

2.5 變量和賦值

定義變量通常只需要寫變量名=xxx,在后面的調(diào)用中用$(變量) 即可.

#變量
testvar=你好嗎?
printvar:
    @echo $(testvar)

如果使用shell變量,需要$$,因為makefile 在執(zhí)行shell變量的時候會對$轉(zhuǎn)義如下

VAR=3   
target: 
    echo $(VAR)      #(1)
    VAR=4             #(2)
    echo $(VAR)       # (3)
    echo $$VAR        # (4)

有時,一個變量可以指向另一個變量:

var1=$(var2)

這里會帶來一個問題var1的值是在定義的時候擴展(靜態(tài)擴展)還是在運行時擴展(動態(tài)擴展).不同的時候擴展結(jié)果會不一樣.
為了解決類似問題讲坎,Makefile一共提供了四個賦值運算符 (=孕惜、:=、晨炕?=衫画、+=),它們的區(qū)別請看

VARIABLE = value
# 在執(zhí)行時擴展瓮栗,允許遞歸擴展削罩。

VARIABLE := value
# 在定義時擴展瞄勾。

VARIABLE ?= value
# 只有在該變量為空時才設(shè)置值。

VARIABLE += value
# 將值追加到變量的尾端弥激。

1> 遞歸展開變量(=):用=或define關(guān)鍵字都可以定義這種變量丰榴,如果變量的定義引用了其它的變量,那么引用會一直展開下去秆撮,直到找到被引用的變量的最新的定義,并以此作為改變量的值返回换况。

var = I love
variable = linux
var += $(variable)
variable = magic
variable = last
allvar:
    echo $(var)

這里首先賦值variable=linux,然后var 引用了variable,最后variable=last,由于引用,最后輸出l love last


=引用結(jié)果

2>簡單擴展變量(:=) 用這種方式定義的變量,會在定義處按照變量擴展開,值不會在后面隨著變量的賦值而變化.

m = mm 
x = $(m) 
y := $(x) bar 
m=xx
x = later 
simpleEqual:;echo $(x) $(y)

由于y變量采用簡單擴展,所以y的值為mm bar,如果后面對y引用的變量值進行改變都不會對y值有影響.例如改變m的值(xx),改變x的值(later) 對后面的$(y)一直是 mm bar.
輸出結(jié)果為


簡單擴展變量結(jié)果

3>可以通過+=為已定義的變量添加新的值
當變量從前沒有被定義過职辨, +=和=是一樣的,它定義一個遞歸展開的變量戈二,但是舒裤,當變量已經(jīng)有定義的時候,+=只是簡單
的進行字符的添加工作觉吭。
如果起初你用:=定義變量腾供,那么+=只是利用變量的當前值進行添加
如果起初用=定義變量,+=的行為就變得有些古怪鲜滩,它并不會在使用+=的地方馬上進行變量展開伴鳖,而是會把展開工作推后,
直到它找到最后變量的定義徙硅,這和=定義變量的行為是類似的

:=情況

m = mm 
x := $(m) 
y = $(x) bar 
m=mm2
y+=y later
simpleEqual:;echo $(x) $(y)
:=圖

=的情況

m = mm 
x = $(m) 
y = $(x) bar 
m=mm2
y+=y later
simpleEqual:;echo $(x) $(y)
=的情況

4> ?=
賦默認值榜聂,如果沒有初始化該變量,就給它賦上默認值嗓蘑。如果已經(jīng)賦值了便不會起作用.

# ?=測試
ARCH=arm
ARCH ?= i386
questionEqual:;echo $(ARCH)
2018-03-24 21-40-13 的屏幕截圖.png

2.6 內(nèi)置變量(Implicit Variables)

在隱含規(guī)則中的命令中须肆,基本上都是使用了一些預(yù)先設(shè)置的變量。你可以在你的makefile中改變這些變量的值桩皿,或是在make的命令行中傳入這些值豌汇,或是在你的環(huán)境變量中設(shè)置這些值,無論怎么樣泄隔,只要設(shè)置了這些特定的變量拒贱,那么其就會對隱含規(guī)則起作用。當然佛嬉,你也可以利用make的“-R”或“--no– builtin-variables”參數(shù)來取消你所定義的變量對隱含規(guī)則的作用柜思。例如,第一條隱含規(guī)則——編譯C程序的隱含規(guī)則的命令是“$(CC) –c $(CFLAGS) $(CPPFLAGS)”巷燥。Make默認的編譯命令是“cc”赡盘,如果你把變量“$(CC)”重定義成“gcc”,把變量“$(CFLAGS)”重定義成 “-g”缰揪,那么陨享,隱含規(guī)則中的命令全部會以“gcc –c -g $(CPPFLAGS)”的樣子來執(zhí)行了葱淳。

內(nèi)置變量分兩種:一種是命令相關(guān)的,例如"CC" ;
一種是參數(shù)相關(guān)的如"CPPFLAGS"
1、關(guān)于命令的變量抛姑。

AR

函數(shù)庫打包程序赞厕。默認命令是“ar”。

AS

匯編語言編譯程序定硝。默認命令是“as”皿桑。

CC

C語言編譯程序。默認命令是“cc”蔬啡。

CXX

C++語言編譯程序诲侮。默認命令是“g++”。

CO

從 RCS文件中擴展文件程序箱蟆。默認命令是“co”沟绪。

CPP

C程序的預(yù)處理器(輸出是標準輸出設(shè)備)。默認命令是“$(CC) –E”空猜。

FC

Fortran 和 Ratfor 的編譯器和預(yù)處理程序绽慈。默認命令是“f77”。

GET

從SCCS文件中擴展文件的程序辈毯。默認命令是“get”坝疼。

LEX

Lex方法分析器程序(針對于C或Ratfor)。默認命令是“l(fā)ex”谆沃。

PC

Pascal語言編譯程序移剪。默認命令是“pc”串塑。

YACC

Yacc文法分析器(針對于C程序)。默認命令是“yacc”。

YACCR

Yacc文法分析器(針對于Ratfor程序)凳怨。默認命令是“yacc –r”俺叭。

MAKEINFO

轉(zhuǎn)換Texinfo源文件(.texi)到Info文件程序链峭。默認命令是“makeinfo”赃额。

TEX

從TeX源文件創(chuàng)建TeX DVI文件的程序。默認命令是“tex”卓舵。

TEXI2DVI

從Texinfo源文件創(chuàng)建軍TeX DVI 文件的程序南用。默認命令是“texi2dvi”。

WEAVE

轉(zhuǎn)換Web到TeX的程序掏湾。默認命令是“weave”裹虫。

CWEAVE

轉(zhuǎn)換C Web 到 TeX的程序。默認命令是“cweave”融击。

TANGLE

轉(zhuǎn)換Web到Pascal語言的程序筑公。默認命令是“tangle”。

CTANGLE

轉(zhuǎn)換C Web 到 C尊浪。默認命令是“ctangle”匣屡。

RM

刪除文件命令封救。默認命令是“rm –f”。
2捣作、關(guān)于命令參數(shù)的變量

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

ARFLAGS

函數(shù)庫打包程序AR命令的參數(shù)惩坑。默認值是“rv”。

ASFLAGS

匯編語言編譯器參數(shù)也拜。(當明顯地調(diào)用“.s”或“.S”文件時)以舒。

CFLAGS

C語言編譯器參數(shù)。

CXXFLAGS

C++語言編譯器參數(shù)搪泳。

COFLAGS

RCS命令參數(shù)。

CPPFLAGS

C預(yù)處理器參數(shù)扼脐。( C 和 Fortran 編譯器也會用到)岸军。

FFLAGS

Fortran語言編譯器參數(shù)。

GFLAGS

SCCS “get”程序參數(shù)瓦侮。

LDFLAGS

鏈接器參數(shù)艰赞。(如:“l(fā)d”)

LFLAGS

Lex文法分析器參數(shù)。

PFLAGS

Pascal語言編譯器參數(shù)肚吏。

RFLAGS

Ratfor 程序的Fortran 編譯器參數(shù)方妖。

YFLAGS

Yacc文法分析器參數(shù)。

2.7自動變量(Automatic Variables)

(1)$@

指代當前目標,就是make中的當前執(zhí)行的目標.例如 make Foo,$@ 表示 Foo

# $@ 測試
touchA.txt touchB.txt:
    touch $@

2018-03-25 13-31-30 的屏幕截圖.png

(2)$<
指代第一個前置條件. 比如規(guī)則 p: a1 a2 那么$< 表示a1.
(3) $?
指代比目標更新的(時間戳比目標時間戳大)所有前置條件.
(4) $^
指代所有的前置條件,之間用空格隔開
(5)$*
指代 匹配符中$的部分.
(6)$(@D) ,$(@F)
$(@D) 指代 $@變量的目錄部分,也就是目標的目錄部分.
$(@F) 指代$@的文件部分,也就是目標的文件部分
"$(D)""$(F)"和上面所述的同理罚攀,也是取文件的目錄部分和文件部分党觅。對于上面的那個例子,"$(D)"返回"dir"斋泄,而"$(F)"返回"foo"

"$(%D)""$(%F)"分別表示了函數(shù)包文件成員的目錄部分和文件部分杯瞻。這對于形同"archive(member)"形式的目標中的"member"中包含了不同的目錄很有用。

"$(<D)" "$(<F)"分別表示依賴文件的目錄部分和文件部分炫掐。

"$(^D)" "$(^F)"分別表示所有依賴文件的目錄部分和文件部分魁莉。(無相同的)

"$(+D)" "$(+F)"分別表示所有依賴文件的目錄部分和文件部分。(可以有相同的)

"$(?D)""$(?F)"分別表示被更新的依賴文件的目錄部分和文件部分募胃。

最后想提醒一下的是旗唁,對于"$<",為了避免產(chǎn)生不必要的麻煩痹束,我們最好給$后面的那個特定字符都加上圓括號检疫,比如,"$(< )"就要比"$<"要好一些祷嘶。

dest/%: src/% 
    @[ -d dest ] || mkdir dest
    cp $< $(@D)

這段代碼的意思是把 src中的目標文件拷貝到 dest目錄下,其中目標文件 為 make dest/test.txt 中的test.txt ,因為% 作為makefile文件中的目標匹配,表示 src中的 文件名;
第三行中的 $< 表示前置的第一個元素也就是 src/%==>src/test.txt;
$(@D) 表示目標的 目錄 即dest/% 的目錄==>dest

2.8 判斷和循環(huán)

makefile中的判斷 一般采用ifxxx ... else ... endif 的形式;
條件判斷 有 ifeq ... else ...endif, ifneq ... else ... endif ,ifdef ...else ... endif,ifndef ... else ... endif

ifeq ($(CC),gcc)
  libs=$(libs_for_gcc)
else
  libs=$(normal_libs)
endif

循環(huán),
for/do/done

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

while/do/done

# while/do/done

n ?= 0
loopwhile:
    @n=$(n); \
    while [ $${n} -lt 10 ] ; do \
    echo $$n ; \
    n=`expr $$n + 1 `;\
    done; \

其中@n=$(n) 表示在定義一個命令變量n= 之前的n,所以后面用到的命令n都是這時定義的n,n=expr $$n + 1 表示一個表達式賦值給n,值為n的值+1.結(jié)果如下:

while/do/done.png
2.9 函數(shù)

makefile 使用函數(shù)的格式
${function arg1 arg2} 或者 $(function arg1 arg2)
常見的內(nèi)置函數(shù)
包括

  • 字符串處理函數(shù)
    1.字符串替換 $(subst from,to,text)
$(subst ee,EE,feet on the street)

結(jié)果 ‘fEEt on the strEEt’.
2.模式匹配替換 $(patsubst pattern,replacement,text)

$(patsubst %.c,%.o,x.c.c bar.c)

有寫簡寫
比如:$(VAR:PATTERN=REPLACEMENT)

objects = foo.o
testPatsub2:    
    test=$(objects:.o=.c)
    echo $${test}

這里面,看 demo var 變量可以傳多個 字符,但是實際測試無法使用,不清楚原因
https://www.gnu.org/software/make/manual/html_node/Text-Functions.html#Text-Functions

2018-03-25 17-16-21 的屏幕截圖.png

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末电谣,一起剝皮案震驚了整個濱河市秽梅,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌剿牺,老刑警劉巖企垦,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異晒来,居然都是意外死亡钞诡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進店門湃崩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來荧降,“玉大人,你說我怎么就攤上這事攒读《浣耄” “怎么了?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵薄扁,是天一觀的道長剪返。 經(jīng)常有香客問我,道長邓梅,這世上最難降的妖魔是什么脱盲? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮日缨,結(jié)果婚禮上钱反,老公的妹妹穿的比我還像新娘。我一直安慰自己匣距,他們只是感情好面哥,可當我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著毅待,像睡著了一般幢竹。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上恩静,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天焕毫,我揣著相機與錄音,去河邊找鬼驶乾。 笑死邑飒,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的级乐。 我是一名探鬼主播疙咸,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼风科!你這毒婦竟也來了撒轮?” 一聲冷哼從身側(cè)響起乞旦,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎题山,沒想到半個月后兰粉,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡顶瞳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年玖姑,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片慨菱。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡焰络,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出符喝,到底是詐尸還是另有隱情闪彼,我是刑警寧澤,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布协饲,位于F島的核電站畏腕,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏囱稽。R本人自食惡果不足惜郊尝,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一二跋、第九天 我趴在偏房一處隱蔽的房頂上張望战惊。 院中可真熱鬧,春花似錦扎即、人聲如沸吞获。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽各拷。三九已至,卻和暖如春闷营,著一層夾襖步出監(jiān)牢的瞬間烤黍,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工傻盟, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留速蕊,地道東北人。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓娘赴,卻偏偏與公主長得像规哲,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子诽表,可洞房花燭夜當晚...
    茶點故事閱讀 44,601評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 來自陳浩的一片老文唉锌,但絕對營養(yǎng)隅肥。 示例工程:3 個頭文件*.h,和 8 個 C 文件*.c袄简。 初 編譯過程腥放,源文件...
    周筱魯閱讀 4,696評論 0 17
  • @(linux 編程)[開發(fā)技能, 工具使用] What is GNU Make Make 是控制工程中通過源碼生...
    orientlu閱讀 11,341評論 0 26
  • makefile關(guān)系到整個工程的編譯規(guī)則,一個工程中的源文件不計其數(shù)痘番,按其類型捉片、功能、模塊分別放在若干的目錄當中汞舱,...
    Joe_HUST閱讀 1,879評論 0 3
  • 而立虛云 今天看了李笑來的《財富自由之路》伍纫,在最近的一篇文章中,笑來強調(diào)了人生的并行任務(wù)昂芜。 以給工作為例莹规,最好是在...
    通靈半藏閱讀 421評論 0 0
  • 初次聽到系統(tǒng)思維這個詞,是源于張妮老師在父母訓(xùn)公眾號的一篇文章《三個月泌神,一百人良漱,系統(tǒng)思維能帶來什么改變》。張妮老師...
    蘇州萬春蘭閱讀 400評論 0 1