makefile教程1
一 初識Makefile
make是一種用于項目編譯的應(yīng)用程序,本質(zhì)是一種腳本。而Makefile則是對make腳本的規(guī)則描述。僅僅是寫腳本編譯項目的話shell腳本也是可以做的,用make的原因在于,make可以解析源文件之間的依賴,根據(jù)依賴關(guān)系自動維護(hù)編譯工作。執(zhí)行宿主操作系統(tǒng)中的各種命令。
Makefile是一個描述文件,定義一系列的規(guī)則來指定源文件之間的調(diào)用先后順序。有自己特定的語法規(guī)則,可以定義函數(shù)及函數(shù)調(diào)用??梢约筛鞣N系統(tǒng)命令。Makefile用于指導(dǎo)make程序如何完成工作。
echo "hello world!"
-
1
-
2
對于文件名,可以叫Makefile或makefile,也可以自定義名稱。對于是否自定義Makefile文件名的區(qū)別在于使用方式不同。
-
1
-
1
-
1
-
1
makefile建立
通過實現(xiàn)一個加減乘除方法作為例子,文件結(jié)構(gòu)如圖所示
最簡單的makefile
-
app:add.c jian.c cheng.c chu.c main.c
-
gcc add.c jian.c cheng.c chu.c main.c -I../include -o app
makefile進(jìn)階
-
app:add.o jian.o cheng.o chu.o main.o
-
gcc add.o jian.o cheng.o chu.o main.o -o app
-
add.o:add.c
-
gcc -c add.c -I../include
-
jian.o:jian.c
-
gcc -c jian.c -I../include
-
cheng.o:cheng.c
-
gcc -c cheng.c -I../include
-
chu.o:chu.c
-
gcc -c chu.c -I../include
-
main.o:main.c
-
gcc -c main.c -I../include
makefile優(yōu)化
(1)常用的變量名(約定俗成的):
CC:表示c編譯器版本
(2)一些特殊字符
$(變量):對變量取值
(3)特殊變量
用于當(dāng)前目標(biāo):
(4)makefile內(nèi)置函數(shù)
wildcard:按照指定格式獲取當(dāng)前目錄下的所有文件名
代碼
-
.PHONY:clean #偽目標(biāo)
-
CC=gcc
-
INCLUDE=-I../include
-
CFLAGS=-c -g -Wall $(INCLUDE) #-g增加調(diào)試信息 -Wall嚴(yán)格編譯
-
CPPFLAGS=-E -D #-E頭文件展開 -D編譯時定義宏
-
CXX=g
-
LDFLAGS=-L../lib -lpthread #這只是個例子,并沒用到該庫。-l庫名
-
TARGET=app
-
RM=rm -rf
-
-
SRCFILE=$(wildcard *.c)
-
DEFFILE=$(patsubst %.c,%.o,$(SRCFILE))
-
-
$(TARGET):$(DEFFILE)
-
$(CC) $^ -o $(TARGET)
-
%.o:%.c
-
$(CC) $(CFLAGS) $<
-
-
clean:
-
-$(RM) $(TARGET) $(DEFFILE)
-
install:
-
sudo cp $(TARGET) /usr/bin
-
uninstall:
-
sudo $(RM) /usr/bin/$(TARGET)
二、Makefile基本結(jié)構(gòu)與依賴
Makefile由一個個規(guī)則組成,一個規(guī)則的結(jié)構(gòu)大致如下:
commands
#include
void func()
{
printf("hello world!\n");
}
-
main.c文件
extern void func();
int main()
{
func();
return 0;
}
Makefile文件:
gcc main.o func.o -o main
gcc -o main.o -c main.c
func.o : func.c
gcc -o func.o -c func.c
目標(biāo)依賴規(guī)則:
-
當(dāng)目標(biāo)不存在時,執(zhí)行對應(yīng)命令。
-
當(dāng)依賴在時間上比目標(biāo)更新時,執(zhí)行對應(yīng)命令。
-
當(dāng)依賴關(guān)系連續(xù)存在時,要依次向上回溯每個目標(biāo)。
如果目標(biāo)存在,但依賴項比目標(biāo)時間要新,則也要向上檢查,生成目標(biāo)。
三 偽目標(biāo)的引入
Makefile中的目標(biāo)指什么?
-
Makefile中目標(biāo)一般對應(yīng)著一個文件
-
make比較目標(biāo)文件和依賴之間的新舊關(guān)系,如果依賴新則執(zhí)行命令
-
make以文件處理作為第一優(yōu)先級
-
CC := gcc
-
TAGRET := hello.out
-
-
$(TARGET): func.o main.o
-
$(CC) -o $(TARGET) func.O
上述Makefile中第一二行依次定義了變量CC、TARGET,第四五行引用了這兩個變量,引用變量采用"變量名或者{變量名}"的形式。
Makefile中的變量只能是字符串類型。
Makefile中變量有四種賦值方式:
1,簡單賦值( := ) 編程語言中常規(guī)理解的賦值方式,只對當(dāng)前語句的變量有效
2,遞歸賦值( = )賦值語句可能影響多個變量,所有目標(biāo)變量相關(guān)的其他變量都受影響
3,條件賦值( ?= )如果變量未定義,則使用符號中的值定義變量。如果該變量已經(jīng)賦值,則該賦值語句無效。
4,追加賦值( = )原變量用空格隔開的方式追加一個新值
用例子來了解一下各個賦值的差別:
簡單賦值
-
x := foo
-
y := $(x)b
-
x := new
-
-
.PHONY : test
-
test:
-
@echo "y => $(y)"
-
@echo "x => $(x)"
輸出值:
x => new
y => foob
遞歸賦值
-
x = foo
-
y = $(x)b
-
x = new
-
-
.PHONY : test
-
test:
-
@echo "y => $(y)"
-
@echo "x => $(x)"
輸出值:
y = > newb
x => new
條件賦值
-
x := foo
-
y := $(x)b
-
x ?= new
-
-
.PHONY : test
-
test:
-
@echo "y => $(y)"
-
@echo "x => $(x)"
輸出值:
y => foob
x = foo
追加賦值
-
x := foo
-
y := $(x)b
-
x = $(y)
-
-
.PHONY : test
-
test:
-
@echo "y => $(y)"
-
@echo "x => $(x)"
輸出結(jié)果:
y => foob
x => foo foob
遞歸賦值就是一個連鎖反應(yīng),只要之前與該變量直接產(chǎn)生過關(guān)聯(lián)的變量都會有影響。
條件賦值,第一次為變量賦值的時候推薦條件賦值。
五 Makefile中的變量值的替換
1.使用指定字符串替換變量中的后綴字符(串)
格式:或{var:a=b}
注意:替換表達(dá)式中不能有空格】
例:
-
src := acc bcc ccc
-
obj := $(src:cc=o)
-
test:
-
@echo "obj => $(obj)"
make test輸出結(jié)果:
ao bo co
2.變量的模式替換
使用%保留變量值中的指定字符串,替換替他字符
格式:{var:a%b=x%y}
注意:替換表達(dá)式中不能有空格
例:
-
src := a123b.c a234b.c ajkhb.c
-
obj := $(src:a%b.c=x%y)
-
test:
-
@echo "obj => $(obj)"
分析:原串 a123b.c按照a%b.c進(jìn)行模式匹配的時候a與b.c中間的123就會被%匹配到,后邊就會被保留下來,a和b.c就會被x和y取代。其他的類似。
make test執(zhí)行結(jié)果:
x123y x234y xjkhy
3.規(guī)則中的模式替換
targets:target-pattern:prereq-pattern
command1
command2
意義:通過target-pattern從targets中匹配子目標(biāo),再通過prereq-pattern從子目標(biāo)生成依賴,進(jìn)而構(gòu)成完整規(guī)則。
例:
-
objs := func.o main.o
-
$(objs): %.o : %.c
-
gcc -o $@ -c $^
分析:
上述第二行,通過%.o匹配objs中的func.o,通過func.c生成依賴,再匹配main.o生成main.c依賴。
上述第二行會被make程序解析成
-
func.o: func.c
-
gcc -o $@ -c $^
-
main.o: main.c
-
gcc -o $@ -c $^
-
4.變量的嵌套引用
一個變量名中可以包含對其他變量的引用
嵌套引用的本質(zhì)是使用一個變量表示另外一個變量
例:
-
x := y
-
y := z
-
a := $($(x))
分析: 這個很好理解,上述第三行可以解析為
a := $(y) ==> a := z
5.命令行變量
在shell中運(yùn)行make的時候,在命令行中定義變量
命令行變量可以默認(rèn)覆蓋Makefile中定義的變量。
例:
-
hm := hello makefile
-
test:
-
@echo "hm => $(hm)"
shell中執(zhí)行 make hm = cmd
執(zhí)行結(jié)果: hm => cmd
6.override關(guān)鍵字
override關(guān)鍵字用于保護(hù)Makefile中的變量不被覆蓋。
-
override var := dest
-
test:
-
@echo "var => $(var)"
shell中執(zhí)行 make hm = cmd
執(zhí)行結(jié)果: var =>dest
這個類似于C 中的const關(guān)鍵字
7.define關(guān)鍵字
define關(guān)鍵字用于在Makefile中定義多行變量
變量定義從變量名開始到endef結(jié)束
define定義的變量等價于使用 = 定義的變量(遞歸賦值)
例:
-
define ade
-
Jack!
-
Tom!
-
endef
可以加上override 修飾
-
over define cmd
-
@echo "Run cmd ls..."
-
@ls
-
endif