'cmake rebuild_cache'仅用于子目录? [英] 'cmake rebuild_cache' for *just* a subdirectory?

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

问题描述

我对CMake的makefile生成阶段比较慢有一个问题,类似于这个未解决的问题:

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

CMake生成makefile的速度很慢

我的项目由顶级CMakeLists.txt文件组成,该文件使用add_subdirectory()为单个库和可执行组件添加各种子项目.

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

对于给定的组件,CMakeLists.txt文件包含以下内容:

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

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

我可以使用以下命令构建该目录的内容:

I can build just the contents of that directory using:

make mylib

如果我修改子目录中的CMakeLists.txt文件(作为从纯Makefile迁移到CMake的一部分,我做了很多工作),然后运行make,它将正确地重新运行CMake以更新配置,就像我要运行make rebuild_cache.

If I modify the CMakeLists.txt file 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.

但是,我注意到它实际上重新配置了 entire 项目.我真的希望CMake足够聪明,以便知道它只需要在当前目录和子目录中重新生成Makefile.

However, I notice that it in fact reconfigures the entire project. I really want for CMake to be clever enough to know it only needs to regenerate the Makefile in the current directory and sub-directories.

是否有更好的方法来构建CMake项目来实现这一目标? 我看到有人在每个子项目的每个CMakeLists.txt中使用 project().总的来说,这是个好主意吗?

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

或者,还有其他方法可以加快CMake的生成步骤吗?(目前我有60多岁了)

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

如果您想讨论为什么CMake本身应该或不应该能够并行运行(想像cmake -j),则奖励积分.

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, but alone it hasn't yet attracted enough attention to warrant an answer. It's 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.

可能的正确答案是,如果不将源修改为CMake,就无法完成.为了获得赏金,我需要对CMake的工作方式和/或存在缺陷的地方进行解释.

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.

说明:在我的情况下,这是生成步骤,很慢.配置本身足够快,但是CMake在输出-配置完成" -生成完成" 之间挂了相当长的时间.

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

在引擎盖下运行:

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

我认为-B--build的同义词.文档中都没有正确描述这两个选项. -H是源目录的根目录(与您认为的文档不同于--help).

I presume -B is a synonym for --build. Neither option is described correctly in the documentation. -H is the root of the source directory (not the same as --help as the documentation would have you believe).

到达配置完成" 的输出很快,但是从那里开始很慢:

It's fast to get to the output of "Configuring done", but slow from there:

例如,


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:

如果在子目录中编辑单个CMakeLists.txt文件,并且 然后运行make -n,它将运行:

If editing a single CMakeLists.txt file in a subdirectory, and then running 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是另一个未记录的选项.

--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 an 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.

每个任务的长度是可变的,但是数量却很多. 我不知道Labels.json和Labels.txt文件是什么(在CMake内部).

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).

一次运行:


    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)

再次运行同一命令:


     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

请注意,Ninja生成器要快得多(尽管仍然不够出色). 例如,

Note the Ninja generator is much faster (though still not brilliant). For example,

/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

请注意,该项目尚未为Ninja做好准备,因为存在以下错误:

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]

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

待解决.这个问题实际上是关于为什么 Makefile 生成器很慢的原因.我不确定忍者显示的问题在这里是有用的提示还是在红色鲱鱼上.

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.

构建更多优化的CMake并没有帮助.

Building CMake with more optimisations does not help.

根据我的跟踪输出以及时间的输出,它不太可能. 用户时间以及因此在CMake代码本身中花费的时间非常少. (请参见例如 "real","user"和"sys"在time(1)的输出中是什么意思? ).

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

实际上使用更优化的CMake 可以使配置部分更快, 但就我而言,生成部分比较慢. 从时间上看来,此步骤某种程度上受I/O约束.

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.

我决定研究Florian的想法,即使用文件流的内存作为临时文件可能会有所作为.

I decided to investigate Florian's idea that using memory insteam of file stream for temporary files might make a difference.

我决定尝试简单的方法,并入侵CMake来将.tmp文件写入RAM磁盘.

I decided to try the easy route and hacked CMake to write .tmp files to a RAM disk instead.

然后我全力以赴,尝试在RAM磁盘上生成构建系统:

I then went the whole hog and tried generating the build system on the RAM disk:

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/

与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.

为完整起见,以下是perf的一些输出(使用-fno-omit-frame-pointer构建的CMake):

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

