如何根据各自的头文件构建多个源文件依赖于Makefile?

时间:2014-05-29 08:02:33

标签: c++ unix sed makefile gnu-make

我发现使用make实用程序为源文件生成标头依赖项makefile并使用此构建库或相应地创建可执行文件时,我发现它很模糊。

1)

如手册中所述:

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

我尝试了那里提到的方法(在我的情况下,依赖文件存在于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尚不清楚。

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

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

编辑:(正如评论中所建议的那样) 在使用-MMD和-MP的第二种方法中,它按预期工作,但我无法理解它是如何工作的。这里不需要sed comamnd,如果相关标头被修改,则源会重建:

obj /%。o:%。c         g ++ -MMD -MP $ {CPPFLAGS} $ {INC_FLAGS} -c $$&lt; -o $$ @

但如gcc manual page中所述,如果我没有解释错误-MMD用于生成依赖项(不包括系统头)文件,-MP用于为每个标题生成空规则,但它只修改对象规则: 即,

obj/%.o obj/%.d : %.cpp(这就是在GNU make manual中提到的sed所做的事情)

或类似的东西,

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

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

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

b)

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

2 个答案:

答案 0 :(得分:2)

  

但是存在obj目录,

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

  

我不明白使用sed命令。该手册解释说它将“。obj:.cpp”规则替换为“。obj .dep:.cpp”,但是如何?

特殊的make变量$*包含与目标模式匹配的词干,它将是与模式匹配的目标的一部分%

sed命令将obj/%.o:替换为obj.o obj.d:,与Make手册中的完全相同。要解释你需要如何理解sed,但这不是一个非常复杂的sed命令。

  

生成使用此依赖项文件但声明后面的错误消息:

这使得配方具有#字符,这意味着它后面的所有内容都是注释,您需要使用\#

来转义它

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

答案 1 :(得分:-1)

所以这是我为大学的一个模块编写的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