2010-03-07 119 views
70

比方說,我有一個makefile與規則的Makefile,頭依賴

%.o: %.c 
gcc -Wall -Iinclude ... 

我想*的.o被重建時一個頭文件的變化。而不是制定一個依賴關係列表,只要/include中的任何頭文件發生更改,則必須重建該目錄中的所有對象。

我想不出一個很好的方法來改變規則來適應這一點,我願意提出建議。獎勵積分,如果標題的列表不必進行硬編碼

+0

在下面寫下我的回答後,我查看了相關列表並找到了:http://stackoverflow.com/questions/297514/how-can-i-have-a-makefile-automatically-rebuild-source-files-that -include-a-modif看起來是重複的。克里斯多德的答案與我的相同,儘管它使用了不同的命名約定。 – dmckee 2010-03-07 00:37:44

回答

104

如果您使用GNU編譯器,編譯器可以爲您組裝一系列依賴項。 Makefile片段中:

depend: .depend 

.depend: $(SRCS) 
     rm -f ./.depend 
     $(CC) $(CFLAGS) -MM $^ -MF ./.depend; 

include .depend 

depend: .depend 

.depend: $(SRCS) 
     rm -f ./.depend 
     $(CC) $(CFLAGS) -MM $^ > ./.depend; 

include .depend 

其中SRCS是一個變量指向源文件的完整清單。

也有工具makedepend,但我從來不喜歡它,就像gcc -MM

+2

我喜歡這個技巧,但是我怎麼才能讓'depend'只在源文件發生變化時運行?它似乎每次都運行,無論... – chase 2011-08-23 20:18:22

+2

@chase:嗯,我錯誤地做了對目標文件的依賴關係,當它顯然應該在源上,並且對兩個目標的依賴關係順序也是錯誤的。這就是我從內存中輸入的內容。現在就試試。 – dmckee 2011-08-23 21:15:40

+4

是否在每個文件之前添加一些前綴以顯示它在另一個目錄中,例如'build/file.o'? – RiaD 2012-10-12 17:41:31

21

如何像:

