我在CMake的生成文件阶段生成缓慢方面遇到了一个问题,类似于以下未解决的问题:
CMake is slow to generate makefiles
我的项目由顶级CMakeLists.txt
文件组成,该文件使用add_subdirectory()
为单个库和可执行组件添加各种子项目。
对于给定的组件,CMakeLists.txt
文件包含以下内容:
add_library(mylib SHARED
sourceFile1.cpp
sourceFile2.cpp
...
)
我可以使用以下命令构建该目录的内容:
make mylib
如果我修改子目录中的
CMakeLists.txt
文件(作为从纯Makefile迁移到CMake的一部分,我做了很多工作),然后运行make
,它将正确地重新运行CMake以更新配置,就像我会运行make rebuild_cache
。但是,我注意到它实际上重新配置了整个项目。我真的希望CMake足够聪明,以便知道它只需要在当前目录和子目录中重新生成Makefile。
有没有更好的方法来构建CMake项目来实现这一目标?
我看到有人在每个子项目中为每个CMakeLists.txt使用project()。总的来说,这是个好主意吗?
另外/是否有某种方法可以加快CMake的生成步骤? (目前我有60多岁)
如果您想讨论为什么CMake本身应该或不应该能够并行运行(想像
cmake -j
),则有加分。我已经添加了介子构建标记作为适度的赏金,但是仅凭它还没有引起足够的重视以提供答案。正是这种问题可能导致人们将构建系统转换为介子构建(假设它没有类似的问题)或类似的问题。
如果不将源修改为CMake,就可能无法正确答案。为了获得赏金,尽管我需要对CMake的工作方式和/或存在缺陷的地方进行解释。
澄清:就我而言,这是缓慢的生成步骤。配置本身足够快,但是CMake在输出“-配置完成”和“-生成完成”之间挂了一段时间。
对于完整的缓存重建,我运行:
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>
我想
-B
是--build
的同义词。文档中均未正确描述这两个选项。 -H
是源目录的根目录(与您认为的文档不同,它不同于--help
)。到达“配置完成”的输出很快,但是从那里开始很慢:
例如,
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 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是另一个未公开的选项。
效果是一样的-重新生成整个构建系统,而不仅仅是当前子树。
源内构建和源外构建之间的行为没有差异。
如果我运行跟踪,例如:
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
花费的大部分时间似乎都花在了打开,访问和取消链接呼叫上(或之间)。
每个任务的时间长短不一,但是数量却很多。
我不知道Labels.json和Labels.txt文件是什么(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)
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). 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
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生成器为什么速度慢的问题。我不确定忍者显示的问题是有用的提示还是红色鲱鱼。
使用更多优化来构建CMake并没有帮助。
根据我的跟踪输出和时间输出,它不太可能。
用户时间以及因此在CMake代码本身中花费的时间非常少。
(请参见例如What do 'real', 'user' and 'sys' mean in the output of time(1)?)。
这是我为完整性所做的尝试:
export CXX_FLAGS="-O3 -ftree-vectorise -msse2"
cmake -DCMAKE_BUILD_TYPE=RELEASE
实际上,使用更优化的CMake确实会使配置部分更快,
但就我而言,生成部分的速度很慢。
从时间上看来,此步骤受I / O约束。
我决定研究Florian的想法,即使用文件流的内存临时存储文件可能会有所作为。
我决定尝试简单的方法,并入侵CMake,将.tmp文件写入RAM磁盘。
然后,我全力以赴,尝试在RAM磁盘上生成构建系统:
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
我很惊讶地发现这与挂钟时间完全没有区别:
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
这里会发生什么?我在猜测子流程,但是我无法弄清哪个子流程正在消耗挂钟时间。他们看起来寿命很短。
为了完整起见,以下是perf的一些输出(使用
-fno-omit-frame-pointer
构建的CMake):perf record -g --call-graph dwarf cmake -H<source> -B<build>
perf report -g graph
样本:事件“周期”的17K,事件计数(大约):14363392067
儿童自我命令共享对象符号
+ 65.23%0.00%cmake cmake [。] do_cmake
+ 65.02%0.00%cmake cmake [。] cmake :: Run
+ 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 :: 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 ::配置
+ 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版本/发行版)。
因此,我尝试着重于您的特定问题。
只是为子目录重建/重写makefile?
首先:使用add_subdirectory()
可以很好地构造CMake代码。但是必须记住,您始终可以在子目录中更改全局CMake属性,并且这些子目录中的目标可能具有交叉依赖性。
因此,CMake会做什么(考虑“我在子目录中触摸过一个CMakeLists.txt
文件”的情况,在这里讨论):
如果更改了CMakeLists.txt
文件,它将再次遍历CMakeLists.txt
文件的完整层次结构,并再次在内存中重建构建环境。
现在,它会临时重新创建所有必要的构建/生成文件,并检查它们是否与现有文件有所不同(请参见cmGeneratedFileStreamBase::Close()
)。
如果文件已更改,它将用新文件替换现有文件。
此行为是必需的,因为即使仅子目录的CMakeLists.txt
文件已更改,任何makefile都可以更改,并且已对其进行了优化,以防止在实际的make
步骤中(通过触摸的makefile)进行不必要的重建。
有什么方法可以加快CMake的生成步骤吗?
因此,是的,它确实会临时重写所有makefile文件(这可能会很慢),并且不,您不能在将add_subdirectory()
仅用于更改的子目录时最小化此文件。
也许将来在CMake自己的代码中进行性能优化的一种可能是使用内存流代替临时文件的文件流。
@BruceAdams通过使用RAM磁盘对生成的Makefile环境进行了测试,没有任何效果。
是的,CMake生成的cmake_check_build_system
规则与rebuild_cache
规则几乎相同,是的,使用的-B
,-H
和--check-build-system
选项是CMake内部命令行选项,因此没有文档说明(即使经常引用)到堆栈溢出,例如在我的答案之一here中)。
帮助我加快配置/生成速度的原因在于,它使用比正常发行版更多的优化选项来重建CMake自身,并使用64位工具链而不是当前仍在发行的32位版本。
这是我的Windows PC上始终使用相同的MSYS环境,但使用相同CMake源代码的不同CMake编译的一些测试结果(使用下面的CMake测试脚本以及100个子目录/库):
CMake 3.2.2官方版本:
$ time -p cmake -G "MSYS Makefiles" ..
[...]
real 43.93
user 0.00
sys 0.03
使用
mingw32
和GNU 4.8.1
我重建CMake 3.2.2与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
并关闭了我的防病毒软件:
$ 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-w64
和GNU 5.3.0
我重建CMake 3.2.2与$ 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
并关闭了我的防病毒软件:
$ time -p /c/temp/cmake-3.2.2/MSYS64/bin/cmake.exe -G "MSYS Makefiles" ..
[...]
real 6.95
user 0.00
sys 0.03
总而言之,我看到两个主要影响:
第一个:可以通过选择64位版本并针对您的处理器平台进行优化来加快配置步骤(当然,您必须为所有项目的构建PC找到通用的
-march=...
or -mtune=...
基础)。第二:可以通过搜索CMake外部可能的文件I / O瓶颈来加快生成步骤。就我而言,告诉防病毒软件不要在每次我对它们进行读/写操作时检查工具链并建立目录,这实际上是在加快速度。
备注:我确认@BruceAdams测试结果表明,the compiler's auto-vectorization(
-O3
或-Ofast
的默认值)对CMake源代码在多个进程/多个内核上运行的能力没有太大帮助。有没有更好的方法来构建CMake项目来实现这一目标?
是的,如果您知道您的CMake脚本代码的某个子树只是生成一个库并且没有依赖关系,您可以使用
ExternalProject_Add()
将其放在外部项目中。是的,对于大型CMake项目,having had similar concerns被视为良好的“现代CMake”实践(另请参见下面的参考资料)。参考资料
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
我用来重现您的问题的内容
仅出于完整性考虑,如果有人想对照自己的号码检查这些数字,这是我的测试代码:
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
调用之后-执行以下操作:$ 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
关于build - 'cmake rebuild_cache'仅用于子目录?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35436945/