makefile編寫過程中的難點

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。

相關函數

  1. Subst()
    用法:$(subst <from> ,<to>,<text>)
    名稱:字符串替換函數
    功能:把字符串<text>中的<from>字符串替換成<to>
    返回:函數返回被替換過後的字符串
  2. 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”
  3. strip
    用法: $(strip <string>)
    名稱:去掉空格函數
    功能:去掉<string>字符串開頭和結尾的空格
  4. shell
    功能:它的參數應該是操作系統shell的命令,它和反引號是相同的功能。shell函數把操作系統命令後的輸出作爲函數返回。
    示例:files := $(shell echo *.c)
  5. findstring
    用法:$(findstring <find>,<in>)
    名稱:查找字符串函數
    功能:在字符串<in>中查找<find>字符串
    返回:如果找到,則返回<find>,否則返回空字符串

CFLAGS編譯器參數

這裏爲什麼要講CFLAGS呢?CFLAGS是c語言編譯器參數,在makefile文件中經常會用到CFLAGS,所以在這裏對CFLAGS也做一些解釋。
例如編譯c程序的隱含規則命令:(CC)c (CFLAGS) $(CPPFLAGS),其中:

  • $(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編譯參數

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章