Makefile-3-書寫規則


前言

  • 本筆記主要記錄Makefile一些概念要點。
  • 本筆記爲提取性筆記,章節與《跟我一塊兒寫Makefile》同步,因此會看到有些小標題會跳過。

概念

Chapter 3:書寫規則

3.3 在規則中使用通配符

  • make 支持三個通配符:
    • *
      • 任意長度的任意字符
      • 長度爲一的任意字符
    • ~以例子說明
      • ~/test
        • 表示當前用戶的 $HOME 目錄下的 test 目錄
      • ~lzm/test
        • 表示用戶爲 lzm 的宿主目錄下的 test 目錄
        • 若用戶沒有宿主目錄,則根據環境變量 HOME 而定。

舉例linux

  • 例子1
    • 變量 objects 表示當前目錄下全部的 .o 文件。
objects := $(wildcard *.o)
  • 例子2 *
    • :這裏的變量 objects 表示的就是 *.o,由於就像 C語言 的宏。
objects = *.o
  • 例子3 *
    • 列出當前全部 .c 文件對應的 .o 文件。
    • 下面的 *,是make的 * ,% 是makefile的 % ,具體看函數定義。
$(patsubst %.c,%.o,$(wildcard *.c))

3.4 文件搜索

  • VPATH 變量
    • Makefile 文件會在當前目錄下尋找依賴文件和目標文件,在找不到的狀況下就在 VPATH 變量中指定的路徑去找。
VPATH = src:../headers
* 上面例子中就是 **VPATH** 的格式,用 **:** 隔開多個路徑。
  • vpath 關鍵字
    • vpath 關鍵字比 VPATH 變量更加靈活, vpath 能夠指定不一樣的文件在不一樣的搜索目錄中。
    • 使用方法有三種:
      1. vpath 在 。爲符合模式 的文件指定搜索目錄 (多個目錄能夠用 空格或者 : 分開)。
      2. vpath 清除符合模式 的文件的搜索目錄。
      3. vpath 清除全部已被設置好了的文件搜索目錄。
vpath %.h include    //指定.h類型文件的搜索路徑是include

3.8 自動生成依賴性

在 Makefile 中,咱們的依賴關係可能會須要包含一系列的頭文件,好比,若是咱們的 main.c 中有一 句 #include "defs.h" ,那麼咱們的依賴關係應該是:函數

main.o : main.c defs.h

大多數的 C/C++ 編譯器都支持一個「-M」的 選項,即自動找尋源文件中包含的頭文件,並生成一個依賴關係。例如,若是咱們執行下面的命令:.net

cc -M main.c

其輸出是:命令行

main.o : main.c defs.h

** 注:若是使用 GNU 的 C/C++ 編譯器,得用 -MM 參數,否則,-M 參數會把一些標準庫的頭文件也包含進來。 **
如:
gcc -M main.c 的輸出是:code

main.o: main.c defs.h /usr/include/stdio.h /usr/include/features.h \
                            /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h \ 
                            /usr/lib/gcc-lib/i486-suse-linux/2.95.3/include/stddef.h \ 
                            /usr/include/bits/types.h /usr/include/bits/pthreadtypes.h \ 
                            /usr/include/bits/sched.h /usr/include/libio.h \ 
                            /usr/include/_G_config.h /usr/include/wchar.h \ 
                            /usr/include/bits/wchar.h /usr/include/gconv.h \ 
                            /usr/lib/gcc-lib/i486-suse-linux/2.95.3/include/stdarg.h \ 
                            /usr/include/bits/stdio_lim.h

gcc -MM main.c 的輸出則是:blog

main.o : main.c defs.h

原理 *

  • 隱晦規則(其中之一)
    • 會自動生成 gcc -c *.c 等語句。
      • 若是使用了該 隱晦規則 規則,在不改變 源文件 的狀況下,改變其它(如頭文件),再去運行 make 命令,是不會幹活的。

若是想使用 隱晦規則 + 依賴自動包含頭文件,能夠往下看。get

  • gcc -MM main.c
    • 會在 makefile 的依賴上自動添加 main.c 包含的頭文件。

基於上面這個原理,咱們能夠把 main.c 包含的頭文件 信息 自動識別出來並保存到 main.d 文件中。
這時候,.d 文件就出來了。編譯器

直接解析例子 **
  • 頭文件改變,make也會幹活。
  • 該腳本實現了,.c 文件編譯過程當中,產生 .d 文件。
%.d : %.c
    @set -e;rm -f $@;  \
    $(CC)  -MM $(CPPFLAGS) $< > $@.;  \
    sed 's,$∗\.o[ :]*,\1.o $@ : ,g' < $@. > $@;  \
    rm -f $@.

參考同步

  • 源碼解析
    • set -e;
      • 表示 直接在命令行模式上進行 sed 動做編輯,其實此爲默認選項
    • rm -f $@;
      • 表示 刪除全部目標文件,便是刪除全部 .d 文件。
    • $(CC)  -MM $(CPPFLAGS) $< > $@.;
      • 表示 編譯產生的一些標註庫的頭文件信息保存到 .d.xxx 隨機文件中。
      • $@.
        • 表示後綴爲隨機的意思。
      • 假設 CC= gcc ,CPPFLAGS=空,即 gcc -MM main.c > main.d.xxxx
        • > 表示重定向的意思。
        • 便是把 main.c 所依賴的頭文件信息寫入 main.d.xxxx 文件。如
main.o: main.c defs.h
* **sed 's,$∗\.o[ :]*,\1.o $@ : ,g' < $@. > $@;**
        * 表示執行linux 命令 sed
        * **< $@.**
            * 該文件內容交給前面,讓 sed 語句處理
        * **$∗\.o[ :]\***
            * 爲匹配字段
            * 表示 main 後面 .o 接着的字串段
        * **$∗\.o[ :]\***
            * 爲替換字段
        * **$@. > $@**
            * 輸入給 .d 文件,便是 main.d,內容以下:
main.o main.d : main.c defs.h
* **rm -f $@.**
            * 刪除 main.d.xxxx 的隨機文件。
  • 生成 .d 文件後,Makefile 文件能夠 include 該文件進入 Makefile 中,這樣, .o .d 都是目標文件,後面有不少依賴的頭文件,一旦頭文件更新,目標文件便會更新
sed 命令
  • 要點格式,具體百度
  • sed 爲linux命令,用於替換。
sed‘s:/usr/local:/usr:g’
  • s: 就是於把 : 看成分隔符 /
sed‘s;/usr/local;/usr;g’
  • s; 就是於把 ; 看成分隔符 /

參考

書籍

  • 《GUN Makefile》
  • 《跟我一塊兒寫Makefile》
相關文章
相關標籤/搜索