性能报告-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, 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

推荐答案

有很多方面定义CMake的配置和生成步骤的持续时间(除了您在CMakeLists.txt文件中实际执行的操作之外;例如,您的主机系统,您的工具链以及您使用的CMake版本/发行版.

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.

只是为子目录重建/重写Makefile?

首先:使用add_subdirectory()可以很好地构造CMake代码.但是必须记住,您始终可以在子目录中更改全局CMake属性,并且这些子目录中的目标可能具有交叉依赖性.

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.

那么CMake会做什么(考虑这里讨论的我触摸了子目录中的一个CMakeLists.txt文件"的情况):

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

  • 如果更改了CMakeLists.txt文件,它将再次遍历CMakeLists.txt文件的完整层次结构,并再次在内存中重建构建环境.
  • 现在,它会临时重新创建所有必要的build/make文件,并检查它们是否与现有文件不同(请参阅
  • If a CMakeLists.txt file is changed it goes through the complete hierarchy 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.

此行为是必需的,因为即使仅子目录的CMakeLists.txt文件已更改,任何makefile都可以更改,并且已对其进行了优化,以防止在实际的make步骤中(从触摸的makefile中)进行不必要的重建.

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

有什么方法可以加快CMake的生成步骤吗?

所以,是的,它确实会临时重写所有makefile(这可能会很慢),不,在使用add_subdirectory()仅更改的子目录时,您无法将其最小化.

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.

也许将来CMake自己的代码中可能进行的性能优化是使用内存流代替临时文件的文件流.

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.

@BruceAdams通过使用RAM磁盘对生成的Makefile环境进行了测试,没有任何效果.

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

是的,CMake生成的cmake_check_build_system规则与rebuild_cache规则几乎相同,是的,所使用的-B-H--check-build-system选项是CMake内部命令行选项,因此未记录(甚至如果经常在Stack Overflow上提及,例如在我的答案之一中

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 therefore undocumented (even if often referred to on Stack Overflow, e.g. in one of my answers here).

帮助我加快配置/生成速度的原因是,使用比正常发行版更多的优化选项来重建CMake本身,并使用64位工具链代替当前仍在分发的32位版本.

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 64-bit toolchain instead of the 32-bit versions currently still distributed.

在Windows PC上,始终使用相同的MSYS环境,但使用相同的CMake源代码的不同CMake编译,这是一些测试结果(使用下面提供的CMake测试脚本以及100个子目录/库):

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. CMake 3.2.2官方版本:

  1. Official CMake 3.2.2 version:

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

  • 使用mingw32GNU 4.8.1我用

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

    得到

    $ 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
    

  • 使用mingw-w64GNU 5.3.0我用

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

    得到

    $ 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:

    第一:可以通过选择64位版本并针对您的处理器平台进行优化来加快配置步骤(当然,您必须找到通用的基础

    1st: The configuration step can be speed-up by going for a 64-bit 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).

    第二个:大多数情况下,可以通过搜索CMake之外的文件I/O瓶颈来加快生成步骤.就我而言,告诉防病毒软件每次我对它们进行读/写操作时都不要检查工具链并建立目录,这确实可以加快速度.

    2nd: The generation step can mostly be sped 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.

    备注:我确认@BruceAdams测试结果为

    Remark: I confirmed @BruceAdams test results that the the compiler's 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.

    是否有更好的方法来构建CMake项目来实现这一目标?

    是的,如果您知道您的CMake脚本代码的某个子树只是生成一个库并且没有依赖关系,您可以使用ExternalProject_Add()将其放在外部项目中.是的,对类似问题也有类似的担忧大型CMake项目,这被视为良好的现代CMake"实践(另请参见下面的参考资料).

    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).

    参考

    • CMake Performance Tips
    • CMake: Parallel generation of make files
    • GCC: how is march different from mtune?
    • CMake: How to set up source, library and CMakeLists.txt dependencies?
    • Making CMake library accessible by other CMake packages automatically
    • Use CMake-enabled libraries in your CMake project

    我用来重现您问题的方式

    仅出于完整性考虑,如果有人想对照自己的号码检查这些数字,这是我的测试代码:

    Just for completeness and if someone wants to check those numbers against his/her 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)
    

    然后-在第一次cmake ..make调用之后-做:

    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天全站免登陆