一、導入
1、編寫文件a.c
#include <stdio.h>
int main(void)
{
func();
return 0;
}
2、編寫文件b.c
#include <stdio.h>
void func(void)
{
printf("Hello World.\n");
}
3、linux環境下執行命令:
gcc -o test a.c b.c
4、在當前目錄下會生成一個test的可執行文件,在linux環境下執行命令運行test
./test
5、分析:通過gcc -o test a.c b.c 命令行對a.c、b.c進行編譯、鏈接生成test可執行程序還是比較簡單的,這是因爲文件數量少,可以這樣用, 但是當文件數量很多時(如幾千幾萬個量級), 沒必要每次對所有文件都編譯、鏈接,可以僅對改動的文件進行編譯,生成.o文件, 然後再對所有.o文件進行鏈接生成可執行程序文件。
6、上述分析,可以藉助編寫Makefile文件來實現。
二、Makefile語法及常用功能
1、Makefile的核心——規則:
目標:依賴1 依賴2...
[TAB]命令
2、執行場景:
當“目標文件”不存在,
或
某個依賴文件比目標文件“新”,
則:執行“命令”
3、對上述a.c b.c編寫Makefile文件
1) 在與a.c、b.c同級目錄下,新建Makefile文件,編寫內容如下:
test : a.o b.o
gcc -o test a.o b.o
a.o : a.c
gcc -c -o a.o a.c
b.o : b.c
gcc -c -o b.o b.c
clean:
rm *.o test
2)linux環境下執行 make 和 make clean命令,觀察目錄內文件變化:
運行make命令後,目錄內生成test可執行程序文件,通過./test命令即可運行該程序;
運行make clean 命令, 目錄內左右 .o 和 test 文件被清除。
4、Makefile的語法
1)通配符:%.o
- $@ 表示目標
- $< 表示第一個依賴文件
- $^ 表示所有依賴文件
使用通配符修改上述Makefile文件,如下:
test: a.o b.o
gcc -o test $^
%.o : %.c
gcc -c -o $@ $<
clean:
rm *.o test
問題及分析:當前文件夾中若有同名的clean文件時,make clean命令將不會被執行,可以使用假想目標:.PHONY來解決。
2) 假想目標:.PHONY
如下:
test: a.o b.o
gcc -o test $^
%.o : %.c
gcc -c -o $@ $<
clean:
rm *.o test
.PHONY: clean
說明:添加 .PHONY: clean 後,就不會判斷名爲clean的文件是否存在,而是直接執行make clean命令。
3)即時變量、延時變量,export
簡單變量(即使變量):
A := xxx # A的值即可確定,在定義時即確定
B = xxx # B的值使用到時才確定
:= # 即時變量
= # 延時變量
?= # 延時變量,如果是第一次定義才起效果,如果在前面該變量已定義則忽略該句
+= # 附加, 它是即時變量還是延時變量取決於前面的定義
三、Makefile語法及常用功能
a. $(foreach var, list, text)
b. $(filter pattern..., text) #在text中取出符合pattern格式的值
$(filter-out pattern..., text) #在text中取出不符合pattern格式的值
c. $(wildcard pattern) #pattern定義了文件名的格式,
#wildcard取出其中存在的文件
d. $(patsubst pattern, replacement, $(var)) #從列表中取出每一個值,
#如果符合pattern
#則替換爲replacement
四、Makefile實例
1、改進:支持頭文件依賴
(詳細介紹可以參考這篇博客: http://blog.csdn.net/qq1452008/article/details/50855810)
gcc -M c.c //打印出依賴
gcc -M -MF c.d c.c //把依賴寫入文件c.d
gcc -c -o c.o c.c -MD -MF c.d //編譯c.o, 把依賴寫入文件c.d
自動添加依賴文件, 舉例:
objs = a.o b.o c.o
#從objs列表中取出符合%的值(此處取出所有),然後替換爲替換爲.%.d
dep_files := $(patsubst %, .%.d, $(objs))
#取出dep_files中存在的文件,即取出所有依賴文件
dep_files := $(wildcard $(dep_files))
test: $(objs)
gcc -o test $^
#判斷是否包含依賴文件,若不包含,則執行include包含依賴文件命令
ifneq ($(dep_files),)
include $(dep_files)
endif
c.o : c.c c.h
#編譯%.o,把依賴寫入文件%.d
%.o : %.c
gcc -c -o $@ $< -MD -MF [email protected]
clean:
rm *.o test
distclean:
rm $(dep_files)
.PHONY: clean
2、添加CFLAGS
#將所有警告設置成錯誤提醒, 設置所有頭文件路徑到 ./ 即當前路徑查找 CFLAGS = -Werror -I./
objs = a.o b.o c.o
#從objs列表中取出符合%的值(此處取出所有),然後替換爲替換爲.%.d
dep_files := $(patsubst %, .%.d, $(objs))
#取出dep_files中存在的文件,即取出所有依賴文件
dep_files := $(wildcard $(dep_files))
#將所有警告設置成錯誤提醒, 設置所有頭文件路徑到 ./ 即當前路徑查找
CFLAGS = -Werror -I./
test: $(objs)
gcc -o test $^
#判斷是否包含依賴文件,若不包含,則執行include包含依賴文件命令
ifneq ($(dep_files),)
include $(dep_files)
endif
c.o : c.c c.h
#編譯%.o,把依賴寫入文件%.d
%.o : %.c
gcc -c -o $@ $< -MD -MF [email protected]
clean:
rm *.o test
distclean:
rm $(dep_files)
.PHONY: clean