簡體   English   中英

Makefile、頭文件依賴

[英]Makefile, header dependencies

假設我有一個帶有規則的 makefile

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

我希望在頭文件更改時重建 *.o。 每當/include任何頭文件發生更改時,都必須重新構建該目錄中的所有對象,而不是計算出依賴項列表。

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

如果您使用的是 GNU 編譯器,編譯器可以為您組裝一個依賴項列表。 生成文件片段:

depend: .depend

.depend: $(SRCS)
        rm -f "$@"
        $(CC) $(CFLAGS) -MM $^ -MF "$@"

include .depend

或者

depend: .depend

.depend: $(SRCS)
        rm -f "$@"
        $(CC) $(CFLAGS) -MM $^ > "$@"

include .depend

其中SRCS是指向整個源文件列表的變量。

還有makedepend工具,但我從來沒有像gcc -MM那樣喜歡它

大多數答案出人意料地復雜或錯誤。 然而,其他地方已經發布了簡單而強大的示例 [ codereview ]。 誠然,gnu 預處理器提供的選項有點令人困惑。 但是,記錄了使用-MM從構建目標中刪除所有目錄的記錄,而不是錯誤 [ gpp ]:

默認情況下,CPP 采用主輸入文件的名稱,刪除任何目錄組件和任何文件后綴,例如“.c”,並附加平台的常用對象后綴。

(有點新) -MMD選項可能是您想要的。 為了完整起見,一個支持多個 src 目錄和帶有一些注釋的構建目錄的 makefile 示例。 對於沒有構建目錄的簡單版本,請參閱 [ 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 $@

# 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 $@

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

此方法有效,因為如果單個目標有多個依賴項,則這些依賴項會簡單地連接起來,例如:

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

相當於:

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

如在: Makefile 單個目標的多個依賴項行所述?

正如我在這里發布的那樣 gcc 可以同時創建依賴項和編譯:

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

-include $(DEPS)

%.o: %.c
    $(CC) $(CFLAGS) -MM -MF $(patsubst %.o,%.d,$@) -o $@ $<

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

'-include' 開頭的破折號告訴 Make 在 .d 文件不存在時繼續(例如在第一次編譯時)。

請注意,gcc 中似乎存在關於 -o 選項的錯誤。 如果您將目標文件名設置為 obj/_file__c.o,那么生成的文件.d 仍將包含文件.o,而不是 obj/_file__c.o。

怎么樣:

includes = $(wildcard include/*.h)

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

您也可以直接使用通配符,但我傾向於發現我在不止一個地方需要它們。

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

上面 Martin 的解決方案效果很好,但不處理駐留在子目錄中的 .o 文件。 Godric 指出 -MT 標志解決了這個問題,但它同時阻止了 .o 文件被正確寫入。 以下將解決這兩個問題:

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

-include $(DEPS)

%.o: %.c
    $(CC) $(CFLAGS) -MM -MT $@ -MF $(patsubst %.o,%.d,$@) $<
    $(CC) $(CFLAGS) -o $@ $<

這將很好地完成工作,甚至可以處理指定的子目錄:

    $(CC) $(CFLAGS) -MD -o $@ $<

用 gcc 4.8.3 測試過

這是一個兩行:

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

這適用於默認的 make 配方,只要您在OBJS中有所有目標文件的OBJS

Sophie's answer 的一個稍微修改的版本,它允許將 *.d 文件輸出到不同的文件夾(我只會粘貼生成依賴文件的有趣部分):

$(OBJDIR)/%.o: %.cpp
# Generate dependency file
    mkdir -p $(@D:$(OBJDIR)%=$(DEPDIR)%)
    $(CXX) $(CXXFLAGS) $(CPPFLAGS) -MM -MT $@ $< -MF $(@:$(OBJDIR)/%.o=$(DEPDIR)/%.d)
# Generate object file
    mkdir -p $(@D)
    $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $< -o $@

注意參數

-MT $@

用於確保生成的 *.d 文件中的目標(即目標文件名)包含 *.o 文件的完整路徑,而不僅僅是文件名。

我不知道為什么在將 -MMD 與 -c結合使用時不需要此參數(如 Sophie 的版本)。 在這種組合中,它似乎將 *.o 文件的完整路徑寫入 *.d 文件。 如果沒有這種組合,-MMD 也只會將沒有任何目錄組件的純文件名寫入 *.d 文件。 也許有人知道為什么 -MMD 與 -c 結合使用時會寫出完整路徑。 我在 g++ 手冊頁中沒有找到任何提示。

我更喜歡這個解決方案,而不是邁克爾威廉姆森接受的答案,它捕獲對源+內聯文件的更改,然后是源+標題,最后是僅源。 這里的優點是如果只進行一些更改,則不會重新編譯整個庫。 對於有幾個文件的項目來說,這不是一個很大的考慮,但如果你有 10 個或 100 個源,你會注意到差異。

COMMAND= gcc -Wall -Iinclude ...

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

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

%.o: %.cpp
    $(COMMAND)

以下對我有用:

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

-include $(DEPS)

%.o: %.cpp
    $(CXX) $(CFLAGS) -MMD -c -o $@ $<

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM