假设我有一个带有规则
的makefile%.o: %.c
gcc -Wall -Iinclude ...
我想在头文件发生变化时重建* .o。每当/include
中的任何头文件发生更改时,都不会计算出依赖项列表,而是必须重建dir中的所有对象。
我想不出改变规则的好方法来容纳这个,我愿意接受建议。如果标题列表不必硬编码,则奖励积分
答案 0 :(得分:111)
如果您使用的是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
答案 1 :(得分:53)
大多数答案都非常复杂或错误。然而,其他地方[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 multiple dependency lines for a single target?
答案 2 :(得分:24)
当我发布here时,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。
答案 3 :(得分:22)
如下:
includes = $(wildcard include/*.h)
%.o: %.c ${includes}
gcc -Wall -Iinclude ...
您也可以直接使用通配符,但我倾向于发现我需要它们在多个地方。
请注意,这仅适用于小型项目,因为它假定每个目标文件都依赖于每个头文件。
答案 4 :(得分:4)
Martin的上述解决方案效果很好,但不处理驻留在子目录中的.o文件。 Godric指出-MT标志负责处理该问题,但它同时阻止.o文件被正确写入。以下将解决这两个问题:
DEPS := $(OBJS:.o=.d)
-include $(DEPS)
%.o: %.c
$(CC) $(CFLAGS) -MM -MT $@ -MF $(patsubst %.o,%.d,$@) $<
$(CC) $(CFLAGS) -o $@ $<
答案 5 :(得分:3)
这可以很好地完成工作,甚至可以处理指定的子目录:
$(CC) $(CFLAGS) -MD -o $@ $<
用gcc 4.8.3进行测试
答案 6 :(得分:1)
这是一个双线:
CPPFLAGS = -MMD
-include $(OBJS:.c=.d)
这适用于默认的制作配方,只要您在OBJS
中有所有目标文件的列表。
答案 7 :(得分:0)
我更喜欢这个解决方案,而不是Michael Williamson接受的答案,它会捕获源+内联文件的变化,然后是源+标题,最后只有源。这里的优点是,如果只进行一些更改,则不会重新编译整个库。对于包含几个文件的项目来说,不是一个巨大的考虑因素,如果你有10个或100个来源,你会注意到差异。
COMMAND= gcc -Wall -Iinclude ...
%.o: %.cpp %.inl
$(COMMAND)
%.o: %.cpp %.hpp
$(COMMAND)
%.o: %.cpp
$(COMMAND)
答案 8 :(得分:0)
以下适用于我:
DEPS := $(OBJS:.o=.d)
-include $(DEPS)
%.o: %.cpp
$(CXX) $(CFLAGS) -MMD -c -o $@ $<
答案 9 :(得分:0)
Sophie 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 与