Linux Makefile 生成 *.d 依賴文件及 gcc -M -MF -MP 等相關選項說明【轉】


轉自:https://blog.csdn.net/qq1452008/article/details/50855810

版權聲明:本文為博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/QQ1452008/article/details/50855810

1. 為什么要使用后綴名為 .d 的依賴文件?

在 Makefile 中, 我們的依賴關系可能需要包含一系列的頭文件。
比如
main.c 源文件內容如下:

#include "stdio.h" #include "defs.h" int main(int argc, char *argv[]) { printf("Hello, %s!\n", NAME); return 0; } 

 

defs.h 頭文件如下:

#ifndef _DEFS_H_ #define _DEFS_H_ #define NAME "makefile" #endif _DEFS_H_ 

 

那么依賴關系應該如下: 
    main.o : main.c stdio.h defs.h ...   

 

但如果是一個比較大型的工程,你必需清楚每一個 C 源文件包含了哪些頭文件,並且在加入或刪除頭文件時,也需要小心地修改 Makefile,這是一個很沒有維護性的工作。為了避免這種繁重而又容易出錯的事情,我們可以使用 C/C++ 編譯的一個功能。大多數的 C/C++ 編譯器都支持一個 “-M” 的選項,即自動找尋源文件中包含的頭文件,並生成一個依賴關系。例如,執行下面的命令:

gcc -M main.c   
其輸出如下:  
    main.o : main.c defs.h

 

由編譯器自動生成依賴關系,這樣做的好處有以下幾點:

  • 不必手動書寫若干文件的依賴關系,由編譯器自動生成
  • 不管是 .c 文件還是 .h 文件有更新,目標文件都會重新編譯

2. 使用說明:

參數介紹:

  • -M
    生成文件的依賴關系,同時也把一些標准庫的頭文件也包含了進來。本質是告訴預處理器輸出一個適合 make 的規則,用於描述各目標文件的依賴關系。對於每個源文件,預處理器輸出 一個 make 規則,該規則的目標項 (target) 是源文件對應的目標文件名,依賴項 (dependency) 是源文件中 ‘#include’ 引用的所有文件,生成的規則可以是單行,但如果太長,就用’\’換行符續成多行。規則 顯示在標准輸出,不產生預處理過的C程序。
    注意:該選項默認打開了 -E 選項, -E 參數的用處是使得編譯器在預處理結束時就停止編譯

例如: gcc -M main.c
則在終端上輸出如下:
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/_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

  • -MM
    生成文件的依賴關系,和 -M 類似,但不包含標准庫的頭文件

例如:gcc -MM main.c
則在終端上輸出如下:
main.o: main.c defs.h

  • -MG
    要求把缺失的頭文件按存在對待,並且假定他們和源程序文件在同一目錄下.必須和 ‘-M’ 選項一起用.

  • -MF File
    當使用了 ‘-M’ 或者 ‘-MM’ 選項時,則把依賴關系寫入名為 ‘File’ 的文件中。若同時也使用了 ‘-MD’ 或 ‘-MMD’,’-MF’ 將覆寫輸出的依賴文件的名稱

例如:gcc -M -MF main.d main.c 則 '—M' 輸出的內容就存在於 main.d 文件中了

 

  • -MD
    等同於 ‘-M -MF File’,但是默認關閉了 ‘-E’ 選項. 其輸出的文件名是基於 ‘-o’ 選項,若給定了 ‘-o’ 選項,則輸出的文件名是 ‘-o’ 指定的文件名,並添加 .d 后綴,若沒有給定,則輸入的文件名作為輸出的文件名,並添加.d后綴,同時繼續指定的編譯工作
    注意:’-MD’ 不會像 ‘-M’ 那樣阻止正常的編譯任務. 因為它默認關閉了 ‘-E’ 選項, 比如命令中使用了 -c 選項,其結果要生成 .o 文件,若使用了 ‘-M’ 選項,則不會生成 .o 文件,若使用的是 ‘-MD’ 選項,則會生成 .o 文件
例如1:gcc -E -MD main.c 本目錄下生成了以下文件: main.d 同時在終端上輸出了 main.c 文件的預處理結果 經實測發現,不使用 '-o' 指定輸出文件名,以下情況有細微的差別: gcc -E main.c //不使用 '-o',則把結果輸出在終端上 gcc -S main.c //不使用 '-o',則把結果默認輸出到以輸入文件名為名稱的 .s 文件中,即 main.s gcc -c main.c //同上 gcc main.o //不使用 '-o',則把結果默認輸出到 a.out 可執行文件中

 

