据我所知,CMake会检查源文件的时间戳,以检测它是否已过时并需要重建(以及包含它的所有文件)。在大型git存储库中切换分支时,这可能会导致问题。
假设我有一个源文件夹和两个构建目录(build1和build2),它们对应两个不同的分支(branch1和branch2)
project
+-- src
+-- branch1_build
+-- branch2_build
假设我的两个分支在几个文件中几乎没有差异;大多数情况下,它们仅对某些配置选项有所不同,所有配置选项都封装在config.h
文件中,由cmake中的CONFIGURE_FILE
命令生成。两个config.h
文件(config.h.in
,因为它经常被调用)的源文件是不同的。例如,一个分支引入了一个新的子文件夹,可以使用config-time选项激活该子文件夹,该子文件夹放在config.h.in
中,类似#cmakedefine HAVE_NEW_FEATURE_FOLDER
。在这种情况下,当切换源文件夹中的分支时,会发生这种情况:cmake识别出config.h.in
文件中的某些内容发生了变化,因此它再次运行;通过再次运行,它会生成一个新的config.h
文件;由于config.h
有一个新的时间戳,所有包含它的文件(直接或间接)最终都会被重新编译。
现在,如果我在源文件夹中的branch1和branch2之间切换(因为我每天都在两个分支上工作),在同一个build文件夹中发出两个连续的make
命令(branch1_build或branch2_build)将触发完整的重新编译,因为尽管config.h
内容没有改变,但它的时间戳已经改变,所以cmake标志已经改变了。
我的问题是:我有什么选择可以避免这种情况?或者,更好的措辞,我如何避免重新编译自上次构建以来实际上未更改的源构建树对,同时还最小化对源代码的更改?
我能想到的唯一解决方案是在CONFIGURE_FILE
上执行config.h.in
,输出config.h.tmp
;比较config.h.tmp
与config.h
,仅,如果不同,请将config.h.tmp
复制到config.h
。然而,这看起来很笨拙,而且过于复杂。我希望cmake已经有了这个机制,可能隐藏在CONFIGURE_FILE
的某些选项/变体中......
假设这还不可能,我想知道cmake在决定是否过时时检查特定文件的sha(而不是时间戳)会有多复杂,并将它与之前版本的sha进行比较(是的,过时这个词中有 date ,但是我们不要在这里讨论词汇讨论)。我想这会更昂贵,所以我认为,如果可能的话,这种行为不应该是默认的,并且用户应该使用谨慎这个功能,通过明确地将文件标记为 check_sha_not_time 种类的文件。在上面的示例中,用户会将config.h
标记为 check_sha_not_time ,并避免重新编译整个库。
注意0:我对cmake内部工作原理知之甚少,因此我建议使用sha而不是时间戳可能完全是疯狂的和/或不可能给出cmake实现。我为此道歉。但这就是为什么一个人在这里问问题,因为他/她不知道,对吧?
注1:我也尝试使用ccache
,但未成功。也许我需要在ccache中使用一些特定的标志或配置选项来触发此功能。
注意2:我想避免重复源文件夹。