2010-03-07 116 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列表。