Browse Source

Merge topic 'ninja-multi-config-post-build'

98805a11ce Ninja Multi-Config: Run POST_BUILD when BYPRODUCTS don't overlap

Acked-by: Kitware Robot <[email protected]>
Merge-request: !5673
Brad King 5 years ago
parent
commit
db8e2e711a

+ 31 - 0
Help/generator/Ninja Multi-Config.rst

@@ -130,3 +130,34 @@ output config using the ``Release`` command config. The ``Release`` build of
 the ``generator`` target is called with ``Debug.txt Debug Release`` as
 arguments. The command depends on the ``Release`` builds of ``tgt1`` and
 ``tgt4``, and the ``Debug`` builds of ``tgt2`` and ``tgt3``.
+
+``PRE_BUILD``, ``PRE_LINK``, and ``POST_BUILD`` custom commands for targets
+only get run in their "native" configuration (the ``Release`` configuration in
+the ``build-Release.ninja`` file) unless they have no ``BYPRODUCTS`` or their
+``BYPRODUCTS`` are unique per config. Consider the following example:
+
+.. code-block:: cmake
+
+  add_executable(exe main.c)
+  add_custom_command(
+    TARGET exe
+    POST_BUILD
+    COMMAND ${CMAKE_COMMAND} -E echo "Running no-byproduct command"
+    )
+  add_custom_command(
+    TARGET exe
+    POST_BUILD
+    COMMAND ${CMAKE_COMMAND} -E echo "Running separate-byproduct command for $<CONFIG>"
+    BYPRODUCTS $<CONFIG>.txt
+    )
+  add_custom_command(
+    TARGET exe
+    POST_BUILD
+    COMMAND ${CMAKE_COMMAND} -E echo "Running common-byproduct command for $<CONFIG>"
+    BYPRODUCTS exe.txt
+    )
+
+In this example, if you build ``exe:Debug`` in ``build-Release.ninja``, the
+first and second custom commands get run, since their byproducts are unique
+per-config, but the last custom command does not. However, if you build
+``exe:Release`` in ``build-Release.ninja``, all three custom commands get run.

+ 6 - 7
Source/cmLocalNinjaGenerator.cxx

@@ -693,13 +693,11 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement(
   }
 }
 
