CMake の makefile ステージの生成が遅いという問題があります。これは、この未回答の質問に似ています。
私のプロジェクトは、個々のライブラリおよび実行可能コンポーネントのさまざまなサブプロジェクトを追加するために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 自体が並列実行できる必要がある、またはできない理由について議論したい場合のボーナス ポイント (a を想像してくださいcmake -j
)。
私は meson-build タグをささやかな報奨金として追加しましたが、それだけではまだ答えを保証するほどの注目を集めていません. この種の問題が原因で、システムのビルドを meson-build に切り替えたり (同様の問題がないと仮定して)、または同様のものに切り替えたりする可能性があります。
ソースをCMakeに変更しないとできない、というのが正解かもしれません。賞金を獲得するには、CMake がどのように機能するか、および/またはどこに欠陥があるかについての説明が必要です。
明確化:私の場合、遅いのは生成ステップです。構成自体は十分に高速ですが、CMake は"-- Configuring done"と"-- Generating done"を出力する間にかなりの時間ハングします。
完全なキャッシュを再構築するには、次を実行します。
make -n rebuild_cache
CMake を実行してビルド システムを再生成しています... Makefile ジェネレーターの使用 -- FOOBAR_VERSION: 01.02.03 -- 設定完了 -- 生成完了 -- ビルド ファイルは次の場所に書き込まれています: /home/brucea/work/depot/emma/main/cmake 実質 74.87 ユーザー 1.74 システム 1.02
ボンネットの下でこれが実行されます:
cmake -H<source dir> -B<build dir>
-B
の同義語だと思い--build
ます。どちらのオプションもドキュメントで正しく説明されていません。-H
はソース ディレクトリのルートです (--help
ドキュメントで信じられているものとは異なります)。
"Configuring done"の出力に到達するのは高速ですが、そこからは低速です。
例えば、
15:44:14 execve("/usr/local/bin/cmake", >grep cmake_strace.log を生成しています > grep "設定中" cmake_strace.log 15:44:15 write(1, "-- 設定完了\n", 20-- 設定完了 15:45:01 write(1, "-- 生成完了\n", 19-- 生成完了 > grep "ビルドファイル" cmake_strace.log 15:45:22 write(1, "-- ビルド ファイルが書き込まれました"..., 77-- ビルド ファイルが次の場所に書き込まれました:
サブディレクトリ内の 1 つの 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 の内部的なもの)。
1 回の実行:
49.363537 open("/home/projectbar/main/test/foo2bar/CMakeFiles/test2.foo2bar.testViewingSource1.dir/build.make", O_RDONLY) = 5 1.324777 アクセス ("/home/projectbar/main/test/performance/CMakeFiles/performancetest.chvcthulhu.testChvcthulhuPerformance2.dir", R_OK) = 0 0.907807 アクセス ("/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 (そのようなファイルまたはディレクトリはありません) 0.600272 アクセス ("/home/projectbar/main/test/foo2bar/testFilesModel2.ok", R_OK) = 0 0.599010 アクセス("/home/projectbar/main/test/hve2snafu/testInvalidByte2c.ok", R_OK) = 0 0.582466 read(5, "openjdk バージョン \"1.8.0_71\"\nOpenJ"..., 1024) = 130 0.570540 writev(3, [{"# CMAKE 生成ファイル: DO NOT 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 アクセス ("/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 (そのようなファイルまたはディレクトリはありません) 0.407120 write(4, "# 対象言語のセット"..., 566) = 566 0.406674 write(3, "# CMAKE 生成ファイル: DO NOT E"..., 675) = 675 0.383892 read(3, "ewingPeriod.cpp.o -c /ホーム/ブルース"..., 8191) = 8191 0.358490 unlink("/home/projectbar/main/cmake/CMakeFiles/mklinks.chvdiff.dir/progress.make.tmp") = -1 ENOENT (そのようなファイルまたはディレクトリはありません)
同じコマンドをもう一度実行します。
2.009451 unlink("/home/projectbar/main/cmake/CMakeFiles/mklinks.lachesis.dir/Labels.json") = -1 ENOENT (そのようなファイルまたはディレクトリはありません) ) = 20 ) = 19 1.300387 アクセス ("/home/projectbar/main/test/chvedit/CMakeFiles/test2.chvedit.tefooultiMatchFactoringEdit2.dir", R_OK) = 0 1.067957 アクセス ("/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 アクセス ("/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 (そのようなファイルまたはディレクトリはありません) 0.659506 unlink("/home/projectbar/main/cmake/CMakeFiles/mklinks.dir/progress.make.tmp") = -1 ENOENT (そのようなファイルまたはディレクトリはありません) 0.647838 unlink("/home/projectbar/main/test/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 unlink("/home/projectbar/main/cmake/CMakeFiles/mklinks.lachesis.dir/Labels.txt") = -1 ENOENT (そのようなファイルまたはディレクトリはありません) 0.591871 access("/home/projectbar/main/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/reportImpressions/CMakeFiles/test2.reportImpressions.dir/progress.make.tmp") = -1 ENOENT (そのようなファイルまたはディレクトリはありません) 0.444344 アクセス ("/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 (そのようなファイルまたはディレクトリはありません) 0.425604 unlink("/home/projectbar/main/test/listdcs/CMakeFiles/test2.listdcs.testListCalls5.dir/progress.make.tmp") = -1 ENOENT (そのようなファイルまたはディレクトリはありません) 0.391163 アクセス ("/home/projectbar/main/src/siedit/CMakeFiles/siedit.dir", R_OK) = 0 0.362171 アクセス ("/home/projectbar/main/test/foo2bar/CMakeFiles/test2.foo2emma.testHowResults6.dir", R_OK) = 0
Ninja ジェネレーターははるかに高速であることに注意してください (それでも素晴らしいとは言えません)。例えば、
/usr/bin/time -p ninja rebuild_cache
ninja: 警告: 複数のルールが ../src/ams2yar/ams2yar を生成します。このターゲットを含むビルドは正しくありません。とにかく続行 [-w dupbuild=warn] ninja: 警告: 複数のルールが ../src/vox/vox を生成します。このターゲットを含むビルドは正しくありません。とにかく続行 [-w dupbuild=warn] ninja: 警告: 複数のルールが ../src/bananas/bananas を生成します。このターゲットを含むビルドは正しくありません。とにかく続行 [-w dupbuild=warn] ninja: 警告: 複数のルールが ../src/fidlertypes2fidlerinfo/fidlertypes2fidlerinfo を生成します。このターゲットを含むビルドは正しくありません。とにかく続行 [-w dupbuild=warn] ninja: 警告: 複数のルールが ../src/mkrundir/mkrundir を生成します。このターゲットを含むビルドは正しくありません。とにかく続行 [-w dupbuild=warn] ninja: 警告: 複数のルールが ../src/runyar/runyar を生成します。このターゲットを含むビルドは正しくありません。とにかく続行 [-w dupbuild=warn] ninja: 警告: 複数のルールが ../src/runyardemo/runyardemo を生成します。このターゲットを含むビルドは正しくありません。とにかく続行 [-w dupbuild=warn] [1/1] CMake を実行してビルド システムを再生成しています... ジェネレーター=忍者 -- FOO_VERSION: 01.02.03 -- 設定完了 -- 生成完了 -- ビルド ファイルは次の場所に書き込まれています: /home/project/cmake/build 実質 12.67 ユーザー 1.01 システム 0.31
次のようなエラーがあるため、プロジェクトはまだ忍者の準備が整っていないことに注意してください。
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 コード自体に費やされる時間は非常に少ないです。(例えば、time(1) の出力で「real」、「user」、および「sys」は何を意味しますか? を参照してください)。
完全を期すために私が試したのは次のとおりです。
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 からの出力を次に示します (CMake でビルド-fno-omit-frame-pointer
):
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::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
そして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