includes = $(wildcard include/*.h) 

%.o: %.c ${includes} 
    gcc -Wall -Iinclude ... 

您也可以直接使用通配符,但我往往會發現,我需要他們更多的比一個地方。

請注意,這隻適用於小型項目,因爲它假定每個目標文件都依賴於每個頭文件。

+0

謝謝,我是這樣做的,比需要的要複雜得多 – Mike 2010-03-07 00:29:43

+9

這可行,但是,這個問題是,每一個對象文件都會被重新編譯,每次做一個小的改變,也就是說,如果你有100個源/頭文件,並且只對一個進行小改動,全部100個被重新編譯。 – 2014-06-16 12:37:57

+0

你應該真的更新你的答案,說這是一種非常低效的方法,因爲它每次更改任何頭文件時都會重建所有文件。其他答案要好得多。 – xaxxon 2015-10-30 21:35:09

24

正如我貼here GCC可以建立依賴關係,並在同一時間編譯:

DEPS := $(OBJS:.o=.d) 

-include $(DEPS) 

%.o: %.c 
    $(CC) $(CFLAGS) -MM -MF $(patsubst %.o,%.d,[email protected]) -o [email protected] $< 

的「-MF '參數指定一個文件來存儲依賴項。

'-include'開始處的短劃線指示在.d文件不存在時繼續進行Make(例如,在第一次編譯時)。

請注意,在-o選項中似乎存在gcc中的錯誤。如果將對象文件名設置爲obj/_file__c.o,則生成的文件 .d將仍包含文件.o,而不是obj/_file__c.o。

+4

當我嘗試這個時,它會導致我的所有.o文件被創建爲空文件。我確實在構建子文件夾中有我的對象(所以$ OBJECTS包含build/main.o build/smbus.o build/etc ...),並且當然會創建.d文件根本不構建.o文件,而如果我刪除-MM和-MF,則會出現這種情況。 – bobpaul 2012-11-14 01:03:26

+1

使用-MT將解決答案的最後幾行中的註釋,該註釋更新每個依賴列表的目標。 – 2013-03-22 19:47:41

+0

我已經嘗試過這種不同的組合,它似乎沒有工作... – g24l 2014-12-15 11:07:33

0

我更喜歡這個解決方案,而不是Michael Williamson接受的答案,它捕獲源+內聯文件,源+標題和最終源的更改。這裏的優點是,如果只做了一些更改,整個庫不會重新編譯。對於一個有兩個文件的項目來說,這不是一個巨大的考慮因素,如果你有10個或100個源文件,你會發現它們的差異。

COMMAND= gcc -Wall -Iinclude ... 

%.o: %.cpp %.inl 
    $(COMMAND) 

%.o: %.cpp %.hpp 
    $(COMMAND) 

%.o: %.cpp 
    $(COMMAND) 
+1

只有在頭文件中沒有任何需要重新編譯除相應實現文件之外的任何cpp文件的情況下才有效。 – matec 2014-11-04 10:28:33

3

這將做的工作只是罰款,甚至處理子目錄被指定:

$(CC) $(CFLAGS) -MD -o [email protected] $< 

用gcc測試了4.8.3

4

以上馬丁的解決方案的偉大工程,但不處理.o文件駐留在子目錄中。Godric指出,-MT標誌可以解決這個問題,但它同時會阻止.o文件被正確寫入。以下將照顧這兩個問題:

DEPS := $(OBJS:.o=.d) 

-include $(DEPS) 

%.o: %.c 
    $(CC) $(CFLAGS) -MM -MT [email protected] -MF $(patsubst %.o,%.d,[email protected]) $< 
    $(CC) $(CFLAGS) -o [email protected] $< 
26

大多數答案是驚人的複雜或錯誤。然而,簡單而健壯的示例已在其他地方發佈[codereview]。無可否認,GNU預處理器提供的選項有點混亂。然而,去除與-MM構建目標的所有目錄中的文件,而不是一個bug [gpp]:

默認情況下,CPP採用主輸入文件名,刪除任何 目錄組件和任何文件後綴(如「.c」),並附加平臺的通用對象後綴。

(較新)-MMD選項可能是你想要的。爲了完整起見,一個makefile文件的例子支持多個src dirs並且用一些註釋構建dirs。對於沒有構建目錄的簡單版本,請參見[codereview]。

CXX = clang++ 
CXX_FLAGS = -Wfatal-errors -Wall -Wextra -Wpedantic -Wconversion -Wshadow 

# Final binary 
BIN = mybin 
# Put all auto generated stuff to this build dir. 
BUILD_DIR = ./build 

# List of all .cpp source files. 
CPP = main.cpp $(wildcard dir1/*.cpp) $(wildcard dir2/*.cpp) 

# All .o files go to build dir. 
OBJ = $(CPP:%.cpp=$(BUILD_DIR)/%.o) 
# Gcc/Clang will create these .d files containing dependencies. 
DEP = $(OBJ:%.o=%.d) 

# Default target named after the binary. 
$(BIN) : $(BUILD_DIR)/$(BIN) 

# Actual target of the binary - depends on all .o files. 
$(BUILD_DIR)/$(BIN) : $(OBJ) 
    # Create build directories - same structure as sources. 
    mkdir -p $(@D) 
    # Just link all the object files. 
    $(CXX) $(CXX_FLAGS) $^ -o [email protected] 

# Include all .d files 
-include $(DEP) 

# Build target for every single object file. 
# The potential dependency on header files is covered 
# by calling `-include $(DEP)`. 
$(BUILD_DIR)/%.o : %.cpp 
    mkdir -p $(@D) 
    # The -MMD flags additionaly creates a .d file with 
    # the same name as the .o file. 
    $(CXX) $(CXX_FLAGS) -MMD -c $< -o [email protected] 

.PHONY : clean 
clean : 
    # This should remove all generated files. 
    -rm $(BUILD_DIR)/$(BIN) $(OBJ) $(DEP) 

此方法有效,因爲如果存在用於單個目標多重依賴性線,所述依賴關係簡單地接合,例如:如上所述

a.o: a.c a.h 
    ./cmd 

a.o: a.h 
a.o: a.c 
    ./cmd 

相當於在:Makefile multiple dependency lines for a single target?

+0

我喜歡這個解決方案。我不想輸入make depend命令。有用! – Robert 2016-06-10 15:02:11

+1

OBJ變量值中存在拼寫錯誤:「CPP」應爲「CPPS」 – ctrucza 2016-08-10 12:56:54

+0

這是我的首選答案;爲你+1。這是唯一一個在這個頁面上是有道理的,並涵蓋(我所能看到的)所有需要重新編譯的情況(避免不必要的編譯,但是足夠) – Joost 2016-08-26 07:48:32

0

以下適用於我:

DEPS := $(OBJS:.o=.d) 

-include $(DEPS) 

%.o: %.cpp 
    $(CXX) $(CFLAGS) -MMD -c -o [email protected] $< 
0

這裏有一個兩班輪:

CPPFLAGS = -MMD 
-include $(OBJS:.c=.d) 

這適用於默認的化妝食譜,只要你有你的所有目標文件中OBJS列表。