如何在Makefile中根据多个源文件各自的头依赖关系构建多个源代码文件

How to build multiple Source files according to their respective headers Dependency in Makefile?

本文关键字:依赖 关系 文件 源代码 构建 源文件 Makefile      更新时间:2023-10-16

我发现使用make实用程序为源文件生成头依赖项makefile并使用它相应地构建库或创建可执行文件是不明智的。

1(

如手册所示:

http://www.gnu.org/software/make/manual/html_node/Automatic-Prerequisites.html#Automatic-先决条件

我尝试了上面提到的方法(在我的例子中,依赖文件出现在obj/下(:

obj/%.d:%.cpp
    @set -e; rm -f $@; 
    g++ -MM $(CPPFLAGS) ${INC_FLAGS} $< > $@.$$$$; 
    sed 's,($*).o[ :]*,1.o $@ : ,g' < $@.$$$$ > $@; 
    rm -f $@.$$$$

但这抛出了一个shell错误:

/bin/sh: cannot create obj/xyz.d.23030: Directory nonexistent

然而,obj目录存在,我不理解sed命令的使用。该手册解释说,它将任何">.obj:.cpp"规则替换为".obj.dep:.cpp",但如何替换?

2(我还尝试了这里提到的方法:
http://mad-scientist.net/make/autodep.html

obj/%.o : %.c
    g++ -MMD ${CPPFLAGS} ${INC_FLAGS} -c $$<  -o $$@
    @cp obj/$*.d obj/$*.P; 
    sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\$$//' 
        -e '/^$$/ d' -e 's/$$/ :/' < $*.d >> $*.P; 
    rm -f $*.d

使用此依赖文件生成,但断言以下错误消息:

"/bin/sh: cannot open obj/%.P: No such file"
sed: -e expression #2, char 4: unterminated `s' command

sed的使用也不清楚。

这变得更加模糊。。。这里在第二种方法中,如果我不添加单独的规则来创建依赖文件并在创建对象时生成它们,As"g++-MP-MMD-c"会同时创建.o和.d。但是如何使用在同一命令中生成的依赖makefile再次编译.o

我感谢任何帮助我解决所发生的错误,并帮助我理解这一点。或者,请建议一些优雅的方法来做同样的事情。

编辑:(如评论中所建议的(在使用-MMD和-MP的第二种方法中,它按预期工作,但我不明白它是如何工作的。这里不需要sed comamnd,如果修改了相关的头,则源将重新生成:

对象/%.o:%.cg++-MMD-MP${CPPFLAGS}${INC_FLAGS}-c$$&lt-o$$@

但正如gcc手册页中所述,如果我没有解释错的话-MMD用于生成依赖项(不包括系统头(文件,-MP用于为每个头生成空规则,但它只修改了对象规则:即

obj/%.o obj/%.d : %.cpp(这是sed正在做的事情,正如GNU制造手册中提到的(

或者类似的东西

obj/%.o : %.cpp (list of dependent headers for particular .cpp file)

以下两个命令的用途是什么?它是如何工作的?

a( sed 's,($*).o[ :]*,1.o $@ : ,g' < $@.$$$$ > $@;

b(

sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\$$//' 
                -e '/^$$/ d' -e 's/$$/ :/' < $*.d >> $*.P;

但是存在obj目录,

显然不是。这是你需要解决的第一件事。

我不懂sed命令的用法。该手册解释说,它将任何".obj:.cpp">规则替换为".obj.dep:.cpp">,但如何替换?

特殊制造变量$*包含与目标图案匹配的词干,该词干将是目标图案% 匹配的部分

sed命令将obj/%.o:替换为obj.o obj.d:,正如Make手册所说。为了解释"如何"你需要理解sed,但它不是一个非常复杂的sed命令。

使用此依赖文件生成,但断言以下错误消息:

这个make配方有一个#字符,这意味着它是一个注释之后的所有内容,你需要用# 来转义它

但是,如果您使用GCC,只需将-MMD添加到生成对象文件的常规配方中就更容易了,这将产生.d文件作为编译的副作用,因此您不需要为.d文件单独设置目标。

所以这是我在大学为我的一个模块编写的makefile,你可以尝试使用它,当你调用make时,它会生成所有文件并链接所有文件,而不需要在文件中定义任何额外的内容。这里有很多多余的东西,但我很久以前就这样做了,但你可以把东西拿出来玩,看看你能去掉什么。希望这有帮助=(

CC=g++
WARNING_FLAGS=-Wall -Wextra -Weffc++ -Winit-self -Wmissing-include-dirs 
-Wswitch-default -Wswitch-enum -Wunused-parameter -Wstrict-overflow=5 
-Wfloat-equal -Wshadow -Wc++0x-compat -Wconversion -Wsign-conversion 
-Wmissing-declarations -Wstrict-null-sentinel -Woverloaded-virtual -Wsign-promo
-Werror -pedantic
FORMATTING_FLAGS=-fno-pretty-templates -fmessage-length=80 -fdiagnostics-show-option
CFLAGS=${WARNING_FLAGS} ${FORMATTING_FLAGS} -g -std=c++0x -pipe  -frepo
LDFLAGS=
LDLIBS=-lGL -lGLEW -lglut -lGLU -lX11 -lXi -lm -lpng
TARGET=main
OBJECTS=$(addsuffix .o, $(basename $(shell ls *.C | grep -v Test)))
HEADERS=$(addsuffix .h, $(basename $(shell ls *.h | grep -v Test)))
TEST_LDFLAGS=-lboost_unit_test_framework
TEST_LDLIBS=${LDLIBS}
TEST_TARGET=test
TEST_OBJECTS=$(addsuffix .o, $(basename $(shell ls *.C | grep -v main)))
CLEAN_TARGETS=$(addsuffix .o, $(basename $(shell ls *.C))) ${TARGET} ${TEST_TARGET} *.rpo *.gch makefile.dep
all: ${OBJECTS} 
    ${CC} ${LDFLAGS} ${LDLIBS} $^ -o ${TARGET}
test: ${TEST_OBJECTS}
    ${CC} ${TEST_LDFLAGS} ${TEST_LDLIBS} $^ -o ${TEST_TARGET}
%.o:
    ${CC} ${CFLAGS} -c ${LDFLAGS} $< -o $@
Test.o: Test.C Makefile
    ${CC} -c $< -o $@
clean:
    rm ${CLEAN_TARGETS}
makefile.dep: *.[Ch]
    for i in *.C; do gcc -std=c++0x -MM "$${i}"; done > $@
include makefile.dep