2012-03-26 78 views
3
%.d: %.c 
     @set -e; rm -f [email protected]; \ 
     $(CC) -MM $< > [email protected]$$$$; \ 
     sed 's,\($*\)\.o[ :]*,\1.o [email protected] : ,g' < [email protected]$$$$ > [email protected]; \ 
     rm -f [email protected]$$$$ 

sinclude $(SOURCES:.c=.d) 

上面是我在某人的博客上看到的,但它沒有解釋代碼如何在makefile中創建.c和.h文件之間的依賴關係。如何自動生成文件之間的依賴關係?

有沒有人會爲我解釋或提供一些材料?

我真的很感謝您的幫助!謝謝!

+1

我不知道答案,但我不得不說,這只是關於線路噪聲的最壞情況我已經曾經在sendmail.cf文件之外見過。 '$ < > $ @。$$$$; \'?真的嗎? – Celada 2012-03-26 14:59:44

+0

我可以購買元音嗎? – 2012-03-26 15:52:14

回答

0

假設你只有新的源文件是foo.c,其中包含

#include "foo.h" 
#include "bar.h" 

製作確定foo.d是過時的(因爲它不存在或foo.c的是更新版本)的線,所以它執行規則。

%.d: %.c 
     @set -e; rm -f [email protected]; \ 
     $(CC) -MM $< > [email protected]$$$$; \ 
     sed 's,\($*\)\.o[ :]*,\1.o [email protected] : ,g' < [email protected]$$$$ > [email protected]; \ 
     rm -f [email protected]$$$$ 

sinclude $(SOURCES:.c=.d) 

製作評估$$$$作爲$$並傳遞到所述殼; shell會將此解釋爲參數$的值,該參數是該規則希望用於構造唯一文件名的shell的進程ID。這將只在一個命令內保持恆定,這就是爲什麼規則是用行延續(「\」)編寫的。這不是一個很好的方法來做到這一點;如果有不同的進程在同一時間試圖構建foo.d,那麼無論如何你可能會被徹底清理。所以我們可以重寫這個規則:

%.d: %.c 
     @set -e; rm -f [email protected] 
     $(CC) -MM $< > [email protected] 
     sed 's,\($*\)\.o[ :]*,\1.o [email protected] : ,g' < [email protected] > [email protected] 
     rm -f [email protected] 

sinclude $(SOURCES:.c=.d) 

我們可以放棄第一條規則,它並不真正對問題產生影響。

第二個命令$(CC) -MM $< > [email protected]擴展爲gcc -MM foo.c > foo.d.temp(或其他一些編譯器)。該-MM標誌告訴編譯器生成依賴列表:

foo.o: foo.c foo.h bar.h 

下一行嚼了這個名單與sed的

sed 's,\($*\)\.o[ :]*,\1.o [email protected] : ,g' 

大致翻譯爲「改變foo.o:foo.o foo.d :」:

foo.o foo.d : foo.c foo.h bar.h 

(並且最後一條命令刪除臨時文件。)

這不是處理依賴關係的最佳方法,因爲每次運行Make時它都會重新生成所有%.d文件,甚至與您的目標無關。更多的拋光方法是Advanced Auto-Dependency Generation

0

#include的實際跟蹤由預處理器執行(請參閱-M and -MM options)。

-M

相反輸出的預處理,輸出適合於make描述主源文件的相關性的規則的結果的。預處理器輸出一個make規則,該規則包含該源文件的目標文件名,冒號和所有包含文件的名稱,包括來自-include-imacros命令行選項的名稱。

-MM

-M但沒有提及包括直接或間接,從這樣的標頭,在系統頭目錄中找到頭文件,也沒有頭文件。

另外一個很好的跟蹤這些類型的依賴關係的可能方式概述可用here

3

From gcc manual

-M 
Instead of outputting the result of preprocessing, output a rule suitable for make describing the dependencies of the main source file. ... 

-MM 
Like -M but do not mention header files that are found in system header directories, ... 

所以這裏的命令:

$(CC) -MM $< > [email protected]$$$$; \ 
     sed 's,\($*\)\.o[ :]*,\1.o [email protected] : ,g' < [email protected]$$$$ > [email protected]; \ 

建立一個臨時($ @ $$$$,即目標文件名附加一個唯一的號碼)gcc -MM文件輸出和使用sed格式,這樣當被makefile包含時,依賴文件將看起來像target file: [gcc generated dependencies]。然後刪除原始的gcc -MM輸出。

0

對於所有有一排等四大美元符號的官樣文章,這個想法很簡單:

  1. 從文件xyz.c創建一個文件xyz.d,運行中的命令...
  2. $(CC)行可能應該包含$(CFLAGS),但它假定編譯器是GCC(-MM選項在其他地方不是標準的)。 -MM標誌請求編譯器生成列出源中包含的頭文件(或其他文件)的輸出,以便爲當前平臺獲取正確的相關性信息。
  3. 編譯器編譯源代碼並將依賴項寫入標準輸出,該輸出被重定向到一個臨時文件。生成文件中[email protected]$$$$的擴展是(例如),xyz.$$在shell中,其中$$成爲運行腳本的shell的PID。
  4. sed命令munges從編譯器輸出,使得一個行開始xyz.o開始於xyz.o xyz(因此該對象文件,並從對象文件都創建的程序依賴於結腸後的文件)xyz.o xyz.d,所以無論是如果任何源文件或頭文件發生更改,則需要更新目標文件和依賴項文件。
  5. 輸出寫入xyz.d
  6. 頂部和底部都有清理。
  7. sinclude行讀取儘可能多的.d文件,因爲它可以找到。

[編輯修復的差異所指出的Beta]

+0

在4)中,它將'xyz.o'改爲'xyz.o xyz。d',而不是'xyz.o xyz'。 – Beta 2012-03-26 17:38:43

+0

@Jonathan Leffler,我有個問題:「sinclude ./header_dir/*.h」和「gcc -I ./Header_dir」有什麼區別? – city 2012-03-27 00:56:22

+0

'sinclude ./Header_dir/*。h'將C代碼複製到'makefile'中,這通常是一個壞主意('make'不理解C代碼,因爲它知道如何編譯它)。相比之下,如果源代碼包含'#include「someheader.h」'並且有一個文件'Header_dir/someheader.h','gcc -I ./ Header_dir'將使得Header_dir中的頭文件可用於C編譯器。完全不同的操作;一個是假的,另一個是明智的。請注意,'sinclude'行包含'xyz.d'依賴文件。 – 2012-03-27 01:07:45