例如2:gcc -E -o tmp.i -MD main.c 本目錄下生成了以下文件: tmp.d tmp.i 例如3:gcc -c -MD main.c 本目錄下生成了以下文件: main.d main.o 例如4:gcc -c -o tmp.o -MD main.c 本目錄下生成了以下文件: tmp.d tmp.o 例如5: gcc -MD main.c 本目錄下生成了以下文件: a.out main.d 例如6: gcc -M -MD main.c 本目錄下生成了以下文件: main.d //並不會生成a.out可執行文件,因為 '-M' 默認打開了 '-E' 選項,使得編譯器在預處理結束后就停止編譯
  • -MMD
    類似於 ‘-MD’,但是輸出的依賴文件中,不包含標准頭文件

  • -MP
    生成的依賴文件里面,依賴規則中的所有.h依賴項都會在該文件中生成一個偽目標,其不依賴任何其他依賴項。該偽規則將避免刪除了對應的頭文件而沒有更新 “Makefile” 去匹配新的依賴關系而導致make出錯的情況出現。
    (英文描述:This option instructs CPP to add a phony target for each dependency
    other than the main file, causing each to depend on nothing. These
    dummy rules work around errors ‘make’ gives if you remove header
    files without updating the ‘Makefile’ to match.)

例如1: gcc -c -MM -MD main.c 生成的 main.d 文件內容如下: main.o: main.c defs.h 例如1: gcc -c -MM -MD main.c -MP 生成的 main.d 文件內容如下: main.o: main.c defs.h defs.h: //該選項會生成該偽目標,其沒有任何依賴項,若不使用 '-MP' 選項,則不會生成該偽目標規則

 

  • -MT Target
    在生成的依賴文件中,指定依賴規則中的目標
例如: gcc -MF main.d -MG -MM -MP -MT main.d -MT main.o main.c $ cat main.d #查看生成的依賴文件的內容 main.d main.o: main.c 注:依賴規則中main.d 和 main.o 目標都是通過'-MT'選項指定的

 

3. 使用參考:

以上簡單介紹了 gcc -M 相關的選項,旨在讓 make 自動推導並生成文件的依賴關系.
以下提供一個比較好的 gcc -M 選項的參考示例, 它將自動生成依賴文件,並保存在指定目錄下的 ‘.d’ 文件中。

makefile如下所示:

SRCS=$(wildcard *.c) OBJS=$(SRCS:.c=.o) DEPS=$(SRCS:.c=.d) .PHONY: all clean all: main -include $(DEPS) #注釋:'-'號的作用:加載錯誤時,會繼續執行 make,主要是考慮到首次 make 時,目錄中若不存在 '*.d' 文件時,加載便會產生錯誤而停止 make 的執行 %.o:%.c gcc -c -g -Wall $< -o $@ -MD -MF $*.d -MP main: $(OBJS) gcc $^ -o $@ #注釋:$^:表示所有的依賴文件 $@:表示目標文件 clean: rm -f *.d *.o main

 

仍舊以本篇文章開頭的源文件進行 make,將生成如下文件:
main : 可執行文件
main.o : 編譯的二進制目標文件
main.d:保存了 main.o 依賴關系的文件

注釋: $* 表示目標模式中 '%' 及其之前的部分.如果目標是 'dir/a.foo.b', 並且目標的模式為 'a.%.b',那么 '$*' 的值就是 'dir/a.foo'. 如果目標中沒有模式的定義,那么 '$*' 就不能被推導出. 但是,如果目標文件是 make 所識別的,那么 '$*' 就是除了后綴的那一部分, 例如:目標是 'foo.c',因為 '.c' 是 make 所能識別的后綴名, 所以 '$*' 的值就是 'foo'.這個特性是 GNU make 的.

4. 延伸說明:

Makefile 文件中使用比較多的自動變量: - $@ : 表示一個規則中的目標.當規則中有多個目標時,$@ 所指的是其中任何造成規則的命令運行的目標 - $^ : 表示規則中的所有依賴項 - $< : 表示規則中的第一個依賴項 例如 Makefile 文件內容如下: target1 target2:dep1 dep2 dep3 @echo "Tar:$@, First Dep:$<, All Dep:$^" dep1 dep2 dep3: #注釋:不寫該行目標規則,執行 make 會報錯,因為 makefile 目錄下不僅沒有 dep1 dep2 dep3 文件,makefile 文件中也沒有以這些依賴文件做為目標的規則. 運行 make: 1. make target1 或者 make (把文件中第一個目標當作首要目標) 終端輸出如下: Tar:target1, First Dep:dep1, All Dep:dep1 dep2 dep3 2. make target2 終端輸出如下: Tar:target2, First Dep:dep1, All Dep:dep1 dep2 dep3 3. make target1 target2 終端輸出如下: Tar:target2, First Dep:dep1, All Dep:dep1 dep2 dep3 Tar:target2, First Dep:dep1, All Dep:dep1 dep2 dep3

 

相信大家在看了以上例子,能夠更加理解這三個自動化變量的含義,尤其是 ‘$@‘, 前面已經說明了其含義,這里就不再贅述了.


以上有些內容引用了其他博客,在此,感謝博主!
以上內容,若有差錯,歡迎指正,以免誤人誤己。

--------------------- 本文來自 Jerry_yl_ 的CSDN 博客 ,全文地址請點擊:https://blog.csdn.net/qq1452008/article/details/50855810?utm_source=copy 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM