cmake rebuild_cache для * просто * подкаталога?
У меня есть проблема с медленной стадией генерации make-файлов CMake, которая похожа на этот вопрос без ответа:
CMake медленно генерирует make-файлы
Мой проект состоит из верхнего уровняCMakeLists.txt
файл, который используетadd_subdirectory()
добавлять различные подпроекты для отдельных библиотек и исполняемых компонентов.
Для данного компонентаCMakeLists.txt
Файл содержит что-то вроде:
add_library(mylib SHARED
sourceFile1.cpp
sourceFile2.cpp
...
)
Я могу собрать только содержимое этого каталога, используя:
make mylib
Если я изменюCMakeLists.txt
файл в подкаталоге (который я много делал как часть перехода с чистых Makefiles на CMake) затем запуститеmake
он корректно перезапускает CMake для обновления конфигурации, как если бы я запускалmake rebuild_cache
.
Тем не менее, я заметил, что на самом деле это перенастраиваетвсе проект. Я действительно хочу, чтобы CMake был достаточно умен, чтобы знать, что ему нужно только восстановить Makefile в текущем каталоге и подкаталогах.
Есть ли лучший способ структурировать проект CMake для достижения этой цели? Я вижу, что некоторые люди используютпроект () для каждого CMakeLists.txt в каждом подпроекте. Вообще это хорошая идея?
В качестве альтернативы / дополнительно есть ли какой-нибудь способ ускорить этап генерации 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
Под капотом это работает:
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:
Если редактировать один файл CMakeLists.txt в подкаталоге, а затем запуститьmake -n
работает:
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
Большая часть времени, по-видимому, тратится на (или между) вызовами open, access и unlink.
Длина каждой задачи довольно переменна, но их огромное количество накапливается. Я понятия не имею, что такое файлы 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)
Еще один прогон той же команды:
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
Обратите внимание, что генератор ниндзя намного быстрее (хотя все еще не блестящий). Например,
/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, так как есть ошибки, такие как:
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, довольно мало. (см. напримерЧто означают «реальный», «пользователь» и «sys» в выводе времени (1)?).
Вот что я попробовал для полноты:
export CXX_FLAGS="-O3 -ftree-vectorise -msse2"
cmake -DCMAKE_BUILD_TYPE=RELEASE
На самом деле, используя более оптимизированный CMakeделает сделать настройку быстрее, но в моем случае этогенерировать часть, которая медленная. Из времени следует, что этот шаг как-то связан с вводом / выводом.
Я решил исследовать идею Флориана о том, что использование памяти в потоке файлов для временных файлов может иметь значение.
Я решил попробовать простой маршрут и взломал 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 (CMake построен с-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