-namespace {
-bool HasUniqueByproducts(cmLocalGenerator& lg,
-                         std::vector<std::string> const& byproducts,
-                         cmListFileBacktrace const& bt)
+bool cmLocalNinjaGenerator::HasUniqueByproducts(
+  std::vector<std::string> const& byproducts, cmListFileBacktrace const& bt)
 {
   std::vector<std::string> configs =
-    lg.GetMakefile()->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+    this->GetMakefile()->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
   cmGeneratorExpression ge(bt);
   for (std::string const& p : byproducts) {
     if (cmGeneratorExpression::Find(p) == std::string::npos) {
@@ -709,7 +707,7 @@ bool HasUniqueByproducts(cmLocalGenerator& lg,
     std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(p);
     for (std::string const& config : configs) {
       for (std::string const& b :
-           lg.ExpandCustomCommandOutputPaths(*cge, config)) {
+           this->ExpandCustomCommandOutputPaths(*cge, config)) {
         if (!seen.insert(b).second) {
           return false;
         }
@@ -719,6 +717,7 @@ bool HasUniqueByproducts(cmLocalGenerator& lg,
   return true;
 }
 
+namespace {
 bool HasUniqueOutputs(std::vector<cmCustomCommandGenerator> const& ccgs)
 {
   std::set<std::string> allOutputs;
@@ -746,7 +745,7 @@ std::string cmLocalNinjaGenerator::CreateUtilityOutput(
   // In Ninja Multi-Config, we can only produce cross-config utility
   // commands if all byproducts are per-config.
   if (!this->GetGlobalGenerator()->IsMultiConfig() ||
-      !HasUniqueByproducts(*this, byproducts, bt)) {
+      !this->HasUniqueByproducts(byproducts, bt)) {
     return this->cmLocalGenerator::CreateUtilityOutput(targetName, byproducts,
                                                        bt);
   }

+ 3 - 0
Source/cmLocalNinjaGenerator.h

@@ -86,6 +86,9 @@ public:
                                cmNinjaDeps& ninjaDeps,
                                const std::string& config);
 
+  bool HasUniqueByproducts(std::vector<std::string> const& byproducts,
+                           cmListFileBacktrace const& bt);
+
 protected:
   std::string ConvertToIncludeReference(
     std::string const& path,

+ 12 - 8
Source/cmNinjaNormalTargetGenerator.cxx

@@ -12,6 +12,7 @@
 #include <utility>
 
 #include <cm/memory>
+#include <cm/optional>
 #include <cm/vector>
 
 #include "cmComputeLinkInformation.h"
@@ -1238,14 +1239,17 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
   std::vector<std::string> preLinkCmdLines;
   std::vector<std::string> postBuildCmdLines;
 
-  if (config == fileConfig) {
-    std::vector<std::string>* cmdLineLists[3] = { &preLinkCmdLines,
-                                                  &preLinkCmdLines,
-                                                  &postBuildCmdLines };
-
-    for (unsigned i = 0; i != 3; ++i) {
-      for (cmCustomCommand const& cc : *cmdLists[i]) {
-        cmCustomCommandGenerator ccg(cc, config, this->GetLocalGenerator());
+  std::vector<std::string>* cmdLineLists[3] = { &preLinkCmdLines,
+                                                &preLinkCmdLines,
+                                                &postBuildCmdLines };
+
+  for (unsigned i = 0; i != 3; ++i) {
+    for (cmCustomCommand const& cc : *cmdLists[i]) {
+      if (config == fileConfig ||
+          this->GetLocalGenerator()->HasUniqueByproducts(cc.GetByproducts(),
+                                                         cc.GetBacktrace())) {
+        cmCustomCommandGenerator ccg(cc, fileConfig, this->GetLocalGenerator(),
+                                     true, config);
         localGen.AppendCustomCommandLines(ccg, *cmdLineLists[i]);
         std::vector<std::string> const& ccByproducts = ccg.GetByproducts();
         std::transform(ccByproducts.begin(), ccByproducts.end(),

+ 2 - 0
Tests/RunCMake/NinjaMultiConfig/PostBuild-debug-in-release-graph-build-stdout.txt

@@ -0,0 +1,2 @@
+Running post-build command with Debug
+Generating Debug\.txt

+ 3 - 0
Tests/RunCMake/NinjaMultiConfig/PostBuild-release-build-stdout.txt

@@ -0,0 +1,3 @@
+Running post-build command with Release
+Generating out\.txt with Release
+Generating Release\.txt

+ 6 - 0
Tests/RunCMake/NinjaMultiConfig/PostBuild.cmake

@@ -0,0 +1,6 @@
+enable_language(C)
+
+add_executable(Exe main.c)
+add_custom_command(TARGET Exe POST_BUILD COMMAND ${CMAKE_COMMAND} -E echo "Running post-build command with $<CONFIG>")
+add_custom_command(TARGET Exe POST_BUILD COMMAND ${CMAKE_COMMAND} -E echo "Generating out.txt with $<CONFIG>" BYPRODUCTS out.txt)
+add_custom_command(TARGET Exe POST_BUILD COMMAND ${CMAKE_COMMAND} -E echo "Generating $<CONFIG>.txt" BYPRODUCTS $<CONFIG>.txt)

+ 6 - 0
Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake

@@ -187,6 +187,12 @@ run_ninja(SimpleCrossConfigs clean-all-in-release-graph build-Release.ninja clea
 run_cmake_build(SimpleCrossConfigs all-all-in-release-graph Release all:all)
 run_cmake_build(SimpleCrossConfigs all-relwithdebinfo-in-release-graph Release all:RelWithDebInfo)
 
+set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/PostBuild-build)
+set(RunCMake_TEST_OPTIONS "-DCMAKE_CROSS_CONFIGS=all")
+run_cmake_configure(PostBuild)
+run_cmake_build(PostBuild release Release Exe)
+run_cmake_build(PostBuild debug-in-release-graph Release Exe:Debug)
+
 set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Framework-build)
 set(RunCMake_TEST_OPTIONS "-DCMAKE_CROSS_CONFIGS=all")
 run_cmake_configure(Framework)