自動(dòng)化構(gòu)建工具make與Makefile用法示例詳解

1. 什么是 make / Makefile?
make 是一個(gè)自動(dòng)化構(gòu)建工具,它根據(jù)一個(gè)叫做 Makefile 的文件中的規(guī)則,自動(dòng)編譯和鏈接程序。更本質(zhì)一點(diǎn)說,make是一個(gè)命令,makefile是一個(gè)文件。Makefile 定義了文件之間的依賴關(guān)系以及如何生成目標(biāo)文件。
注意:
Makefile文件名首字母可以大寫也可以小寫,但通常使用Makefile或makefile。
2. Makefile 的基本結(jié)構(gòu)
依賴關(guān)系與依賴方法
一個(gè)典型的規(guī)則如下:
target: dependencies
recipe- 第一行:
target是要生成的目標(biāo)文件,dependencies是生成該目標(biāo)所依賴的文件。 - 第二行:
recipe是生成目標(biāo)的命令(必須以 Tab 鍵開頭)。
示例:
myproc:myproc.c
gcc -o myproc myproc.c
myproc是目標(biāo)文件,依賴myproc.c。- 依賴方法:
gcc -o myproc myproc.c。
make 的執(zhí)行規(guī)則
make命令默認(rèn)掃描當(dāng)前目錄下的Makefile,并執(zhí)行 第一個(gè) 目標(biāo)。- 如果依賴文件的時(shí)間戳比目標(biāo)文件新(即內(nèi)容被修改過),則重新生成目標(biāo);否則跳過。
- 這樣設(shè)計(jì)可以避免重復(fù)編譯未修改的代碼,提高構(gòu)建效率。
3. 如何判斷文件是否被修改?
之前說過,文件=內(nèi)容+屬性
文件的三個(gè)時(shí)間戳(stat 命令)

在 Linux 中,每個(gè)文件都有三個(gè)時(shí)間戳:
| 時(shí)間戳 | 含義 |
|---|---|
| Access | 最近一次訪問時(shí)間(讀文件) |
| Modify | 最近一次內(nèi)容修改時(shí)間 |
| Change | 最近一次屬性修改時(shí)間 |
注意:
- 修改文件內(nèi)容時(shí),Modify 和 Change 都會(huì)更新(因?yàn)槲募笮〉葘傩宰兞耍?/li>
- 單獨(dú)修改屬性(如
chmod)只會(huì)更新 Change。- Access 時(shí)間不會(huì)每次都更新(為了減少磁盤 I/O),通常訪問多次后才刷新一次。
make 的判斷依據(jù)
make 只根據(jù) Modify 時(shí)間來判斷文件內(nèi)容是否發(fā)生了更改。
如果依賴文件的 Modify 時(shí)間晚于目標(biāo)文件,則重新生成。
使用 touch 修改時(shí)間
touch 命令除了可以創(chuàng)建空文件,還可以將所有時(shí)間戳更新為當(dāng)前時(shí)間:
touch filename # 將 filename 的 Access、Modify、Change 都改為當(dāng)前時(shí)間

利用這個(gè)特性,可以強(qiáng)制讓 make 認(rèn)為文件被修改過,從而總是執(zhí)行某個(gè)目標(biāo)。
touch可以統(tǒng)一更改時(shí)間到當(dāng)前時(shí)刻
為什么講這些呢?
因?yàn)檫@些是關(guān)鍵字PHONY的原理
PHONY可以使程序可以總是被執(zhí)行,下圖中的clean就是如此,原理就是通過touch修改時(shí)間
所以我們使用make clean的時(shí)候可以總是被執(zhí)行

如果改成下圖這樣,make也可以總是被執(zhí)行,但為了節(jié)省編譯時(shí)間,通常不會(huì)這樣做

4. 偽目標(biāo)(.PHONY)
為什么需要偽目標(biāo)?
有時(shí)候我們想執(zhí)行一些不生成具體文件的操作(例如 clean 刪除中間文件)。但 clean 本身不是一個(gè)真實(shí)的文件,如果恰好當(dāng)前目錄下有一個(gè)名為 clean 的文件,make clean 就會(huì)認(rèn)為目標(biāo)已經(jīng)存在且無依賴,從而跳過執(zhí)行。
使用 .PHONY 聲明偽目標(biāo)
.PHONY: clean
clean:
rm -f *.o hello.PHONY告訴 make:clean不是一個(gè)真實(shí)文件,無論是否存在,都執(zhí)行它的命令。- 偽目標(biāo)的原理本質(zhì)上是 make 強(qiáng)制把它的依賴時(shí)間視為“總是比目標(biāo)新”,從而總是執(zhí)行。
能否讓普通目標(biāo)也總是執(zhí)行?
可以,但不推薦。例如:
hello: hello.c
gcc hello.c -o hello
touch hello # 更新 hello 的時(shí)間戳,這樣下次 make 時(shí)會(huì)認(rèn)為 hello 比依賴新,從而不編譯這樣會(huì)導(dǎo)致每次 make 都重新編譯,失去了增量編譯的優(yōu)勢(shì)。因此,一般只對(duì) clean 等輔助目標(biāo)使用 .PHONY。
5. Makefile 的推導(dǎo)規(guī)則(自動(dòng)推導(dǎo))
拆分寫法(不常用,僅用于理解)
上述的命令可以拆分成下圖(一般不這樣寫,為了講解原理而拆分)
makefile會(huì)從上向下掃描,沒有就入棧,有就出棧執(zhí)行

在實(shí)際開發(fā)中,我們一般這樣寫

其中$(BIN) 和 (SRC)替換成(SRC) 替換成(SRC)替換成@和$^
$@表示目標(biāo)文件。$^表示所有依賴文件。

如果不想回顯命令,可以在前邊加上@

如果想看起來直觀一點(diǎn),可以在命令后輸出一行,指定內(nèi)容
make 會(huì)從上向下掃描,發(fā)現(xiàn)需要 hello.o,則先去執(zhí)行生成 hello.o 的規(guī)則,再返回執(zhí)行 hello 的規(guī)則。
簡化寫法(常用)
實(shí)際開發(fā)中,我們通常會(huì)使用變量和自動(dòng)化變量來簡化:
BIN = hello
SRC = hello.c
$(BIN): $(SRC)
gcc -o $@ $^
隱藏命令回顯
在命令前加 @ 可以阻止 make 輸出該命令本身:
$(BIN): $(SRC)
@gcc $^ -o $@
@echo "編譯完成"處理多個(gè)源文件

%.o: %.c是一個(gè)模式規(guī)則,表示所有.o文件都依賴對(duì)應(yīng)的.c文件。$<表示第一個(gè)依賴文件(即對(duì)應(yīng)的.c文件)。
6. Makefile 的終極形態(tài)(通用模板)
說明:
wildcard函數(shù):展開當(dāng)前目錄下所有.c文件。SRC:.c=.o是變量替換語法,將所有.c后綴替換為.o。- 這個(gè)模板可以自動(dòng)適應(yīng)任意數(shù)量的
.c文件,無需手動(dòng)列出。

SRC=$(shell ls *.c) SRC=$(wildcard *.c) #兩種方式都可以 顯示當(dāng)前目錄下的所有.c文件 OBJ=$(SRC:.c=.o) #把所有SRC內(nèi)部的.c文件替換成.o文件
總結(jié)
| 概念 | 說明 |
|---|---|
| 依賴關(guān)系 | 目標(biāo)文件依賴哪些源文件或中間文件 |
| 依賴方法 | 生成目標(biāo)的具體命令,前面必須有一個(gè) Tab 鍵 |
| 時(shí)間戳 | make 根據(jù)文件的 Modify 時(shí)間判斷是否需要重新編譯 |
| 偽目標(biāo) | 用 .PHONY 聲明,總是執(zhí)行其命令(如 clean) |
| 自動(dòng)化變量 | $@(目標(biāo))、$^(所有依賴)、$<(第一個(gè)依賴) |
| 模式規(guī)則 | %.o: %.c 表示所有 .o 依賴同名 .c |
| 函數(shù) | wildcard、shell 等用于動(dòng)態(tài)獲取文件列表 |
掌握這些內(nèi)容,你就可以編寫靈活、高效的 Makefile,實(shí)現(xiàn)項(xiàng)目的自動(dòng)化構(gòu)建。
新編譯 |
| 偽目標(biāo) | 用.PHONY聲明,總是執(zhí)行其命令(如clean) |
| 自動(dòng)化變量 |$@(目標(biāo))、$^(所有依賴)、$<(第一個(gè)依賴) |
| 模式規(guī)則 |%.o: %.c表示所有.o依賴同名.c|
| 函數(shù) |wildcard、shell等用于動(dòng)態(tài)獲取文件列表 |
掌握這些內(nèi)容,你就可以編寫靈活、高效的 Makefile,實(shí)現(xiàn)項(xiàng)目的自動(dòng)化構(gòu)建。
到此這篇關(guān)于自動(dòng)化構(gòu)建工具make與Makefile用法示例詳解的文章就介紹到這了,更多相關(guān)自動(dòng)化構(gòu)建工具make與Makefile內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python執(zhí)行Linux系統(tǒng)命令的4種方法
這篇文章主要介紹了Python執(zhí)行Linux系統(tǒng)命令的4種方法,即在Python腳本中調(diào)用Shell命令,需要的朋友可以參考下2014-10-10
Shell腳本配合iptables屏蔽來自某個(gè)國家的IP訪問
這篇文章主要介紹了Shell腳本配合iptables屏蔽來自某個(gè)國家的IP訪問,本文利用IPdeny的IP數(shù)據(jù),然后用Shell腳本導(dǎo)入iptables實(shí)現(xiàn)屏蔽IP訪問,需要的朋友可以參考下2015-04-04
Linux Shell腳本實(shí)現(xiàn)檢測(cè)tomcat
這篇文章主要介紹了Linux Shell腳本實(shí)現(xiàn)檢測(cè)tomcat的方法,推薦給小伙伴們,需要的朋友可以參考下2015-03-03

