Note:
這篇博客用於講解makefile編寫過程中的一些難點,不是makefile的基礎教程,不建議初學者閱讀。這篇博客參考了其他的書籍和文章,在最後會給出,有需要的可以去看一下。筆者看過《GNU+Make項目管理(第三版)》和《跟我一起寫Makefile-陳皓》,其中前者晦澀難懂,適合進階閱讀,後者的話就比較適合初學者閱讀。在學習makefile編寫之前,建議先學會gcc編譯的方法和步驟,關於gcc相關的知識,筆者在以後也會更新。
What is this:
這篇文章將會帶你學習makefile的變量用法、隱含規則、定義模式規則、自動化規則、相關函數等。
規則
makefile文件包含了一組用於編譯應用程序的規則。make所看到的第一項規則會被作爲默認規則使用。規則可分爲三個部分:目標(target)、依賴目標或稱必要條件(prerequisite)、命令(command):
target : prereq1 prereq2
commands
target 是一個必須建立的文件或進行的事情(僞目標);prerequisite或依存對象(dependent)是target被成功創建之前必須事先存在的文件;command是通過prerequisite生成target所需的shell命令,通常放到TAB符之後。
當make被要求處理某項規則時,它首先會找出prerequisite和target中指定的文件。如果prerequisite中存在關聯到其他規則的文件,則make會先完成相應規則的更新動作,然後纔會考慮target。如果prerequisite的存在時間在target時間之後,則make會執行命令以便重新建立target。command是在被傳遞給shell,並在subshell中運行,所以如果你希望第二條命令在同樣的subshell中運行,就應該把兩條命令寫在一行,用分號隔開。
隱含規則
隱含規則不是模式規則就是後綴規則,當make檢查一個target,如果找不到更新它的規則,就會使用隱含規則
定義模式規則
你可以使用模式規則定義一個隱含規則。模式規則一般是這樣的:
%.o : %.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
在模式規則中,至少在target中需要包含%,否則就是一般規則了。在target中,%代表任意字符,在prerequisite中,%和target的%表示的意思相同;也就是說,如果%.o 代表a.o b.o c.o ,那麼%.c 就一定代表a.c b.c c.c 。這個模式規則就指出了怎麼從一個.c文件生成相應的.o文件。
自動化變量
上面使用到了
自動化變量 | 代表的意義 |
---|---|
$@ | 規則中的target |
$< | prerequisite中的第一個目標的名字,如果prerequisite是以模式(%)定義的, 那麼$<將是符合模式的一系列文件集。 |
$? | 所有比target新的prerequisite的集合,以空格分隔 |
$^ | 所有prerequisite的集合,以空格分開,如果prerequisite中有多個重複,那麼 這個變量會去除重複的prerequisite |
$* | 這個變量表示目標模式中%及其之前的部分,如果目標是dir/a.foo.b , 並且目標的模式是a.%.b,那麼$*的值就是dir/a.foo。 |
相關函數
- Subst()
用法:$(subst <from> ,<to>,<text>)
名稱:字符串替換函數
功能:把字符串<text>中的<from>字符串替換成<to>
返回:函數返回被替換過後的字符串 - patsubst
用法:$(patsubst <pattern>,<replacement>,<text>)
名稱:模式字符串替換函數
功能:查找<text>中的單詞(單詞以空格、Tab、或回車、換行符分隔)是否符合模式<pattern>,如果匹配的話,則以<replacement>替換,這裏<pattern>可以包括通配符“%”,表示任意長度的字符串,如果<replacement>也包括“%”,那麼<replacement>中的這個“%”將是<pattern>中的那個“%”所代表的字符串
返回:函數返回被替換過的字符串
示例:$(patsubst %.c %.o x.c.c bar.c)把字符串“x.c.c bar.c”符合模式%.c的單詞替換成%.o,返回結果是“x.c.o bar.o” - strip
用法: $(strip <string>)
名稱:去掉空格函數
功能:去掉<string>字符串開頭和結尾的空格 - shell
功能:它的參數應該是操作系統shell的命令,它和反引號是相同的功能。shell函數把操作系統命令後的輸出作爲函數返回。
示例:files := $(shell echo *.c) - findstring
用法:$(findstring <find>,<in>)
名稱:查找字符串函數
功能:在字符串<in>中查找<find>字符串
返回:如果找到,則返回<find>,否則返回空字符串
CFLAGS編譯器參數
這裏爲什麼要講CFLAGS呢?CFLAGS是c語言編譯器參數,在makefile文件中經常會用到CFLAGS,所以在這裏對CFLAGS也做一些解釋。
例如編譯c程序的隱含規則命令:
- $(CC)是c語言編譯程序
- $(CFLAGS)是c語言編譯器參數
- $(CPPFLAGS)是c預處理器參數
這裏用$(CFLAGS)代替了gcc的很多選項,比如-w -i等,將這些值定義成一個變量,主要是爲了方便書寫和管理,如果每次使用相同配置的gcc都要輸入一長串的參數值,很容易出現錯誤。CFLAGS出現的一些常用的值如下:
- -W/-Wall:-W,在編譯中開啓一些額外的warning信息。-Wall,將所有的警告信息全開
- -w:禁止輸出warning消息
- -I: 指定頭文件所在的文件夾,使用示例:-I/path/inc
- -L:指定函數庫所在的文件夾,使用示例:-L/path/lib
- -l:指定所使用到的函數庫,使用示例-llibxxx.a
- -D:打開宏,使用示例:-DLOW_POWER,相當於在所有的文件前面加上#define LOW_POWER 1; -DLOW_POWER=5,相當於#define LOW_POWER 5;
- -U:關閉宏,使用示例:-ULOW_POWER,相當於在所有文件前面加上#undef LOW_POWER
- Wl option:傳遞option給連接程序
- -share:儘量使用動態庫
- -x:設定文件所使用的語言,使後綴名無效,對以後的多個有效.也就是根據約定C語言的後綴名稱是.c的,而c++的後綴名是.c或者.cpp,使用示例:-x c filename
參考文檔
《跟我一起寫Makefile-陳皓》
《GNU+Make項目管理(第三版)》
gcc編譯參數