【问题标题】:Compile files only if needing仅在需要时编译文件
【发布时间】:2012-10-03 16:29:58
【问题描述】:

我在./src 目录中有几个 cpp 和 hpp 文件。我将所有 cpp 文件编译到一个二进制文件中,比如./bin/run。我只想在需要时重新编译,即它或其标题之一已更改。

我可能可以创建 Makefile,当且仅当文件被更改时才会重新编译文件,但这很不舒服,因为我的大部分代码都在标题中。 (不会改,因为product本身就是header,cpp文件是test)。

我想在./build中存储临时的.o文件

我知道g++ -MM 函数,但我不知道如何使用它。

我很高兴看到使用不必要的make 的解决方案,但如果它们足够简单,则可以使用任何其他系统。

UPD 我会试着澄清一下,问题是什么:

可能会创建新的 cpp,可能会添加或删除包含,等等。我不想每次都编辑我的 makefile。

【问题讨论】:

  • 你为什么不想使用make?这是为了解决这个问题。
  • 为什么还不能使用make,但是对于headers,将headers设置为make目标而不是cpp文件?
  • 您可以使用SCons,它会自动确定C++代码中的依赖关系。
  • @Adam:哦。我的意思是,不是制作,我编辑了它。
  • @slugonamission,因为我不编译头文件,我编译依赖头文件的cpp,然后编辑头文件并再次编译cpp

标签: c++ build makefile


【解决方案1】:

为了解决我提到的问题(-include 不是一个好的解决方案),我使用了这样的东西:

build/%.o: %.cpp
    @$(CC) -MD -c -Wall -o $@ $<
    @cp build/$*.d build/$*.P
    @sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
         -e '/^$$/ d' -e 's/$$/ :/' < build/$*.P >> build/$*.d
    @rm build/$*.P

-include build/*.d

不需要 `%.d 规则。

编辑:

@JackKelly 有 [*cough*, *choke*] 向我展示了一种更好的方法来有效地获取相同的依赖文件:

build/%.o: %.cpp
    @$(CC) -MD -c -Wall -o $@ $<
    @$(CC) -MM -MP -Wall -o $*.d $<

-include build/*.d

是的,你可以对同一个目标有多个规则,只要其中一个有命令即可;先决条件积累。我们的想法是获取这样的文件:

file.o: file.cpp headerfile.h
headerfile.h:

第二行 (headerfile.h:) 是 headerfile.h 的规则,它没有先决条件或命令。它什么也不做,但它是一个规则,所以如果headerfile.h 缺失,Make 就满足了。

【讨论】:

  • 你能再澄清一点吗,会发生什么?如我所见,每个.o 文件都有两条规则。可以吗?将如何处理?
  • 我得到了一个非常奇怪的 .d 文件(在将 -MD 更改为 -MMD 以避免 std 头文件后,与 -MD 相同):pastebin.com/5ct1da35 我对 file.o: file.cpp[\n] file.cpp: headers 的预期是否正确?
  • 显然你可以用 -MP 选项绕过这个有趣的 sed 脚本,评论?
  • 抱歉,不是重点,我已经在不知不觉中寻找那面旗帜好几个月了,很高兴找到它
【解决方案2】:

你提到g++ -MM,它可以做你想做的事:

include $(ALLOBJ:%.o=%.d)

%.d: %.cxx
    @echo making dependencies for $<
    @g++ -MM -MP $(CXXFLAGS) $< -o $@
    @sed -i 's,$*\.o,& $@ ,g' $@

基本上,这定义了从.cxx 文件创建.d 文件的规则。反过来,include 语句需要.d 文件,该语句需要ALLOBJ 中的每个.o 文件一个。

依赖规则的最后一行是“sed 魔法”,它使依赖文件自己重新生成。如果您认为正则表达式充其量是 hack,而且通常是邪恶的,您可以use the -MT flag

【讨论】:

  • 这是一个很好的解决方案,但如果删除头文件会中断:如果foo.cpp 包含bar.h,则用户修改foo.cpp 以不使用它并删除bar.h , 然后 Make 看到 foo.d 必须更新,但不能这样做,因为 foo.dep 依赖于无法找到的 bar.h
  • 好点,我通常定义一个特殊的命令来删除这种情况下的依赖关系,但你也可以只使用-include,对吧?
  • 但是是的,我想使用-include 会更容易...如果出现其他问题可能更难调试(因为它会导致 make 忽略include 调用中的错误) .
  • 呃,好像差不多完成了。现在我对这条sed 线有疑问。我不知道sed。现在它按预期生成文件build/%name.d,代码main.o build/main.d : tests/main.cpp 不是预期的。首先我不明白这里为什么需要build/main.d,其次:我们必须在main.o 之前添加build/。您能否为此提供代码(我怀疑它是 1 sed 行)。谢谢
  • .d 文件也取决于标题:如果这些更改,则应重新构建。至于第二个问题,只需将 's,$*\.o,& $@ ,g' 替换为 's,$*\.o,build/& $@ ,g'
【解决方案3】:

一个解决方案的大纲如下:

  • 为每个源文件使用辅助依赖文件(即为foo.c创建foo.dep,为bar.dep创建bar.dep等)
  • 使用gcc -MM创建依赖文件
  • 为了强制make自动执行此操作,请使用foo.c作为foo.depfoo.o的先决条件;这需要在gcc -MM 的输出上使用一些小的sed 魔法
  • 在你的主makefile中包含所有的依赖文件;这是使这种方法成为可能的关键步骤。

最后一步写成如下:

-include $(dependency_files)

这是非常棘手但可能的;请参阅GNU make manual 了解更多信息。

【讨论】:

  • 哦,我现在看到了主要思想,我会尝试一下,谢谢,但是如果我不想明确地写 $(dependency_files) 是否有简单的方法,如果我有 @ 987654335@? (似乎不是tests/*.dep,因为其中一些可能不会在第一次构建时生成)
  • 查看@Shep 的回答(%.o=%.d 部分)
【解决方案4】:

您可以使用 Make 执行此操作,您只需在规则的敏感度列表中指定标题。例如

myfile.o: myfile.cpp
    gcc -c myfile.o myfile.cpp ${LDFLAGS}    # This is optional. make can infer this line.

变成

myfile.o: myfile.cpp myfile.h
    gcc -c myfile.o myfile.cpp ${LDFLAGS}    # Again, optional.

现在,每当myfile.h 更改时,myfile.cpp 都会重新构建。更多的标头可以用类似的方式链接起来。

【讨论】:

  • 哦,你是对的,这是可能的。但实际上我想做点什么让make 或任何其他工具为我工作
  • 嗯?您为什么要最大限度地提高您的工作量?
  • 哈,当然不是make 的最大工作量。相反,我认为在每个包含编辑后重写 dep-lists 很难,我尽量避免它
猜你喜欢
  • 1970-01-01
  • 2014-03-15
  • 2014-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-02
  • 2017-06-04
  • 1970-01-01
相关资源
最近更新 更多