8

CMake の makefile ステージの生成が遅いという問題があります。これは、この未回答の質問に似ています。

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
4

1 に答える 1

6

CMake の構成と生成ステップの期間を定義する非常に多くの側面があります (CMakeLists.txt ファイルで実際に行うこと以外に、ホスト システム、ツールチェーン、使用している CMake のバージョン/ディストリビューションなどです)。

だから私はあなたが持っている特定の質問に集中しようとします.

サブディレクトリだけのmakefileを再構築/再書き込みしますか?

はじめに: を使用するadd_subdirectory()と、CMake コードを構造化するのに適しています。ただし、サブディレクトリ内のグローバル CMake プロパティはいつでも変更でき、それらのサブディレクトリ内のターゲットには相互依存関係がある可能性があることに注意する必要があります。

それで、CMakeは何をしますか(CMakeLists.txtここで説明した「サブディレクトリ内の1つのファイルに触れた」ケースを考慮して):

  • CMakeLists.txtファイルが変更されると、ファイルの完全な階層を再度CMakeLists.txt調べて、メモリ内にビルド環境を再構築します。
  • これで、必要なすべてのビルド/メイク ファイルが一時的に再作成され、それらが既存のものと異なるかどうかがチェックされます (「参考文献」を参照cmGeneratedFileStreamBase::Close())。
  • ファイルが変更された場合、既存のファイルが新しいファイルに置き換えられます。

この動作が必要なのは、サブディレクトリのファイルのみが変更された場合でもメイクファイルが変更される可能性がありCMakeLists.txt、実際のmakeステップで (タッチされたメイクファイルから) 不必要な再構築を防ぐように最適化されているためです。

CMake の生成ステップを高速化する方法はありますか?

そうです、すべてのメイクファイルを一時的に書き換えます (遅くなる可能性があります)。いいえ、add_subdirectory()変更されたサブディレクトリのみを使用している間はこれを最小限に抑えることはできません。

おそらく、CMake 独自のコードで将来的に可能なパフォーマンスの最適化の 1 つは、一時ファイルにファイルストリームの代わりにメモリストリームを使用することです。

@BruceAdams は、生成されたメイクファイル環境に RAM ディスクを使用してこれをテストしましたが、効果はありませんでした。

はい、CMake で生成さcmake_check_build_systemれたルールはルールとほぼ同じであり、rebuild_cache使用されています。オプションは CMake 内部コマンド ライン オプションであるため、文書化されていません (スタック オーバーフローで頻繁に参照されている場合でも、ここでの回答の 1 つなど)。-B-H--check-build-system

構成/生成を高速化するのに役立ったのは、通常のディストリビューションよりも多くの最適化オプションを使用して CMake 自体を再構築し、現在まだ配布されている 32 ビット バージョンの代わりに 64 ビット ツールチェーンを使用することでした。

以下は、常に同じ MSYS 環境を使用しているが、同じ CMake ソース コードの異なる CMake コンパイルを使用している Windows PC でのテスト結果です (100 個のサブディレクトリ/ライブラリを含む以下の CMake テスト スクリプトを使用)。

  1. 公式の CMake 3.2.2 バージョン:

    $ time -p cmake -G "MSYS Makefiles" ..
    [...]
    real 43.93
    user 0.00
    sys 0.03
    
  2. を使用してmingw32GNU 4.8.1CMake 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
    
  3. を使用してmingw-w64GNU 5.3.0CMake 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
    

要約すると、2 つの主な影響が見られます。

第 1 : 構成ステップは、64 ビット バージョンに移行し、プロセッサ プラットフォームに合わせて最適化することで高速化できます (プロジェクトのすべてのビルド PC に共通のベース-march=...またはビルド PC を確実に見つける必要があります)。-mtune=...

2つ目: 生成ステップは、CMake の外部で起こりうるファイル I/O ボトルネックを検索することで、ほとんどの場合高速化できます。私の場合、ウイルス対策ソフトウェアにツールチェーンをチェックしないように指示し、ディレクトリを読み書きするたびにディレクトリを構築すると、実際に速度が向上しました。

注意: @BruceAdams のテスト結果を確認したところ、コンパイラの自動ベクトル化-O3(またはのデフォルト-Ofast) は、複数のプロセス/複数のコアで実行する CMake ソース コードの機能について多くのことを行うことができません。

これを達成するためにCMakeプロジェクトを構築するより良い方法はありますか?

はい、たとえば、CMake スクリプト コードの特定のサブツリーがライブラリを生成するだけで依存関係がないことがわかっている場合は、 を使用してその部分を外部プロジェクトに配置できますExternalProject_Add()。はい、大規模な CMake プロジェクトに関して同様の懸念があったため、これは優れた「最新の CMake」プラクティスと見なされています (以下の参考文献も参照)。

参考文献

あなたの問題を再現するために私が使用したもの

完全を期すために、誰かがそれらの数値を自分の数値と照合したい場合は、ここに私のテスト コードを示します。

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
于 2016-03-06T12:09:17.413 に答える