C++ Makefile:自动生成二进制文件的依赖项

C++ Makefile:自动生成二进制文件的依赖项,c++,compilation,makefile,C++,Compilation,Makefile,我想“完全”自动化项目Makefile中的依赖项生成过程。到目前为止,我一直在关注自动依赖关系,它工作得非常好。只有一个问题:这只适用于头文件依赖项,因此它将自动检测bin_1.o是否依赖于头文件_1.h以及头文件_2.h。但是,我可以直接将头文件依赖项转换为对象文件依赖项。比如说,一个自动生成的依赖项文件说 bin_1.o: bin_1.cpp header_1.h header_2.h 因此,在链接步骤中,我可以立即得出结论,我需要将文件bin_1.o、header_1.o和header_

我想“完全”自动化项目Makefile中的依赖项生成过程。到目前为止,我一直在关注自动依赖关系,它工作得非常好。只有一个问题:这只适用于头文件依赖项,因此它将自动检测bin_1.o是否依赖于头文件_1.h以及头文件_2.h。但是,我可以直接将头文件依赖项转换为对象文件依赖项。比如说,一个自动生成的依赖项文件说

bin_1.o: bin_1.cpp header_1.h header_2.h
因此,在链接步骤中,我可以立即得出结论,我需要将文件bin_1.o、header_1.o和header_2.o链接在一起,以生成二进制bin_1。换句话说,bin_1对应的依赖项文件应该具有

bin_1: bin_1.o header_1.o header_2.o
这正是我努力实现的目标。上面描述的转换是由一个小型python脚本extract_dependencies.py完成的,我的Makefile的精简版本如下所示:

binaries = bin_1 bin_2 bin_3

SRCS := $(wildcard *.cpp)

all: $(binaries)

# dependencies
DEPDIR := .d
$(shell mkdir -p $(DEPDIR) >/dev/null)
DEPFLAGS = -MT $@ -MMD -MP -MF $(DEPDIR)/$*.Td

COMPILE = $(CC) $(DEPFLAGS) $(CFLAGS) -c
POSTCOMPILE = mv -f $(DEPDIR)/$*.Td $(DEPDIR)/$*.d
GENERATE_BINARY_DEPS = python extract_dependencies.py $(DEPDIR)/$*.d > $(DEPDIR)/$*.bin.d

$(DEPDIR)/%.d: ;
$(DEPDIR)/%.bin.d: ;
.PRECIOUS: $(DEPDIR)/%.d $(DEPDIR)/%.bin.d

$(binaries): % : %.o $(DEPDIR)/%.bin.d
    ${CC} ${CFLAGS} $(shell cat .d/$@.bin.d | cut -d ' ' -f 2-) ${LDFLAGS} -o $@

%.o: %.cpp
%.o: %.cpp $(DEPDIR)/%.d
    $(COMPILE) $<
    $(POSTCOMPILE)
    $(GENERATE_BINARY_DEPS)

clean:
    rm -vf *.o
    rm -vf bin_1 bin_2 bin_3

realclean:
    $(MAKE) clean
    rm -fr .d

-include $(patsubst %,$(DEPDIR)/%.d,$(basename $(SRCS)))
-include $(patsubst %,$(DEPDIR)/%.bin.d,$(basename $(SRCS)))
binaries=bin_1 bin_2 bin_3
SRCS:=$(通配符*.cpp)
全部:$(二进制文件)
#依赖关系
DEPDIR:=.d
$(shell mkdir-p$(DEPDIR)>/dev/null)
DEPFLAGS=-MT$@-MMD-MP-MF$(DEPDIR)/$*.Td
COMPILE=$(CC)$(DEPFLAGS)$(CFLAGS)-c
POSTCOMPILE=mv-f$(DEPDIR)/$*.Td$(DEPDIR)/$*.d
GENERATE\u BINARY\u DEPS=python extract\u dependencies.py$(DEPDIR)/$*.d>$(DEPDIR)/$*.bin.d
美元(DEPDIR)/%;
美元(DEPDIR)/%;
.PRECIOUS:$(DEPDIR)/%.d$(DEPDIR)/%.bin.d
$(二进制文件):%:%.o$(DEPDIR)/%.bin.d
${CC}${CFLAGS}$(shell cat.d/$@.bin.d|cut-d'-f2-${LDFLAGS}-o$@
%.o:%.cpp
%.o:%.cpp$(DEPDIR)/%.d
$(编译)$<
$(邮政编码)
$(生成二进制数据)
清洁:
rm-vf*.o
rm-vf仓1仓2仓3
realclean:
$(使)干净
rm-fr.d
-包括$(patsubst%,$(DEPDIR)/%.d,$(basename$(SRCS)))
-包括$(patsubst%,$(DEPDIR)/%.bin.d,$(basename$(SRCS)))
现在问题来了:为了让它工作,我需要运行“make”两次。生成了*.bin.d依赖项文件,但仅在第二次运行时,Make才真正“意识到”,即头文件_1.o对于bin_1也是必需的,而不仅仅是bin_1.o。在第一次运行时,它尝试将所有对象文件链接在一起,而不首先实际构建所有对象文件

有没有办法解决这个问题,我。E第一次通过时一切都好吗


谢谢

因为Make将在第一次读取整个Make文件,然后执行目标。很难一次更新%.bin.d。或者,我们可以尝试在内部触发第二个“make”,比如

ifneq ($(STAGE),2)
$(binaries): % : %.o $(DEPDIR)/%.bin.d
        @{MAKE} $(binaries) STAGE=2
else
#2nd pass
$(binaries):
        ${CC} ${CFLAGS} -o $@ $(shell cat .d/$@.bin.d | cut -d ' ' -f 2-) ${LDFLAGS}
endif

通常,头文件不应该生成任何obj文件,可以将它们包含在前提条件中(例如头文件_1.h),但不应该有头文件_1.o。请检查链接阶段是否真的需要header_u?.o。嗨,Eric,当然你是对的,但在我的代码中,我有很多类,比如class_1.h和class_1.cpp中定义的。然后,通过编译类_1.cpp生成对象文件类_1.o,但是对于链接阶段,依赖项与相应头文件的依赖项相同。很好,这是一个好的开始。我必须补充两点:1。在我的版本gnumake3.81中,我需要在第一个构建目标otherweise中使用“${Make}$@STAGE=2”,但找不到该命令。2.不幸的是,这只适用于一次只运行一个Make作业的情况(默认或选项“-j1”)。使用MAKEFLAGS环境变量中的say“-j4”,不同的实例将相互干扰,重命名.d文件等,最终崩溃。所以现在,我想我会坚持调用Make两次。。。