Linux之Makefile


Makefile文件的作用是指導make程序該如何工作。

 

make的工作原理

當我們只輸入make命令的工作流程是:
1. make會在當前目錄下找名字叫“Makefile”或“makefile”的文件;
2. 如果找到,它會找文件中的第一個目標文件(target),在上面的例子中,他會找到“main”這個文件,並把這個文件作為最終的目標文件;
3. 如果main文件不存在,或是main所依賴的后面的 .o 文件的文件修改時間要比main這個文件新,那么,make會執行下面定義的命令來生成main文件;
4. 如果main所依賴的.o文件也存在,那么make會在當前文件中找目標為.o文件的依賴性,如果找到再根據命令生成.o文件(這是一個遞歸的過程);


如果在找尋的過程中,出現了被依賴的文件找不到的錯誤,那么make就會直接退出,並報錯。

如果在一條依賴鏈中,比如:A依賴B,B依賴C,C依賴D。那么當D更新后,make發現D比C新則會重新構建C,以此類推,最終A也會被更新。

 

Makefile文件的語法組成

基本的結構形式:

1 target: prerequisites
2     command
3     command
4     ...

說明:
target:可以是任何類型的文件,也可以是一個標簽(Label),或叫作“偽目標”,這個我們一會兒再講。
prerequisites:就是要生成target所需要的文件、目標。
command:當prerequisites比target要新,就會執行這里定義的動作(任意的Shell命令)


其實就是一個文件的依賴關系處理,也就是說,target目標依賴於prerequisites中的文件,其生成規則定義在command中。說白一點就是說,prerequisites中如果有任何一個及以上的文件比target文件要新的話,command所定義的命令就會被執行。這就是Makefile的規則。也是Makefile中最核心的內容。

 

Makefile中使用變量

我們通過腳本實驗來了解定義變量的幾種形式:

 1 .PHONY: target
 2 
 3 VAR_0:=$(VAR)
 4 VAR_1=$(VAR)
 5 VAR="hello world"
 6 VAR2:=$(VAR)
 7 VAR="hello world2"
 8 VAR3="hello world3"
 9 VAR3?=$(VAR)
10 VAR_0+="abc"
11 VAR_1+="abc"
12 
13 target:
14     @echo $(VAR_0)
15     @echo $(VAR_1)
16     @echo $(VAR)
17     @echo $(VAR2)
18     @echo $(VAR3)

$ make
abc
hello world2 abc
hello world2
hello world
hello world3

=   直接賦值,比較直觀。值得說的是當賦值的是變量時,如果引用的變量不存在,那么賦值的是空字符串。
:=  延遲引用變量,也就是說只有當腳本中使用到VAR2變量時,make才會去找被引用的VAR變量的值。
?= 條件賦值,被稱為條件賦值是因為:只有此變量在之前沒有被賦值的情況下才會對這個變量進行賦值。
+= 追加賦值,上面的例子的輸出很明顯了。

Makefile中也可以直接使用shell進程的環境變量,比如可以在Makefile中輸出@echo $(PATH)等等。

make自動推導
首先讓我在本地創建幾個文件:

$ vim lib1.h

1 #ifndef __LIB1_H__
2 #define __LIB1_H__
3 void lib1();
4 #endif

$ vim lib1.c

1 #include <stdio.h>
2 void lib1()
3 {
4     printf("this is lib1\n");
5 }

$ vim lib2.h

1 #ifndef __LIB2_H__
2 #define __LIB2_H__
3 void lib2();
4 #endif

$ vim lib2.c

1 #include <stdio.h>
2 void lib2()
3 {
4     printf("this is lib2\n");
5 }

$ vim main.c

1 #include "lib1.h"
2 #include "lib2.h"
3 
4 int main(int argc, char *argv[]) {
5     lib1();
6     lib2();
7     return 0;
8 }

$ vim Makefile

 1 .PHONY: clean
 2 
 3 CC=gcc
 4 CFLAGS=-O3
 5 OBJS=main.o lib1.o lib2.o
 6 LIB=libtest.a
 7 BIN=main
 8 
 9 $(BIN): $(LIB) $(BIN).o 
10     $(CC) $(CFLAGS) -o $@ $(BIN).o -L. -Wl,-Bstatic -ltest  -Wl,-Bdynamic
11     echo $?
12 
13 %.o: %.c 
14     $(CC) -c -o $*.o $*.c
15 
16 $(LIB): lib1.o lib2.o
17     ar crv $@ $^
18 
19 clean:
20     rm -rf $(BIN)
21     rm -rf $(OBJS)
22     rm -rf $(LIB)

$ make

大家可以自行改動代碼進行測試!

說一下.PHONY的作用,.PHONY后面寫的是偽目標,也就是說這種目標只是占用一個符號一個名字而已,無論當前目錄下是否有clean文件,不會對比是否最新,只要執行make clean,clean目標下面定義的命令永遠都會執行!


$@:表示目標文件名稱
$<:prerequisites依賴列表中的第一個依賴的名字
$?:所有比目標新的依賴文件名稱的集合,以空格分隔
$^:當前目標中依賴的所有文件,它並不關心這些文件是不是比目標文件新。然而,重復的依賴文件名會被移除。這會在你需要將所有的依賴文件輸出到屏幕時變得非常有用
$+:很像$^,也是所有依賴文件的集合,但是它不去除重復的依賴
$*:匹配目標模式中“%”之前的部分


好方法和技巧:
1. 引入外部Makefile
2. 變量值替換
從一個已有的宏創建一個新宏並非不可能。例如宏SRC代表一系列的源文件,你希望生成一個對應的目標文件宏OBJ。要這樣做,你只需要指定OBJ = SRC,除了擴展名不同以外:OBJ = $(SRC:.c=.o)


陷阱:
1. 環境變量 MAKEFILES
2. 萬能通配符的陷阱
3. 環境變量 VPATH

 

本文會繼續不斷打磨、完善!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM