cmake的rebuild_cache为* *只是一个子目录? [英] cmake rebuild_cache for *just* a subdirectory?

查看:1212
本文介绍了cmake的rebuild_cache为* *只是一个子目录?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我和cmake的是缓慢的makefile阶段的产生是类似这样的悬而未决的问题一个问题:

CMake的速度很慢,产生的makefile

我的项目是由它使用add_subdirectory()添加各种子项目单独库和可执行组件顶级的CMakeLists.txt的。

对于给定的组件的CMakeLists.txt包含类似:

  add_library(MYLIB SHARED
  sourceFile1.cpp
  sourceFile2.cpp
  ...

我可以建立只使用该目录的内容:

 使MYLIB

如果我修改子目录中的CMakeLists.txt(我已经做了很多从单纯的Makefile向CMake迁移的一部分),然后运行使其正确地重新运行cmake的更新配置,如果我运行make rebuild_cache。
然而,我注意到,它实际上重新配置的全部项目。我真正想要的是cmake的足够聪明,知道它只需要重新生成Makefile文件在当前目录和子目录。

有没有更好的方式来一个cmake的项目结构来实现这一目标?
我看到有些人在每一个分项工程使用的项目()的每一个的CMakeLists.txt。一般来说,这是一个好主意?

或者/另外有一些方法,以加快cmake的生成步骤?(目前我有60 +)

如果你想讨论为什么CMake的本身应该或不应该能够并行运行

奖励积分(想象的 cmake的-j 的)


我已经添加了介子,生成标记作为单独一个温和赏金尚未引起足够的重视,以保证一个答案。它的这种问题,可能导致人们切换到构建系统到介子 - 构建(假设它没有类似的问题),或者类似的东西。

有可能的是,正确答案是它不能在不修改的源cmake的完成。为了赚取赏金虽然我需要在条款解释如何cmake的工程和/或它是有缺陷的。


澄清:这是的一步是在我的情况很慢。配置本身足够快,但CMake的挂起了半响输出的之间 - 配置完成的和的 - 生成完成。

有关整个缓存重建我运行:

 使-n rebuild_cache


运行CMake的再生构建系统...
使用Makefile生成器
- FOOBAR_VERSION:03年2月1日
- 配置完成
- 生成完成
- 建立文件已被写入:/家庭/鸦胆子/工作/库/艾玛/主/ cmake的
真正74.87
用户1.74
SYS 1.02

在引擎盖下这个运行:

  cmake的-H<信源目录> -B<建立目录>

我presume -B是--build的代名词
任何选项的文档中描述正确(@todo报告错误)
-H是源目录的根目录下(不一样--help的文档希望你相信)

其快速去的的配置完成输出的但是从那里缓慢:
例如。


十五时44分14秒的execve(在/ usr / local / bin目录/ cmake的
> grep的生成cmake_strace.log
> grep的配置cmake_strace.log
15时44分15秒的写入(1, - 配置做\\ n,20--配置DONE
15时45分01秒的写入(1, - 生成做的\\ n,19--生成DONE
> grep的构建文件cmake_strace.log
15点45分22秒的写入(1, - 建立文件被写入......,77--建立文件已被写入到:

如果在子目录中编辑单一的CMakeLists.txt文件
然后运行make -n运行:

  CD /家庭/项目/ cmake的&放大器;&安培;在/ usr / local / bin目录/ cmake的-H /家庭/项目/ cmake的-B /家庭/项目/ cmake的--check的构建系统CMakeFiles / Makefile.cmake 0

- 检查 - 制造 - 系统是另一个无证选项

的效果是相同的 - 再生整体构建系统而不仅仅是当前的子树。
有一个在来源和进出源码编译的之间的行为没有什么区别。

如果我运行跟踪例如:

  strace的-r cmake的--trace -H /家庭/项目/ cmake的-B /家庭/项目/ cmake的2  - ;&放大器; 1 |三通cmake_rebuild_cache.log
排序-r cmake_rebuild_cache.log | uniq的

大部分时间花在好像是(或之间)的开放,接入与放花;断开链接调用。
每个任务的长度变化很大,但它们的数量庞大的积聚。
我不知道是什么Labels.json和Labels.txt文件是关于(向CMake内部的东西)

1运行:


    49.363537 open(\"/home/projectbar/main/test/foo2bar/CMakeFiles/test2.foo2bar.testViewingSource1.dir/build.make\", O_RDONLY)= 5
     1.324777 access(\"/home/projectbar/main/test/performance/CMakeFiles/performancetest.chvcthulhu.testChvcthulhuPerformance2.dir\", R_OK)= 0
     0.907807访问(/家庭/ projectbar /主/测试/ foo2bar / CMakeFiles / test2.foo2bar.testPeripheralConnection2.dir,R_OK)= 0
     0.670272取消链接(/家庭/ projectbar /主/ src目录/ foo2bar / Foo2Bar / CMakeFiles / foo2bar_lib.dir / progress.make.tmp)= -1 ENOENT(没有这样的文件或目录)
     0.600272访问(/家庭/ projectbar /主/测试/ foo2bar / testFilesModel2.ok,R_OK)= 0
     0.599010访问(/家庭/ projectbar /主/测试/ hve2snafu / testInvalidByte2c.ok,R_OK)= 0
     0.582466读(5,OpenJDK的版本\\1.8.0_71 \\\\ nOpenJ......,1024)= 130
     0.570540 writev则(3,[{#CMake的生成的文件:不要E...,8190},{M,1}],2)= 8191
     0.553576附近(4)= 0
     0.448811 unlink(\"/home/projectbar/main/test/snafu2hve/CMakeFiles/test2.snafu2hve.testNoProbes2.dir/progress.make.tmp\") = -1 ENOENT(没有这样的文件或目录)
     0.431559访问(/家庭/ projectbar /主/ src目录/ foo2bar / Foo2Bar / CMakeFiles / foo2bar_lib.dir,R_OK)= 0
     0.408003 unlink(\"/home/projectbar/main/test/lachesis/CMakeFiles/test2.lachesis.testBadSequenceNumber1.dir/progress.make.tmp\") = -1 ENOENT(没有这样的文件或目录)
     0.407120写(4,#的一套语言的哪些......,566)= 566
     0.406674写(3,#CMake的生成的文件:不要E...,675)= 675
     0.383892读(3,ewingPeriod.cpp.o -C /家/布鲁斯......,8191)= 8191
     0.358490取消链接(/家庭/ projectbar /主/ cmake的/ CMakeFiles / mklinks.chvdiff.dir / progress.make.tmp)= -1 ENOENT(没有这样的文件或目录)

同一命令的另一种运行:


     2.009451取消链接(/家庭/ projectbar /主/ cmake的/ CMakeFiles / mklinks.lachesis.dir / Labels.json)= -1 ENOENT(没有这样的文件或目录)
)= 20
)= 19
     1.300387 access(\"/home/projectbar/main/test/chvedit/CMakeFiles/test2.chvedit.tefooultiMatchFactoringEdit2.dir\", R_OK)= 0
     1.067957 access(\"/home/projectbar/main/test/chvedit/CMakeFiles/test2.chvedit.tefooultiMatchFactoringEdit2.dir\", R_OK)= 0
)= 1
     0.885854 unlink(\"/home/projectbar/main/src/gorkyorks2bar/CMakeFiles/doxygen.correct.gorkyorks2bar.dir/Labels.json\") = -1 ENOENT(没有这样的文件或目录)
     0.854539 access(\"/home/projectbar/main/test/reportIm$p$pssions/ReportIm$p$pssions/CMakeFiles/testsuite1_reportIm$p$pssions.dir\", R_OK)= 0
     0.791741取消链接(/家庭/ projectbar /主/ cmake的/ CMakeFiles / mklinks.bar_models.dir / progress.make.tmp)= -1 ENOENT(没有这样的文件或目录)
     0.659506取消链接(/家庭/ projectbar /主/ cmake的/ CMakeFiles / mklinks.dir / progress.make.tmp)= -1 ENOENT(没有这样的文件或目录)
     0.647838取消链接(/家庭/ projectbar /主/测试/ libyar / YarModels / CMakeFiles / testsuite1_yarmodels.dir / Labels.txt)= -1 ENOENT(没有这样的文件或目录)
     0.620511 unlink(\"/home/projectbar/main/test/libyar/YarModels/CMakeFiles/testsuite1_yarmodels.dir/Labels.json\") = -1 ENOENT(没有这样的文件或目录)
     0.601942取消链接(/家庭/ projectbar /主/ cmake的/ CMakeFiles / mklinks.lachesis.dir / Labels.txt)= -1 ENOENT(没有这样的文件或目录)
     0.591871访问(/家庭/ projectbar /主/ src目录/ runbardemo / simple_demo / CMakeFiles,R_OK)= 0
     0.582448写(3,CMAKE_PROGRESS_1 = \\ n \\ n,21)= 21
     0.536947写(3,CMAKE_PROGRESS_1 = \\ n \\ n,21)= 21
     0.499758 unlink(\"/home/projectbar/main/test/foo2bar/CMakeFiles/test2.foo2bar.testInputDirectory1.dir/progress.make.tmp\") = -1 ENOENT(没有这样的文件或目录)
     0.458120 unlink(\"/home/projectbar/main/test/yak2dcs/CMakeFiles/test2.yak2dcs.testsuite2.dir/progress.make.tmp\") = -1 ENOENT(没有这样的文件或目录)
     0.448104 unlink(\"/home/projectbar/main/test/reportIm$p$pssions/CMakeFiles/test2.reportIm$p$pssions.dir/progress.make.tmp\") = -1 ENOENT(没有这样的文件或目录)
     0.444344访问(/家庭/ projectbar /主/ src目录/香蕉/ CMakeFiles / bin.bananas.dir,R_OK)= 0
     0.442685 unlink(\"/home/projectbar/main/test/rvedit/CMakeFiles/test2.rvedit.tefooissingOptionValue.dir/progress.make.tmp\") = -1 ENOENT(没有这样的文件或目录)
     0.425604 unlink(\"/home/projectbar/main/test/listdcs/CMakeFiles/test2.listdcs.testListCalls5.dir/progress.make.tmp\") = -1 ENOENT(没有这样的文件或目录)
     0.391163访问(/家庭/ projectbar /主/ src目录/ siedit / CMakeFiles / siedit.dir,R_OK)= 0
     0.362171访问(/家庭/ projectbar /主/测试/ foo2bar / CMakeFiles / test2.foo2emma.testHowResults6.dir,R_OK)= 0

请注意忍者发生器的速度要快得多(虽然还没有辉煌)
例如。

 的/ usr / bin / time会-p忍者rebuild_cache


忍者:警告:多个规则产生../src/ams2yar/ams2yar。建立涉及这一目标将是不正确的;继续反正[-w dupbuild =警告]
忍者:警告:多个规则产生../src/vox/vox。建立涉及这一目标将是不正确的;继续反正[-w dupbuild =警告]
忍者:警告:多个规则产生../src/bananas/bananas。建立涉及这一目标将是不正确的;继续反正[-w dupbuild =警告]
忍者:警告:多个规则产生../src/fidlertypes2fidlerinfo/fidlertypes2fidlerinfo。建立涉及这一目标将是不正确的;继续反正[-w dupbuild =警告]
忍者:警告:多个规则产生../src/mkrundir/mkrundir。建立涉及这一目标将是不正确的;继续反正[-w dupbuild =警告]
忍者:警告:多个规则产生../src/runyar/runyar。建立涉及这一目标将是不正确的;继续反正[-w dupbuild =警告]
忍者:警告:多个规则产生../src/runyardemo/runyardemo。建立涉及这一目标将是不正确的;继续反正[-w dupbuild =警告]
[1/1]运行CMake的再生构建系统...
发电机=忍者
- FOO_VERSION:03年2月1日
- 配置完成
- 生成完成
- 建立文件已被写入:/家庭/项目/ cmake的/编译
真正12.67
用户1.01
SYS 0.31

请注意,该项目没有完全准备好忍者但因为有这样的错误:

 忍者:警告:多个规则产生../src/runfoobardemo/runfoobardemo。建立涉及这一目标将是不正确的;继续反正[-w dupbuild =警告]

 忍者:错误:依赖循环:../src/foobar  - > ../src/foobar/CMakeFiles/foobar  - > ../src/ams2emma/foobar

待解决。这个问题实际上是关于为什么的的Makefile 的产生是缓慢的。我不知道如果问题忍者节目是有用的提示这里或红鲱鱼。


CMake的建设与更多的优化于事无补。
根据我的跟踪输出它和时间的输出是不可能的,它会。
用户时间,因此时间cmake的$ C $内度过C本身是相当低的。
(参见,例如<一个href=\"http://stackoverflow.com/questions/556405/what-do-real-user-and-sys-mean-in-the-output-of-time1\">What做实,用户和SYS意味着时间的输出(1)?)
这是我试过的完整性:

 出口CXX_FLAGS = -  O3 -ftree-vectorise -msse2
cmake的-DCMAKE_BUILD_TYPE = RELEASE

实际使用更加优化的CMake的的使配置部分快
但对我来说这是生成一部分是缓慢的。
它将从时序看来,这一步是某种I / O限制。


我决定调查弗洛里安的想法,使用文件流的内存insteam临时文件可能会有所作为。
我决定尝试简单的方法,并砍死cmake的将文件写入到的.tmp一个ramdisk来代替。
然后,我就全力以赴,并试图上产生ramdisk上

构建系统

 须藤的mkdir到/ mnt / RAMDISK
须藤挂载的tmpfs -t -o大小=512米的tmpfs的/ mnt / RAMDISK
在/ usr / bin / time会-p cmake的-H /&lt;信源&GT; -B的/ mnt / RAMDISK /编译

我很惊讶地发现,这没有区别在所有挂钟时间:

 真实59.61
用户1.55
SYS 0.62
&GT;杜-SH的/ mnt / ramdisk的/建造/
4.4M的/ mnt / ramdisk的/建造/

同样与RAMFS:

 真实51.09
用户1.58
SYS 0.50

什么可以在这里发生的事情?我猜子过程,但其子进程占用的挂钟时间,如果其中任何一个都是我不能工作了。他们看起来是很短暂的。


完整性这里是PERF一些输出(cmake的使用-fno-省略帧指针建):

  PERF记录-g --call-图矮的CMake -H&lt;信源&GT; -B&LT;建立&GT;
PERF报告-g图


样本:事件'循环',事件计数的17K(约):14363392067
  儿童自我命令共享对象符号
+ 65.23%0.00%cmake的cmake的[] do_cmake
+ 65.02%0.00%cmake的cmake的[] cmake的运行::
+ 60.32%0.00%cmake的cmake的[。]主
+ 59.82%0.00%cmake的libc-2.17.so [。] __libc_start_main
+ 57.78%0.00%cmake的cmake的[] _start
+ 55.04%0.00%cmake的cmake的[] cmGlobalUnixMakefileGenerator3 ::生成
+ 54.56%0.00%cmake的cmake的[] cmake的生成::
+ 49.90%0.00%cmake的cmake的[] cmGlobalGenerator ::生成
+ 38.87%,0.02%cmake的cmake的[] cmLocalUnixMakefileGenerator3 ::生成
+ 18.65%,0.01%cmake的cmake的[] cmMakefileTargetGenerator :: WriteTargetBuildRules
+ 17.05%,0.02%cmake的cmake的[] cmMakefile :: ExecuteCommand
+ 16.99%,0.01%cmake的cmake的[] cmMakefile :: ReadListFile
+ 16.84%,0.01%cmake的cmake的[] CMCOMMAND :: InvokeInitialPass
+ 16.79%0.00%cmake的cmake的[] cmMakefile ::配置
+ 14.71%0.00%cmake的cmake的[] cmMakefile :: ConfigureSubDirectory
+ 14.67%,0.05%cmake的cmake的[] cmMacroHelperCommand :: InvokeInitialPass
+ 14.27%,0.02%cmake的cmake的[] cmMakefileUtilityTargetGenerator :: WriteRuleFiles
+ 13.91%0.00%cmake的cmake的[] cmGlobalGenerator ::配置
+ 13.50%,0.05%cmake的cmake的[] cmOutputConverter ::转换
+ 13.48%0.00%cmake的cmake的[] cmAddSubDirectoryCommand :: InitialPass
+ 13.46%0.00%cmake的cmake的[] cmMakefile :: AddSubDirectory
+ 12.91%0.00%cmake的cmake的[] cmGlobalUnixMakefileGenerator3 ::配置
+ 12.82%0.00%cmake的cmake的[] cmake的:: ActualConfigure
+ 10.90%0.00%cmake的cmake的[] cmake的配置::
+ 10.55%,0.02%cmake的cmake的[] cmMakefileTargetGenerator :: WriteObjectRuleFiles
+ 10.35%,0.09%cmake的cmake的[] cmLocalUnixMakefileGenerator3 :: WriteMakeRule
+ 9.76%0.03%cmake的cmake的[] cmMakefileTargetGenerator :: WriteObjectBuildFile
+ 7.97%0.00%cmake的cmake的[] cmMakefileLibraryTargetGenerator :: WriteRuleFiles
+ 7.93%0.00%cmake的cmake的[] cmMakefileExecutableTargetGenerator :: WriteRuleFiles
+ 7.88%0.00%cmake的cmake的[] cmLocalUnixMakefileGenerator3 :: WriteLocalMakefile
+ 7.68%,0.02%的CMake [kernel.kallsyms] [K] sysret_audit
+ 7.60%0.05%cmake的[kernel.kallsyms] [k]的__audit_syscall_exit
+ 7.40%0.08%cmake的cmake的[] cmsys :: SystemTools :: CollapseFullPath

PERF报告-g图 - 无子女的:


+ 2.86%cmake的libc-2.17.so [。] _int_malloc
+ 2.15%cmake的libc-2.17.so [。] __memcpy_ssse3_back
+ 2.11%cmake的[kernel.kallsyms] [k]的find_next_bit
+ 1.84%cmake的libc-2.17.so [。] __memcmp_sse4_1
+ 1.83%cmake的libc-2.17.so [。] _int_free
+ 1.71%的CMake的libstdc ++。so.6.0.20 [。]的std :: __ ostream_insert>
+ 1.18%的CMake的libstdc ++。so.6.0.20 [。]的std :: basic_string的,性病::分配器> :: basic_string的〜
+ 1.13%cmake的libc-2.17.so [。]的malloc
+ 1.12%cmake的cmake的[] cmOutputConverter :: Shell__ArgumentNeedsQuotes
+ 1.11%的CMake的libstdc ++。so.6.0.20 [。]的std ::字符串::比较
+ 1.08%cmake的libc-2.17.so [。] __strlen_sse2_pminub
+ 1.05%cmake的cmake的[。]的std ::字符串:: _ S_construct
+ 1.04%cmake的cmake的[] cmsys :: SystemTools :: ConvertToUnixSlashes
+ 0.97%cmake的cmake的[] yy_get_ previous_state
+ 0.87%cmake的cmake的[] cmOutputConverter :: Shell__GetArgument
+ 0.76%的CMake的libstdc ++。so.6.0.20 [。]的std :: basic_filebuf> :: xsputn
+ 0.75%的CMake的libstdc ++。so.6.0.20 [。]的std ::字符串::大小
+ 0.75%cmake的cmake的[] cmOutputConverter :: Shell__SkipMakeVariables
+ 0.74%cmake的cmake的[] cmOutputConverter :: Shell__CharNeedsQuotesOnUnix
+ 0.73%cmake的[kernel.kallsyms] [k]的mls_sid_to_context
+ 0.72%的CMake的libstdc ++。so.6.0.20 [。]的std :: basic_string的,性病::分配器> :: basic_string的
+ 0.71%cmake的cmake的[] cmOutputConverter :: Shell__GetArgumentSize
+ 0.65%cmake的libc-2.17.so [。] malloc_consolidate
+ 0.65%cmake的[kernel.kallsyms] [k]的mls_compute_context_len
+ 0.65%cmake的cmake的[] cmOutputConverter :: Shell__CharNeedsQuotes
+ 0.64%cmake的cmake的[] cmSourceFileLocation ::匹配
+ 0.58%cmake的cmake的[] cmMakefile :: ExpandVariablesInStringNew
+ 0.57%cmake的cmake的[。]的std :: __ deque_buf_size
+ 0.56%cmake的cmake的[] cmCommandArgument_yylex
+ 0.55%cmake的cmake的[。]的std ::矢量> ::大小
+ 0.54%cmake的cmake的[] cmsys :: SystemTools :: SplitPath
+ 0.51%的CMake的libstdc ++。so.6.0.20 [。]的std :: basic_streambuf> :: xsputn


解决方案

谈到我的意见变成一个答案

回答这并不容易,因为有明确的CMake的配置和生成步骤的持续时间(除了你在你的CMakeLists.txt文件实际上呢,它如您的主机系统的许多方面,你的工具链和CMake的版本/分布您正在使用)。

所以我尽量集中在你的具体问题。

重建/重写makefile文件的只是的一个子目录?

有关启动:使用 add_subdirectory()有利于构建你的CMake code。但你要记住,你总是可以改变一个子目录的全球CMake的属性和这些子目录里面的目标可以有交叉依赖。

那么,是什么做的CMake(考虑大小写这里讨论的在一个子目录我已经摸了一把的CMakeLists.txt 文件):


  • 如果一个的CMakeLists.txt 文件被更改它通过的的CMakeLists.txt 文件再次完全hirarchy和在内存再次重建构建环境。

  • 现在,它暂时重新创建所有必需的构建/ make文件并检查他们从现有的推迟(见的 cmGeneratedFileStreamBase ::关闭()

  • 如果一个文件已经改变了它替换现有的用新

此行​​为是必要的,因为当在实际只是一个子目录的CMakeLists.txt 文件已更改,并进行了优化,prevent不必要的重建任何makefile文件甚至可以改变制作步骤(从感动makefile文件)。

有没有一些方法来加快cmake的生成步骤?

所以,是的,它确实暂时重写所有的makefile(可能是缓慢的),没有,你不能减少这种同时使用 add_subdirectory()来才有所改观子目录。

也许在CMake的自身code中的未来的一个可能的性能优化将是使用memorystreams代替文件流的临时文件。

编辑: @BruceAdams通过使用没有影响产生的makefile环境RAM磁盘测试这一点。

和肯定的,CMake的生成 cmake_check_build_system 规则做几乎一样的 rebuild_cache 规则,是所使用的 -B -H - 检查 - 制造 - 系统选项CMake的内部命令行选项,并为此无证(即使经常在我的答案之一<提到在计算器上,例如,一个href=\"http://stackoverflow.com/questions/33917454/cmake-how-to-specify-the-version-of-visual-c-to-work-with\">here).

什么帮助我以加快配置/生成是重建自己的CMake比正态分布了很多优化选项,并使用64位的工具链,而不是目前仍然分布在32位版本。

修改:这里有一些测试结果我的Windows PC上(使用100子目录/库下面发现了CMake的测试脚本)总是使用相同的MSYS环境,但同样的CMake源不同的CMake编译code:


  1. 官方的CMake 3.2.2的版本:

      $时间-p cmake的-GMSYS的Makefile..
    [...]
    真正43.93
    用户0.00
    SYS 0.03


  2. 使用的mingw32 GNU 4.8.1 我CMake的重建与3.2.2

      cmake的-DCMAKE_BUILD_TYPE =释放-DCMAKE_CXX_FLAGS = -  O3-GMSYS的Makefile..

    和获得

      $时间-p /c/temp/cmake-3.2.2/MSYS32/bin/cmake.exe -GMSYS的Makefile..
    [...]
    真正41.37
    用户0.01
    SYS 0.04

    和我的杀毒软件一样关闭

      $时间-p /c/temp/cmake-3.2.2/MSYS32/bin/cmake.exe -GMSYS的Makefile..
    [...]
    真正20.98
    用户0.00
    SYS 0.04


  3. 使用的MinGW-W64 GNU 5.3.0 我CMake的重建与3.2.2

      $ cmake的-DCMAKE_BUILD_TYPE =释放-DCMAKE_CXX_FLAGS = - 三月=本地-m64 -Ofast -flto-GMSYS的Makefile..

    和获得

      $时间-p /c/temp/cmake-3.2.2/MSYS64/bin/cmake.exe -GMSYS的Makefile..
    [...]
    真正25.59
    用户0.00
    SYS 0.04

    和我的杀毒软件一样关闭

      $时间-p /c/temp/cmake-3.2.2/MSYS64/bin/cmake.exe -GMSYS的Makefile..
    [...]
    真正6.95
    用户0.00
    SYS 0.03


要总结我看到两个主要影响:

1 :配置步骤可以通过将一个64位版本是加速和优化您的处理器平台(你肯定会找到一个共同的基础的 -march = ... -mtune = ... 所有项目的构建个人电脑)。

2日:用生成步骤大多可加速通过搜索可能的文件I / O瓶颈的CMake之外。在我的情况告诉杀毒软件不检查工具链和生成目录每个I读/写的时候真的加速的东西。

备注:我证实@BruceAdams测试结果的的编译器自动矢量(默认为 -O3 -Ofast )不能做太多约CMake的源$ C ​​$ C的在多进程/多内核上运行的能力。

有没有更好的方式来一个cmake的项目结构来实现这一目标?

是的,如果你如知道你的CMake的脚本code的某个子树刚生成一个库,并没有依赖,也可以通过把这些部分在外部项目 ExternalProject_Add()。是的,<一个href=\"http://stackoverflow.com/questions/31512485/cmake-how-to-setup-source-library-and-cmakelists-txt-dependencies\">having也有类似的担忧就的大型项目的CMake这被看作是一个很好的现代cmake的做法(见下文还引用)。

参考

我来重现问题了吗?

只是为了完整性,如果有人想对自己检查这些数字,这里是我的测试code:

  cmake_minimum_required(3.0版)项目(CMakeTest CXX)#set_property(全球房地产GLOBAL_DEPENDS_DEBUG_MODE 1)集(_idx 1)而(_idx LESS 100)
    数学(EXPR _next_idx$ {_ IDX} + 1)
    如果(NOT EXISTS$ {} CMAKE_CURRENT_SOURCE_DIR / lib目录$ {_ IDX})
        文件(MAKE_DIRECTORYLIB $ {_ IDX})
        文件(
            写LIB $ {_} IDX / lib目录$ {_} IDX .H
                INT LIB $ {_} IDX _func();
        )
        文件(
            写LIB $ {_} IDX / lib目录$ {_} IDX .CC
                的#include \\LIB $ {_ next_idx} .H \\\\ n
                INT LIB $ {_} IDX _func(){返回的lib $ {_ next_idx} _func();}
        )
        文件(
            写LIB $ {_} IDX /CMakeLists.txt
                add_library(LIB $ {_ IDX} \\LIB $ {_} IDX .CC \\)\\ n
                target_link_libraries(LIB $ {_} IDX的lib $ {_ next_idx})\\ n
                target_include_directories(LIB $ {_} IDX PUBLIC \\\\)
        )
    万一()
    add_subdirectory(LIB $ {_ IDX})
    集(_idx$ {_ next_idx})
ENDWHILE()如果(NOT EXISTS$ {} CMAKE_CURRENT_SOURCE_DIR / lib目录$ {_ IDX})
    文件(MAKE_DIRECTORYLIB $ {_ IDX})
    文件(
        写LIB $ {_} IDX / lib目录$ {_} IDX .H
            INT LIB $ {_} IDX _func();
    )
    文件(
        写LIB $ {_} IDX / lib目录$ {_} IDX .CC
            INT LIB $ {_} IDX _func(){返回0;}
    )
    文件(
        写LIB $ {_} IDX /CMakeLists.txt
            add_library(LIB $ {_ IDX} \\LIB $ {_} IDX .CC \\)\\ n
            target_include_directories(LIB $ {_} IDX PUBLIC \\\\)
    )
万一()
add_subdirectory(LIB $ {_ IDX})如果(NOT EXISTS$ {} CMAKE_CURRENT_SOURCE_DIR /main.cc)
    文件(
        WRITEmain.cc
            的#include \\lib1.h \\\\ n
            INT的main(){返回lib1_func();}
    )
万一()add_executable($ {} PROJECT_NAMEmain.cc)
target_link_libraries($ {} PROJECT_NAME LIB1)

然后 - 后的第一个 cmake的.. 制作来电 - 这样做的:

  $触摸../lib100/CMakeLists.txt
$时间-p cmake的..
- 配置完成
- 生成完成
- 建立文件被写入到:[路径这里]
真正28.89
用户0.01
SYS 0.04

I have an issue with the generation of makefiles stage of cmake being slow which is similar to this unanswered question:

CMake is slow to generate makefiles

My project is made up of a top level CMakeLists.txt which uses add_subdirectory() to add various subprojects for individual library and executable components.

For a given component the CMakeLists.txt contains something like:

add_library(mylib SHARED
  sourceFile1.cpp
  sourceFile2.cpp
  ...
)

I can build just the contents of that directory using:

make mylib

If I modify the CMakeLists.txt in the sub-directory (which I've been doing a lot as part of a migration from pure Makefiles to cmake) then run make it correctly re-runs cmake to update the configuration as if I'd run make rebuild_cache. However, I notice that it in fact reconfigures the entire project. What I really want is for cmake to be clever enough to know it only needs to regenerate the Makefile in the current directory and sub-directories.

Is there a better way to structure a cmake project to achieving this? I see some people use project() for each CMakeLists.txt in each sub-project. In general is this a good idea?

Alternatively/Additionally is there some way to speed up the generation step of cmake? (currently I have 60s+)

Bonus points if you want to discuss why cmake itself should or shouldn't be able to run in parallel (imagine a cmake -j)


I've added the meson-build tag as a modest bounty alone hasn't yet attracted enough attention to warrant an answer. Its this kind of problem that might cause people to switch to build systems to meson-build (assuming it doesn't have similar problems) or something similar.

It is possible that the correct answer is it can't be done without modifying the source to cmake. To earn the bounty though I require an explanation in terms of how cmake works and/or where it is flawed.


Clarification: It is the generation step that is slow in my case. The configure itself is quick enough but cmake hangs for a quite a while between outputting "-- Configuring done" and "-- Generating done".

For a full cache rebuild I run:

make -n rebuild_cache

Running CMake to regenerate build system...
using Makefile generator
-- FOOBAR_VERSION: 01.02.03
-- Configuring done 
-- Generating done
-- Build files have been written to: /home/brucea/work/depot/emma/main/cmake
real 74.87
user 1.74
sys 1.02

under the hood this runs:

cmake -H<source dir> -B<build dir>

I presume -B is a synonym for --build neither option is described correctly in the documentation (@todo report bug) -H is the root of the source directory (not the same as --help as the docs would have you believe)

Its fast to get to the output of "Configuring done" but slow from there: E.g.

15:44:14 execve("/usr/local/bin/cmake",
>grep Generating cmake_strace.log 
>grep "Configuring" cmake_strace.log 
15:44:15 write(1, "-- Configuring done\n", 20-- Configuring done
15:45:01 write(1, "-- Generating done\n", 19-- Generating done
>grep "Build files" cmake_strace.log 
15:45:22 write(1, "-- Build files have been written"..., 77-- Build files have been written to: 

If edit a single CMakeLists.txt file in a subdirectory then run make -n it runs:

cd /home/project/cmake && /usr/local/bin/cmake -H/home/project/cmake -B/home/project/cmake --check-build-system CMakeFiles/Makefile.cmake 0

--check-build-system is another undocumented option.

The effect is the same - regenerate the whole build system not just the current subtree. There is no difference in behaviour between an in source and and out of source build.

If I run a trace e.g.:

strace -r cmake --trace -H/home/project/cmake -B/home/project/cmake 2>&1 | tee cmake_rebuild_cache.log
sort -r cmake_rebuild_cache.log | uniq

The majority of time spent seems to be spent on (or between) open, access & unlink calls. The length of each task is quite variable but the huge number of them builds up. I have no idea what the Labels.json and Labels.txt files are about (something internal to cmake)

1 run:

    49.363537 open("/home/projectbar/main/test/foo2bar/CMakeFiles/test2.foo2bar.testViewingSource1.dir/build.make", O_RDONLY) = 5
     1.324777 access("/home/projectbar/main/test/performance/CMakeFiles/performancetest.chvcthulhu.testChvcthulhuPerformance2.dir", R_OK) = 0
     0.907807 access("/home/projectbar/main/test/foo2bar/CMakeFiles/test2.foo2bar.testPeripheralConnection2.dir", R_OK) = 0
     0.670272 unlink("/home/projectbar/main/src/foo2bar/Foo2Bar/CMakeFiles/foo2bar_lib.dir/progress.make.tmp") = -1 ENOENT (No such file or directory)
     0.600272 access("/home/projectbar/main/test/foo2bar/testFilesModel2.ok", R_OK) = 0
     0.599010 access("/home/projectbar/main/test/hve2snafu/testInvalidByte2c.ok", R_OK) = 0
     0.582466 read(5, "openjdk version \"1.8.0_71\"\nOpenJ"..., 1024) = 130
     0.570540 writev(3, [{"# CMAKE generated file: DO NOT E"..., 8190}, {"M", 1}], 2) = 8191
     0.553576 close(4)                  = 0
     0.448811 unlink("/home/projectbar/main/test/snafu2hve/CMakeFiles/test2.snafu2hve.testNoProbes2.dir/progress.make.tmp") = -1 ENOENT (No such file or directory)
     0.431559 access("/home/projectbar/main/src/foo2bar/Foo2Bar/CMakeFiles/foo2bar_lib.dir", R_OK) = 0
     0.408003 unlink("/home/projectbar/main/test/lachesis/CMakeFiles/test2.lachesis.testBadSequenceNumber1.dir/progress.make.tmp") = -1 ENOENT (No such file or directory)
     0.407120 write(4, "# The set of languages for which"..., 566) = 566
     0.406674 write(3, "# CMAKE generated file: DO NOT E"..., 675) = 675
     0.383892 read(3, "ewingPeriod.cpp.o -c /home/bruce"..., 8191) = 8191
     0.358490 unlink("/home/projectbar/main/cmake/CMakeFiles/mklinks.chvdiff.dir/progress.make.tmp") = -1 ENOENT (No such file or directory)

another run of the same command:

     2.009451 unlink("/home/projectbar/main/cmake/CMakeFiles/mklinks.lachesis.dir/Labels.json") = -1 ENOENT (No such file or directory)
) = 20
) = 19
     1.300387 access("/home/projectbar/main/test/chvedit/CMakeFiles/test2.chvedit.tefooultiMatchFactoringEdit2.dir", R_OK) = 0
     1.067957 access("/home/projectbar/main/test/chvedit/CMakeFiles/test2.chvedit.tefooultiMatchFactoringEdit2.dir", R_OK) = 0
)         = 1
     0.885854 unlink("/home/projectbar/main/src/gorkyorks2bar/CMakeFiles/doxygen.correct.gorkyorks2bar.dir/Labels.json") = -1 ENOENT (No such file or directory)
     0.854539 access("/home/projectbar/main/test/reportImpressions/ReportImpressions/CMakeFiles/testsuite1_reportImpressions.dir", R_OK) = 0
     0.791741 unlink("/home/projectbar/main/cmake/CMakeFiles/mklinks.bar_models.dir/progress.make.tmp") = -1 ENOENT (No such file or directory)
     0.659506 unlink("/home/projectbar/main/cmake/CMakeFiles/mklinks.dir/progress.make.tmp") = -1 ENOENT (No such file or directory)
     0.647838 unlink("/home/projectbar/main/test/libyar/YarModels/CMakeFiles/testsuite1_yarmodels.dir/Labels.txt") = -1 ENOENT (No such file or directory)
     0.620511 unlink("/home/projectbar/main/test/libyar/YarModels/CMakeFiles/testsuite1_yarmodels.dir/Labels.json") = -1 ENOENT (No such file or directory)
     0.601942 unlink("/home/projectbar/main/cmake/CMakeFiles/mklinks.lachesis.dir/Labels.txt") = -1 ENOENT (No such file or directory)
     0.591871 access("/home/projectbar/main/src/runbardemo/simple_demo/CMakeFiles", R_OK) = 0
     0.582448 write(3, "CMAKE_PROGRESS_1 = \n\n", 21) = 21
     0.536947 write(3, "CMAKE_PROGRESS_1 = \n\n", 21) = 21
     0.499758 unlink("/home/projectbar/main/test/foo2bar/CMakeFiles/test2.foo2bar.testInputDirectory1.dir/progress.make.tmp") = -1 ENOENT (No such file or directory)
     0.458120 unlink("/home/projectbar/main/test/yak2dcs/CMakeFiles/test2.yak2dcs.testsuite2.dir/progress.make.tmp") = -1 ENOENT (No such file or directory)
     0.448104 unlink("/home/projectbar/main/test/reportImpressions/CMakeFiles/test2.reportImpressions.dir/progress.make.tmp") = -1 ENOENT (No such file or directory)
     0.444344 access("/home/projectbar/main/src/bananas/CMakeFiles/bin.bananas.dir", R_OK) = 0
     0.442685 unlink("/home/projectbar/main/test/rvedit/CMakeFiles/test2.rvedit.tefooissingOptionValue.dir/progress.make.tmp") = -1 ENOENT (No such file or directory)
     0.425604 unlink("/home/projectbar/main/test/listdcs/CMakeFiles/test2.listdcs.testListCalls5.dir/progress.make.tmp") = -1 ENOENT (No such file or directory)
     0.391163 access("/home/projectbar/main/src/siedit/CMakeFiles/siedit.dir", R_OK) = 0
     0.362171 access("/home/projectbar/main/test/foo2bar/CMakeFiles/test2.foo2emma.testHowResults6.dir", R_OK) = 0

Note the ninja generator is much faster (though still not brilliant) E.g.

/usr/bin/time -p ninja rebuild_cache

ninja: warning: multiple rules generate ../src/ams2yar/ams2yar. builds involving this target will not be correct; continuing anyway [-w dupbuild=warn]
ninja: warning: multiple rules generate ../src/vox/vox. builds involving this target will not be correct; continuing anyway [-w dupbuild=warn]
ninja: warning: multiple rules generate ../src/bananas/bananas. builds involving this target will not be correct; continuing anyway [-w dupbuild=warn]
ninja: warning: multiple rules generate ../src/fidlertypes2fidlerinfo/fidlertypes2fidlerinfo. builds involving this target will not be correct; continuing anyway [-w dupbuild=warn]
ninja: warning: multiple rules generate ../src/mkrundir/mkrundir. builds involving this target will not be correct; continuing anyway [-w dupbuild=warn]
ninja: warning: multiple rules generate ../src/runyar/runyar. builds involving this target will not be correct; continuing anyway [-w dupbuild=warn]
ninja: warning: multiple rules generate ../src/runyardemo/runyardemo. builds involving this target will not be correct; continuing anyway [-w dupbuild=warn]
[1/1] Running CMake to regenerate build system...
Generator=Ninja
-- FOO_VERSION: 01.02.03
-- Configuring done
-- Generating done
-- Build files have been written to: /home/project/cmake/build
real 12.67
user 1.01
sys 0.31

Note that the project is not quite ready for ninja yet as there are errors like:

ninja: warning: multiple rules generate ../src/runfoobardemo/runfoobardemo. builds involving this target will not be correct; continuing anyway [-w dupbuild=warn]

and

ninja: error: dependency cycle: ../src/foobar -> ../src/foobar/CMakeFiles/foobar -> ../src/ams2emma/foobar

to be resolved. This question is really about why the Makefile generator is slow. I'm not sure if the problems ninja shows are useful hints here or red herrings.


Building cmake with more optimisations does not help. Based on my trace output it and the output of time it is unlikely that it would. The user time and therefore time spend within the cmake code itself is quite low. (see e.g. What do 'real', 'user' and 'sys' mean in the output of time(1)?) Here's what I tried for completeness:

export CXX_FLAGS="-O3 -ftree-vectorise -msse2"
cmake -DCMAKE_BUILD_TYPE=RELEASE 

Actually using a more optimised cmake does make the configure part faster but in my case it is the generate part that is slow. It would appear from the timing that this step is somehow I/O bound.


I decided to investigate Florian's idea that using memory insteam of file stream for temporary files might make a difference. I decided to try the easy route and hacked cmake to write .tmp files to a ramdisk instead. I then went the whole hog and tried generating the build system on on the ramdisk

sudo mkdir /mnt/ramdisk
sudo mount -t tmpfs -o size=512m tmpfs /mnt/ramdisk
/usr/bin/time -p cmake -H/<source> -B/mnt/ramdisk/build

I was very surprised to find this makes no difference at all to the wall clock time:

real 59.61
user 1.55
sys 0.62
>du -sh /mnt/ramdisk/build/
4.4M    /mnt/ramdisk/build/

Similarly with ramfs:

real 51.09
user 1.58
sys 0.50

What could be happening here? I was guessing sub-processes but I can't work out which sub-processes are consuming the wall clock time if any of them are. They look to be very short lived.


for completeness here is some output from perf (cmake built with -fno-omit-frame-pointer):

perf record -g --call-graph dwarf cmake -H<source> -B<build>
perf report -g graph

Samples: 17K of event 'cycles', Event count (approx.): 14363392067
  Children      Self  Command          Shared Object                 Symbol
+   65.23%     0.00%  cmake            cmake                         [.] do_cmake
+   65.02%     0.00%  cmake            cmake                         [.] cmake::Run
+   60.32%     0.00%  cmake            cmake                         [.] main
+   59.82%     0.00%  cmake            libc-2.17.so                  [.] __libc_start_main
+   57.78%     0.00%  cmake            cmake                         [.] _start
+   55.04%     0.00%  cmake            cmake                         [.] cmGlobalUnixMakefileGenerator3::Generate
+   54.56%     0.00%  cmake            cmake                         [.] cmake::Generate
+   49.90%     0.00%  cmake            cmake                         [.] cmGlobalGenerator::Generate
+   38.87%     0.02%  cmake            cmake                         [.] cmLocalUnixMakefileGenerator3::Generate
+   18.65%     0.01%  cmake            cmake                         [.] cmMakefileTargetGenerator::WriteTargetBuildRules
+   17.05%     0.02%  cmake            cmake                         [.] cmMakefile::ExecuteCommand
+   16.99%     0.01%  cmake            cmake                         [.] cmMakefile::ReadListFile
+   16.84%     0.01%  cmake            cmake                         [.] cmCommand::InvokeInitialPass
+   16.79%     0.00%  cmake            cmake                         [.] cmMakefile::Configure
+   14.71%     0.00%  cmake            cmake                         [.] cmMakefile::ConfigureSubDirectory
+   14.67%     0.05%  cmake            cmake                         [.] cmMacroHelperCommand::InvokeInitialPass
+   14.27%     0.02%  cmake            cmake                         [.] cmMakefileUtilityTargetGenerator::WriteRuleFiles
+   13.91%     0.00%  cmake            cmake                         [.] cmGlobalGenerator::Configure
+   13.50%     0.05%  cmake            cmake                         [.] cmOutputConverter::Convert
+   13.48%     0.00%  cmake            cmake                         [.] cmAddSubDirectoryCommand::InitialPass
+   13.46%     0.00%  cmake            cmake                         [.] cmMakefile::AddSubDirectory
+   12.91%     0.00%  cmake            cmake                         [.] cmGlobalUnixMakefileGenerator3::Configure
+   12.82%     0.00%  cmake            cmake                         [.] cmake::ActualConfigure
+   10.90%     0.00%  cmake            cmake                         [.] cmake::Configure
+   10.55%     0.02%  cmake            cmake                         [.] cmMakefileTargetGenerator::WriteObjectRuleFiles
+   10.35%     0.09%  cmake            cmake                         [.] cmLocalUnixMakefileGenerator3::WriteMakeRule
+    9.76%     0.03%  cmake            cmake                         [.] cmMakefileTargetGenerator::WriteObjectBuildFile
+    7.97%     0.00%  cmake            cmake                         [.] cmMakefileLibraryTargetGenerator::WriteRuleFiles
+    7.93%     0.00%  cmake            cmake                         [.] cmMakefileExecutableTargetGenerator::WriteRuleFiles
+    7.88%     0.00%  cmake            cmake                         [.] cmLocalUnixMakefileGenerator3::WriteLocalMakefile
+    7.68%     0.02%  cmake            [kernel.kallsyms]             [k] sysret_audit
+    7.60%     0.05%  cmake            [kernel.kallsyms]             [k] __audit_syscall_exit
+    7.40%     0.08%  cmake            cmake                         [.] cmsys::SystemTools::CollapseFullPath

And perf report -g graph -no-children:

+    2.86%  cmake            libc-2.17.so                  [.] _int_malloc
+    2.15%  cmake            libc-2.17.so                  [.] __memcpy_ssse3_back
+    2.11%  cmake            [kernel.kallsyms]             [k] find_next_bit
+    1.84%  cmake            libc-2.17.so                  [.] __memcmp_sse4_1
+    1.83%  cmake            libc-2.17.so                  [.] _int_free
+    1.71%  cmake            libstdc++.so.6.0.20           [.] std::__ostream_insert >
+    1.18%  cmake            libstdc++.so.6.0.20           [.] std::basic_string, std::allocator >::~basic_string
+    1.13%  cmake            libc-2.17.so                  [.] malloc
+    1.12%  cmake            cmake                         [.] cmOutputConverter::Shell__ArgumentNeedsQuotes
+    1.11%  cmake            libstdc++.so.6.0.20           [.] std::string::compare
+    1.08%  cmake            libc-2.17.so                  [.] __strlen_sse2_pminub
+    1.05%  cmake            cmake                         [.] std::string::_S_construct
+    1.04%  cmake            cmake                         [.] cmsys::SystemTools::ConvertToUnixSlashes
+    0.97%  cmake            cmake                         [.] yy_get_previous_state
+    0.87%  cmake            cmake                         [.] cmOutputConverter::Shell__GetArgument
+    0.76%  cmake            libstdc++.so.6.0.20           [.] std::basic_filebuf >::xsputn
+    0.75%  cmake            libstdc++.so.6.0.20           [.] std::string::size
+    0.75%  cmake            cmake                         [.] cmOutputConverter::Shell__SkipMakeVariables
+    0.74%  cmake            cmake                         [.] cmOutputConverter::Shell__CharNeedsQuotesOnUnix
+    0.73%  cmake            [kernel.kallsyms]             [k] mls_sid_to_context
+    0.72%  cmake            libstdc++.so.6.0.20           [.] std::basic_string, std::allocator >::basic_string
+    0.71%  cmake            cmake                         [.] cmOutputConverter::Shell__GetArgumentSize
+    0.65%  cmake            libc-2.17.so                  [.] malloc_consolidate
+    0.65%  cmake            [kernel.kallsyms]             [k] mls_compute_context_len
+    0.65%  cmake            cmake                         [.] cmOutputConverter::Shell__CharNeedsQuotes
+    0.64%  cmake            cmake                         [.] cmSourceFileLocation::Matches
+    0.58%  cmake            cmake                         [.] cmMakefile::ExpandVariablesInStringNew
+    0.57%  cmake            cmake                         [.] std::__deque_buf_size
+    0.56%  cmake            cmake                         [.] cmCommandArgument_yylex
+    0.55%  cmake            cmake                         [.] std::vector >::size
+    0.54%  cmake            cmake                         [.] cmsys::SystemTools::SplitPath
+    0.51%  cmake            libstdc++.so.6.0.20           [.] std::basic_streambuf >::xsputn

解决方案

Turning my comments into an answer

Answering this isn't easy, because there are so many aspects that define CMake's configuration and generation steps duration (besides what you actually do in your CMakeLists.txt files, it's e.g. your host system, your toolchain and which CMake version/distribution you are using).

So I try to concentrate on the specific questions you have.

Rebuild/Rewrite makefiles for just a subdirectory?

For the start: Using add_subdirectory() is good for structuring your CMake code. But you have to keep in mind that you can always change global CMake properties in a subdirectory and that targets inside those subdirectories can have cross-dependencies.

So what does CMake do (considering the "I have touched one CMakeLists.txt file in a subdirectory" case discussed here):

  • If a CMakeLists.txt file is changed it goes through the complete hirarchy of CMakeLists.txt files again and rebuilds the build environment again in memory.
  • Now it temporarily recreates all the necessary build/make files and checks if they defer from the existing ones (see cmGeneratedFileStreamBase::Close())
  • If a file has changed it replaces the existing one with the new one

This behavior is necessary because any makefile can change even when only a subdirectories CMakeLists.txt file has changed and it was optimized to prevent unnecessary rebuilds during the actual make step (from touched makefiles).

Is there some way to speed up the generation step of cmake?

So yes, it does temporarily rewrite all makefiles (which could be slow) and no, you can't minimize this while using add_subdirectory() to only the changed subdirectory.

Maybe one possible performance optimization for the future in CMake's own code would be to use memorystreams instead of filestreams for the temporary files.

Edit: @BruceAdams tested this by using a RAM disk for the generated makefile environment with no effect.

And yes, the CMake generated cmake_check_build_system rule does almost the same as the rebuild_cache rule and yes the used -B, -H and --check-build-system options are CMake internal command line options and therefor undocumented (even if often referred to on StackOverflow, e.g. in one of my answers here).

What helped me to speed-up the configuration/generation was to rebuild CMake itself with a lot more optimization options than the normal distributions and using a 64bit toolchain instead of the 32bit versions currently still distributed.

Edit: Here are some test results (using the CMake test script found below with 100 subdirectories/libraries) on my Windows PC always using the same MSYS environment but different CMake compilations of the same CMake source code:

  1. Official CMake 3.2.2 version:

    $ time -p cmake -G "MSYS Makefiles" ..
    [...]
    real 43.93
    user 0.00
    sys 0.03
    

  2. Using mingw32 and GNU 4.8.1 I rebuild CMake 3.2.2 with

    cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-O3" -G "MSYS Makefiles" ..
    

    and got

    $ time -p /c/temp/cmake-3.2.2/MSYS32/bin/cmake.exe -G "MSYS Makefiles" ..
    [...]
    real 41.37
    user 0.01
    sys 0.04
    

    and the same with my antivirus software turned off

    $ time -p /c/temp/cmake-3.2.2/MSYS32/bin/cmake.exe -G "MSYS Makefiles" ..
    [...]
    real 20.98
    user 0.00
    sys 0.04
    

  3. Using mingw-w64 and GNU 5.3.0 I rebuild CMake 3.2.2 with

    $ cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-march=native -m64 -Ofast  -flto" -G "MSYS Makefiles" ..
    

    and got

    $ time -p /c/temp/cmake-3.2.2/MSYS64/bin/cmake.exe -G "MSYS Makefiles" ..
    [...]
    real 25.59
    user 0.00
    sys 0.04
    

    and the same with my antivirus software turned off

    $ time -p /c/temp/cmake-3.2.2/MSYS64/bin/cmake.exe -G "MSYS Makefiles" ..
    [...]
    real 6.95
    user 0.00
    sys 0.03
    

To summarize I see two main influences:

1st: The configuration step can be speed-up by going for a 64bit version and optimize for your processor platform (you would certainly have to find a common base -march=... or -mtune=... for all your project's build PCs).

2nd: The generation step can mostly be speed-up by searching for possible file I/O bottlenecks outside of CMake. In my case telling the antivirus software to not check the toolchain and build directories each time I read/write to those was really speeding up things.

Remark: I confirmed @BruceAdams test results that the compilers auto-vectorization (default for -O3 or -Ofast) is not able to do much about CMake source code's ability to run in multiple processes/on multiple cores.

Is there a better way to structure a cmake project to achieving this?

Yes, if you e.g. know that a certain sub-tree of your CMake script code just generates a library and has no dependencies, you could put that part in an external project by using ExternalProject_Add(). And yes, having had similar concerns regarding large CMake projects this is seen as a good "modern cmake" practice (see also references below).

References

What I used to reproduce your problem?

Just for completeness and if someone wants to check those numbers against his own here is my test code:

cmake_minimum_required(VERSION 3.0)

project(CMakeTest CXX)

#set_property(GLOBAL PROPERTY GLOBAL_DEPENDS_DEBUG_MODE 1)

set(_idx 1)

while (_idx LESS 100)
    math(EXPR _next_idx "${_idx} + 1")
    if (NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/lib${_idx}")
        file(MAKE_DIRECTORY "lib${_idx}")
        file(
            WRITE "lib${_idx}/lib${_idx}.h" 
                "int lib${_idx}_func();"
        )
        file(
            WRITE "lib${_idx}/lib${_idx}.cc" 
                "#include \"lib${_next_idx}.h\"\n"
                "int lib${_idx}_func() { return lib${_next_idx}_func(); }"
        )
        file(
            WRITE "lib${_idx}/CMakeLists.txt" 
                "add_library(lib${_idx} \"lib${_idx}.cc\")\n"
                "target_link_libraries(lib${_idx} lib${_next_idx})\n"
                "target_include_directories(lib${_idx} PUBLIC \".\")"
        )
    endif()
    add_subdirectory("lib${_idx}")
    set(_idx "${_next_idx}")
endwhile()

if (NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/lib${_idx}")
    file(MAKE_DIRECTORY "lib${_idx}")
    file(
        WRITE "lib${_idx}/lib${_idx}.h"
            "int lib${_idx}_func();"
    )
    file(
        WRITE "lib${_idx}/lib${_idx}.cc" 
            "int lib${_idx}_func() { return 0; }"
    )
    file(
        WRITE "lib${_idx}/CMakeLists.txt" 
            "add_library(lib${_idx} \"lib${_idx}.cc\")\n"
            "target_include_directories(lib${_idx} PUBLIC \".\")"
    )
endif()
add_subdirectory("lib${_idx}")

if (NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/main.cc")
    file(
        WRITE "main.cc" 
            "#include \"lib1.h\"\n"
            "int main() { return lib1_func(); }"
    )
endif()

add_executable(${PROJECT_NAME} "main.cc")
target_link_libraries(${PROJECT_NAME} lib1)

And then - after the first cmake .. and make calls - doing:

$ touch ../lib100/CMakeLists.txt
$ time -p cmake ..
-- Configuring done
-- Generating done
-- Build files have been written to: [your path here]
real 28.89
user 0.01
sys 0.04

这篇关于cmake的rebuild_cache为* *只是一个子目录?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