Linux自動(dòng)化構(gòu)建工具-make/Make?le使用解讀
Make/Makefile完全指南
一、引言
在軟件開發(fā)的世界里,構(gòu)建項(xiàng)目是一項(xiàng)重復(fù)且繁瑣的工作。
尤其是對(duì)于大型項(xiàng)目,編譯源文件、鏈接庫、生成可執(zhí)行文件等操作可能涉及成百上千個(gè)文件,手動(dòng)管理這些過程幾乎是不可能的。
這時(shí),自動(dòng)化構(gòu)建工具就顯得尤為重要。
二、Make/Makefile 基礎(chǔ)概念
1. 什么是 Make?
Make 是一個(gè)自動(dòng)化構(gòu)建工具,它根據(jù) Makefile 中定義的規(guī)則來編譯和鏈接程序。
Make 的核心思想是:只重新構(gòu)建那些發(fā)生了變化的文件,從而大大提高構(gòu)建效率。
2. 什么是 Makefile?
Makefile 是一個(gè)文本文件,包含了一系列規(guī)則,告訴 Make 如何構(gòu)建你的項(xiàng)目。
一個(gè)簡單的 Makefile 可能包含源文件、目標(biāo)文件、依賴關(guān)系以及構(gòu)建命令等信息。
3. 為什么需要 Make/Makefile?
- 提高效率:自動(dòng)檢測文件變化,只重新編譯必要的文件。
- 簡化流程:將復(fù)雜的構(gòu)建過程抽象為簡單的命令。
- 便于維護(hù):項(xiàng)目結(jié)構(gòu)和構(gòu)建規(guī)則清晰明了。
三、Makefile 基本語法
1. 規(guī)則的基本格式
Makefile 由一系列規(guī)則組成,每個(gè)規(guī)則的基本格式如下:
target: dependencies
command1
command2
...
- target:目標(biāo)文件或操作名稱。
- dependencies:目標(biāo)文件所依賴的文件或目標(biāo)。
- command:構(gòu)建目標(biāo)所需執(zhí)行的命令(必須以 Tab 鍵開頭)。
2. 簡單示例
下面是一個(gè)簡單的 Makefile 示例,用于編譯一個(gè) C 程序:
hello: hello.c
gcc -o hello hello.c
這個(gè) Makefile 定義了一個(gè)規(guī)則:目標(biāo)是生成可執(zhí)行文件 hello,它依賴于 hello.c 文件,構(gòu)建命令是使用 gcc 編譯 hello.c。
3. 變量的使用
在 Makefile 中,可以使用變量來簡化代碼。例如:
CC = gcc
CFLAGS = -Wall -g
hello: hello.c
$(CC) $(CFLAGS) -o hello hello.c
這里定義了兩個(gè)變量:CC 表示編譯器,CFLAGS 表示編譯選項(xiàng)。使用 $(變量名) 來引用變量。
4. 自動(dòng)變量
Make 提供了一些自動(dòng)變量,用于簡化規(guī)則的編寫:
$@:表示當(dāng)前目標(biāo)。$<:表示第一個(gè)依賴文件。$^:表示所有依賴文件。
使用自動(dòng)變量,上面的示例可以改寫為:
CC = gcc
CFLAGS = -Wall -g
hello: hello.c
$(CC) $(CFLAGS) -o $@ $<
四、Makefile 高級(jí)特性
1. 模式規(guī)則
模式規(guī)則允許定義通用的編譯規(guī)則,適用于一類文件。例如:
CC = gcc
CFLAGS = -Wall -g
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
這個(gè)規(guī)則表示如何從 .c 文件生成 .o 文件,適用于所有的 C 源文件。
2. 靜態(tài)模式規(guī)則
靜態(tài)模式規(guī)則用于為一組目標(biāo)定義相同的構(gòu)建規(guī)則。例如:
objects = foo.o bar.o baz.o
$(objects): %.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
這個(gè)規(guī)則表示如何從對(duì)應(yīng)的 .c 文件生成 foo.o、bar.o 和 baz.o。
3. 函數(shù)的使用
Makefile 提供了一些內(nèi)置函數(shù),用于處理文件列表、字符串等。例如:
SRCS = $(wildcard *.c) OBJS = $(patsubst %.c,%.o,$(SRCS)) all: $(OBJS)
wildcard函數(shù)用于獲取所有匹配的文件列表。patsubst函數(shù)用于模式替換。
4. 偽目標(biāo)
偽目標(biāo)所修飾的依賴關(guān)系,即使在執(zhí)行過一次后,仍然會(huì)被強(qiáng)制執(zhí)行。
偽目標(biāo)不是真正的文件名,而是一種執(zhí)行命令的方式。例如:
.PHONY: clean
clean:
rm -f *.o hello
.PHONY 聲明 clean 為偽目標(biāo),這樣即使當(dāng)前目錄下存在名為 clean 的文件,Make 也會(huì)執(zhí)行對(duì)應(yīng)的命令。
偽目標(biāo)詳細(xì)說明
stat
在說偽目標(biāo)之前,就要談到stat這個(gè)指令,stat 命令用于顯示文件或文件系統(tǒng)的詳細(xì)信息,包括文件類型、權(quán)限、時(shí)間戳、inode 信息等。
時(shí)間戳的區(qū)別:
stat 輸出中包含三種時(shí)間戳:
- Access (atime):文件最后被訪問的時(shí)間(如 cat、less 命令讀取文件)。一般來說,為了提高效率,會(huì)在執(zhí)行幾次modify 和 change 后 access 才會(huì)改變。
- Modify (mtime):文件內(nèi)容最后被修改的時(shí)間(如 vim 編輯文件后保存)。修改文件內(nèi)容時(shí)間
- Change (ctime):文件元數(shù)據(jù)(如權(quán)限、所有者)最后被更改的時(shí)間。修改文件屬性時(shí)間
** 在我們使用make指令時(shí),當(dāng)使用一次之后,有時(shí)會(huì)顯示不能夠再次使用,這是因?yàn)橹挥性谠次募罱男薷臅r(shí)間比可執(zhí)行文件要老時(shí),才能夠執(zhí)行 **
只需要比較可執(zhí)行程序最近的修改時(shí)間和源文件最近的修改時(shí)間(使用時(shí)間戳比較) .exe 新于 .c 源文件,不需要重新編譯 .exe 老于 .c 源文件,需要重新編譯
所以說,為了不受修改時(shí)間對(duì)指令的影響,就引入了偽目標(biāo)這一概念。
偽目標(biāo)
在 Makefile 里,偽目標(biāo)(phony target)并非代表實(shí)際的文件,它的作用是把多個(gè)命令組織起來,達(dá)成特定的構(gòu)建目的。
當(dāng)你執(zhí)行 make 命令并帶上偽目標(biāo)名稱時(shí),Make 會(huì)直接執(zhí)行該偽目標(biāo)所關(guān)聯(lián)的命令,而不會(huì)去檢查是否存在同名文件,也不會(huì)考慮文件的更新時(shí)間。
偽目標(biāo)的關(guān)鍵特性
- 不對(duì)應(yīng)實(shí)際文件:偽目標(biāo)的名稱在文件系統(tǒng)中找不到對(duì)應(yīng)的文件。
- 強(qiáng)制執(zhí)行命令:不管文件是否有更新,Make 都會(huì)執(zhí)行偽目標(biāo)的命令。
- 避免命名沖突:要是目錄中存在和目標(biāo)同名的文件,使用偽目標(biāo)就能防止規(guī)則被錯(cuò)誤觸發(fā)。
為什么需要 .PHONY 聲明?
在 Makefile 中,使用 .PHONY 來聲明偽目標(biāo)是很有必要的。如果不這樣做,當(dāng)目錄中存在與目標(biāo)同名的文件時(shí),Make 可能會(huì)認(rèn)為目標(biāo)已經(jīng)是最新的,從而不會(huì)執(zhí)行相應(yīng)的命令。
例如,要是沒有 .PHONY 聲明:
makefile
clean:
rm -f *.o
當(dāng)目錄中存在名為 clean 的文件時(shí),執(zhí)行 make clean 命令不會(huì)刪除任何 .o 文件,因?yàn)?Make 覺得目標(biāo) clean 已經(jīng)是最新狀態(tài)了。
而加上 .PHONY 聲明后:
makefile
.PHONY: clean
clean:
rm -f *.o
無論是否存在 clean 文件,Make 都會(huì)執(zhí)行 rm -f *.o 命令。
五、Makefile 實(shí)戰(zhàn)技巧
1. 調(diào)試技巧
- 使用
make -n查看將要執(zhí)行的命令,但不實(shí)際執(zhí)行。 - 使用
make -d顯示詳細(xì)的調(diào)試信息。 - 在命令前加
@可以不顯示該命令本身,只顯示結(jié)果。 - make會(huì)一層又一層地去找文件的依賴關(guān)系,直到最終編譯出第一個(gè)目標(biāo)文件。在找尋的過程中,如果出現(xiàn)錯(cuò)誤,比如最后被依賴的文件找不到,那么make就會(huì)直接退出,并報(bào)錯(cuò),而對(duì)于所定義的命令的錯(cuò)誤,或是編譯不成功,make根本不理。make只管文件的依賴性,即,如果在我找了依賴關(guān)系之后,冒號(hào)后面的文件還是不在,就不會(huì)工作了。
- 單獨(dú)使用make指令時(shí),會(huì)自動(dòng)執(zhí)行makefile文件的第一條依賴關(guān)系。
2. 并行構(gòu)建
使用 make -jN 可以并行執(zhí)行 N 個(gè)任務(wù),加快構(gòu)建速度。例如:
make -j4 # 并行執(zhí)行 4 個(gè)任務(wù)
3. 條件編譯
可以在 Makefile 中使用條件語句,根據(jù)不同的條件執(zhí)行不同的命令。例如:
ifeq ($(DEBUG), 1) CFLAGS += -DDEBUG -g endif
總結(jié)
Make/Makefile 是 Linux 系統(tǒng)中強(qiáng)大的自動(dòng)化構(gòu)建工具,通過合理使用 Makefile 的各種特性,可以高效地管理復(fù)雜項(xiàng)目的構(gòu)建過程。
本文介紹了 Make/Makefile 的基礎(chǔ)知識(shí)、語法、高級(jí)特性以及在大型項(xiàng)目中的組織方法和實(shí)戰(zhàn)技巧。掌握這些內(nèi)容后,你將能夠編寫高效、靈活的 Makefile,提高軟件開發(fā)效率。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Ubuntu 16.04安裝Apache Tomcat的方法
Apache Tomcat是Java Servlet和Java Server Pages技術(shù)的開源軟件實(shí)現(xiàn)。可以使用OpenJDK tomcat運(yùn)行你的Java應(yīng)用。Apache Tomcat安裝方法大家都不是很清楚,下面小編給大家介紹下Ubuntu 16.04安裝Apache Tomcat的方法2016-10-10
Linux(Ubuntu)系統(tǒng)上傳項(xiàng)目到GitHub新建倉庫過程
該文主要講述了如何創(chuàng)建SSHkeys,設(shè)置本地git的用戶名和郵箱,連接GitHub賬號(hào),上傳項(xiàng)目到GitHub上等整個(gè)過程,具體步驟包括:創(chuàng)建SSHkeys、設(shè)置本地git信息、連接GitHub賬號(hào)、創(chuàng)建GitHub倉庫、上傳項(xiàng)目等2026-03-03
教你一招實(shí)現(xiàn)Linux中的文本比對(duì)
這篇文章主要給阿加介紹了關(guān)于Linux下文本比對(duì)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-11-11
CentOS上搭建Nginx+Mono運(yùn)行asp.net環(huán)境的配置方法
這篇文章主要介紹了CentOS上搭建Nginx+Mono運(yùn)行asp.net環(huán)境的配置方法,需要的朋友可以參考下2017-03-03
Linux上兩種網(wǎng)絡(luò)連接實(shí)現(xiàn)方式
這篇文章主要介紹了Linux上兩種網(wǎng)絡(luò)連接實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09
Linux下實(shí)現(xiàn)不活動(dòng)用戶登錄超時(shí)后自動(dòng)登出
這篇文章主要介紹了Linux下實(shí)現(xiàn)不活動(dòng)用戶登錄超時(shí)后自動(dòng)登出 ,本文給大家?guī)砹怂姆N方式,每種方式都通過實(shí)例代碼文字給大家介紹的非常詳細(xì),需要的朋友可以參考下2019-08-08
Apache添加多端口及實(shí)現(xiàn)單ip多端口映射的方法
這篇文章主要介紹了Apache添加多端口及實(shí)現(xiàn)單ip多端口映射的方法的相關(guān)資料,需要的朋友可以參考下2016-02-02

