'cmake rebuild_cache' für * nur * ein Unterverzeichnis?

Ich habe ein Problem mit der langsamen Erstellung von Makefiles in CMake, das dieser unbeantworteten Frage ähnelt:

CMake erzeugt nur langsam Makefiles

Mein Projekt besteht aus einer obersten EbeneCMakeLists.txt Datei, die @ verwendadd_subdirectory(), um verschiedene Unterprojekte für einzelne Bibliotheken und ausführbare Komponenten hinzuzufügen.

Für eine bestimmte Komponente ist dasCMakeLists.txt Datei enthält so etwas wie:

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

Ich kann nur den Inhalt dieses Verzeichnisses erstellen mit:

make mylib

Wenn ich das @ ändeCMakeLists.txt -Datei im Unterverzeichnis (was ich im Rahmen einer Migration von reinen Makefiles nach CMake oft getan habe), dann startemake es führt CMake korrekt neu aus, um die Konfiguration so zu aktualisieren, als ob ich @ ausführen würmake rebuild_cache.

Allerdings stelle ich fest, dass es in der Tat die @ rekonfigurie gesamtes project. Ich möchte wirklich, dass CMake klug genug ist, um zu wissen, dass es nur das Makefile im aktuellen Verzeichnis und in den Unterverzeichnissen neu generieren muss.

Gibt es eine bessere Möglichkeit, ein CMake-Projekt zu strukturieren, um dies zu erreichen? Ich sehe einige Leute @ verwendProjekt( für jede CMakeLists.txt in jedem Unterprojekt. Ist das im Allgemeinen eine gute Idee?

Alternativ / zusätzlich gibt es eine Möglichkeit, den Generierungsschritt von CMake zu beschleunigen? (zur Zeit habe ich über 60 Jahre)

Bonuspunkte, wenn Sie diskutieren möchten, warum CMake selbst parallel ausgeführt werden soll oder nicht (stellen Sie sich ein @ vcmake -j).

Ich habe das Meson-Build-Tag als bescheidene Prämie hinzugefügt, aber alleine hat es noch nicht genug Aufmerksamkeit erregt, um eine Antwort zu rechtfertigen. Es ist diese Art von Problem, das dazu führen kann, dass die Leute dazu übergehen, Systeme auf Meson-Build umzustellen (vorausgesetzt, es gibt keine ähnlichen Probleme) oder ähnliches.

Es ist möglich, dass die richtige Antwort lautet, dass dies nicht möglich ist, ohne die Quelle in CMake zu ändern. Um das Kopfgeld zu verdienen, benötige ich eine Erklärung, wie CMake funktioniert und / oder wo es fehlerhaft ist.

Klärung Es ist derGeneratio step das ist in meinem fall langsam. Die Konfiguration selbst ist schnell genug, aber CMake bleibt eine Weile zwischen der Ausgabe von @ hänge "- Konfiguration abgeschlossen" und "- Generierung abgeschlossen".

Für einen vollständigen Cache-Neuaufbau führe ich Folgendes aus:

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

Unter der Haube läuft dies:

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

Ich nehme an-B ist ein Synonym für--build. Keine der beiden Optionen ist in der Dokumentation korrekt beschrieben.-H ist das Stammverzeichnis des Quellverzeichnisses (nicht dasselbe wie--help Wie die Dokumentation vermuten lässt).

Es ist schnell zu der Ausgabe von @ zu gelang "Konfiguration abgeschlossen", aber langsam von dort:

Beispielsweise

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:

Wenn Sie eine einzelne CMakeLists.txt-Datei in einem Unterverzeichnis bearbeiten und anschließend @ ausführmake -n, es läuft

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 ist eine weitere undokumentierte Option.

Der Effekt ist der gleiche - regenerieren Sie das gesamte Build-System, nicht nur den aktuellen Teilbaum. Es gibt keinen Unterschied im Verhalten zwischen einem In-Source- und einem Out-of-Source-Build.

Wenn ich eine Ablaufverfolgung durchführe,

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

Die meiste Zeit wird offenbar für (oder zwischen) Öffnen, Zugreifen und Aufheben der Verbindung von Anrufen aufgewendet.

Die Länge jeder Aufgabe ist recht variabel, aber die große Anzahl von ihnen baut sich auf. Ich habe keine Ahnung, worum es in den Dateien Labels.json und Labels.txt geht (etwas internes in CMake).

Ein Durchgang

    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)

Weitere Ausführung desselben Befehls:

     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

Hinweis, der Ninja-Generator ist viel schneller (obwohl immer noch nicht brillant). Beispielsweise

/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

Bitte beachten Sie, dass das Projekt noch nicht für Ninja bereit ist, da es Fehler gibt wie:

ninja: warning: multiple rules generate ../src/runfoobardemo/runfoobardemo. builds involving this target will not be correct; continuing anyway [-w dupbuild=warn]

un

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

gelöst werden. Bei dieser Frage geht es wirklich darum, warum das Makefile Generator ist langsam. Ich bin mir nicht sicher, ob die Probleme, die Ninja zeigt, nützliche Hinweise oder rote Heringe sind.

Building CMake mit mehr Optimierungen hilft nicht.

ufgrund meiner Trace-Ausgabe und der Ausgabe der Zeit ist es unwahrscheinlich, dass dies der Fall ist. Die Benutzerzeit und damit der Zeitaufwand im CMake-Code selbst ist recht gering. (siehe z. B.Was bedeuten 'real', 'user' und 'sys' in der Ausgabe von time (1)?).

Hier ist, was ich der Vollständigkeit halber versucht habe:

export CXX_FLAGS="-O3 -ftree-vectorise -msse2"
cmake -DCMAKE_BUILD_TYPE=RELEASE

Aktiv mit einem optimierten CMake does mache den configure Teil schneller, aber in meinem Fall ist es dasgeneriereteil das ist langsam. Aus dem Timing ergibt sich, dass dieser Schritt irgendwie an die E / A gebunden ist.

Ich habe mich entschlossen, Florians Idee zu untersuchen, dass die Verwendung des Speicherinsteams des Dateistreams für temporäre Dateien einen Unterschied machen könnte.

Ich habe mich für den einfachen Weg entschieden und CMake gehackt, um stattdessen .tmp-Dateien auf eine RAM-Disk zu schreiben.

Ich ging dann das ganze Schwein und versuchte, das Build-System auf der RAM-Disk zu generieren:

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

Ich war sehr überrascht, dass dies für die Uhrzeit der Wanduhr überhaupt keinen Unterschied macht:

real 59.61
user 1.55
sys 0.62
>du -sh /mnt/ramdisk/build/
4.4M    /mnt/ramdisk/build/

Ähnlich wie bei ramfs:

real 51.09
user 1.58
sys 0.50

Was könnte hier passieren? Ich habe Unterprozesse erraten, aber ich kann nicht herausfinden, welche Unterprozesse die Zeit der Wanduhr verbrauchen, wenn es welche gibt. Sie scheinen sehr kurzlebig zu sein.

Der Vollständigkeit halber hier eine Ausgabe von 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

Undperf 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

Antworten auf die Frage(2)

Ihre Antwort auf die Frage