Browse Source

Genex: add_custom_command: DEPFILE supports genex

This facility is very useful for 'Ninja Multi-Config' and required
as well for future support of DEPFILE in 'Xcode' and 'Visual Studio'
generators (#20286).
Marc Chevrier 4 years ago
parent
commit
0c47b91fcc

+ 6 - 1
Help/command/add_custom_command.rst

@@ -272,7 +272,9 @@ The options are:
   .. versionadded:: 3.7
 
   Specify a ``.d`` depfile for the :generator:`Ninja` generator and
-  :ref:`Makefile Generators`.
+  :ref:`Makefile Generators`. The depfile may use "generator expressions" with
+  the syntax ``$<...>``. See the :manual:`generator-expressions(7)
+  <cmake-generator-expressions(7)>` manual for available expressions.
   A ``.d`` file holds dependencies usually emitted by the custom
   command itself.
   Using ``DEPFILE`` with other generators than :generator:`Ninja` or
@@ -281,6 +283,9 @@ The options are:
   .. versionadded:: 3.20
     Added the support of :ref:`Makefile Generators`.
 
+  .. versionadded:: 3.21
+    Added the support of :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
   If the ``DEPFILE`` argument is relative, it should be relative to
   :variable:`CMAKE_CURRENT_BINARY_DIR`, and any relative paths inside the
   ``DEPFILE`` should also be relative to :variable:`CMAKE_CURRENT_BINARY_DIR`

+ 5 - 0
Help/release/dev/add_custom_command-DEPFILE-genex.rst

@@ -0,0 +1,5 @@
+add_custom_command-DEPFILE-genex
+--------------------------------
+
+* The :command:`add_custom_command` command ``DEPFILE`` option learned to
+  support :manual:`generator expressions <cmake-generator-expressions(7)>`.

+ 20 - 1
Source/cmCustomCommandGenerator.cxx

@@ -139,6 +139,14 @@ std::vector<std::string> EvaluateOutputs(std::vector<std::string> const& paths,
   }
   return outputs;
 }
+
+std::string EvaluateDepfile(std::string const& path,
+                            cmGeneratorExpression const& ge,
+                            cmLocalGenerator* lg, std::string const& config)
+{
+  std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(path);
+  return cge->Evaluate(lg, config);
+}
 }
 
 cmCustomCommandGenerator::cmCustomCommandGenerator(
@@ -381,9 +389,20 @@ void cmCustomCommandGenerator::AppendArguments(unsigned int c,
   }
 }
 
+std::string cmCustomCommandGenerator::GetDepfile() const
+{
+  const auto& depfile = this->CC->GetDepfile();
+  if (depfile.empty()) {
+    return "";
+  }
+
+  cmGeneratorExpression ge(this->CC->GetBacktrace());
+  return EvaluateDepfile(depfile, ge, this->LG, this->OutputConfig);
+}
+
 std::string cmCustomCommandGenerator::GetFullDepfile() const
 {
-  std::string depfile = this->CC->GetDepfile();
+  std::string depfile = this->GetDepfile();
   if (depfile.empty()) {
     return "";
   }

+ 1 - 0
Source/cmCustomCommandGenerator.h

@@ -57,6 +57,7 @@ public:
   std::vector<std::string> const& GetDepends() const;
   std::set<BT<std::pair<std::string, bool>>> const& GetUtilities() const;
   bool HasOnlyEmptyCommandLines() const;
+  std::string GetDepfile() const;
   std::string GetFullDepfile() const;
   std::string GetInternalDepfile() const;
 

+ 1 - 1
Source/cmLocalNinjaGenerator.cxx

@@ -670,7 +670,7 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement(
       cmCryptoHash hash(cmCryptoHash::AlgoSHA256);
       customStep += hash.HashString(ninjaOutputs[0]).substr(0, 7);
 
-      std::string depfile = cc->GetDepfile();
+      std::string depfile = ccg.GetDepfile();
       if (!depfile.empty()) {
         switch (cc->GetCMP0116Status()) {
           case cmPolicies::WARN:

+ 4 - 4
Tests/RunCMake/BuildDepends/CustomCommandDepfile.cmake

@@ -3,15 +3,15 @@ enable_language(C)
 
 add_custom_command(
   OUTPUT topcc.c
-  DEPFILE topcc.c.d
-  COMMAND ${CMAKE_COMMAND} -DOUTFILE=${CMAKE_CURRENT_BINARY_DIR}/topcc.c -DINFILE=topccdep.txt -DDEPFILE=topcc.c.d -P "${CMAKE_CURRENT_LIST_DIR}/WriteDepfile.cmake"
+  DEPFILE topcc_$<CONFIG>.c.d
+  COMMAND ${CMAKE_COMMAND} -DOUTFILE=${CMAKE_CURRENT_BINARY_DIR}/topcc.c -DINFILE=topccdep.txt -DDEPFILE=topcc_$<CONFIG>.c.d -P "${CMAKE_CURRENT_LIST_DIR}/WriteDepfile.cmake"
   )
 add_custom_target(topcc ALL DEPENDS topcc.c)
 
 add_custom_command(
   OUTPUT topexe.c
-  DEPFILE ${CMAKE_CURRENT_BINARY_DIR}/topexe.c.d
-  COMMAND ${CMAKE_COMMAND} -DOUTFILE=topexe.c "-DINFILE=${CMAKE_CURRENT_BINARY_DIR}/topexedep.txt" -DDEPFILE=topexe.c.d -P "${CMAKE_CURRENT_LIST_DIR}/WriteDepfile.cmake"
+  DEPFILE ${CMAKE_CURRENT_BINARY_DIR}/topexe_$<CONFIG>.c.d
+  COMMAND ${CMAKE_COMMAND} -DOUTFILE=topexe.c "-DINFILE=${CMAKE_CURRENT_BINARY_DIR}/topexedep.txt" -DDEPFILE=topexe_$<CONFIG>.c.d -P "${CMAKE_CURRENT_LIST_DIR}/WriteDepfile.cmake"
   )
 add_executable(topexe "${CMAKE_CURRENT_BINARY_DIR}/topexe.c")
 

+ 6 - 1
Tests/RunCMake/Ninja/CustomCommandDepfile-check.cmake

@@ -1,5 +1,10 @@
 set(log "${RunCMake_BINARY_DIR}/CustomCommandDepfile-build/build.ninja")
 file(READ "${log}" build_file)
+
+set(RunCMake_TEST_FAILED)
 if(NOT "${build_file}" MATCHES "depfile = test\\.d")
-  set(RunCMake_TEST_FAILED "Log file:\n ${log}\ndoes not have expected line: depfile = test.d")
+  list(APPEND RunCMake_TEST_FAILED "Log file:\n ${log}\ndoes not have expected line: depfile = test.d")
+endif()
+if(NOT "${build_file}" MATCHES "depfile = test_Debug\\.d")
+  list(APPEND RunCMake_TEST_FAILED "\nLog file:\n ${log}\ndoes not have expected line: depfile = test_Debug.d")
 endif()

+ 12 - 1
Tests/RunCMake/Ninja/CustomCommandDepfile.cmake

@@ -6,6 +6,17 @@ add_custom_command(
   WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
   DEPFILE "test.d"
   )
-add_custom_target(copy ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/hello.copy.c")
+
+add_custom_command(
+  OUTPUT hello.copy2.c
+  COMMAND "${CMAKE_COMMAND}" -E copy
+          "${CMAKE_CURRENT_SOURCE_DIR}/hello.c"
+          hello.copy2.c
+  WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
+  DEPFILE "test_$<CONFIG>.d"
+  )
+
+add_custom_target(copy ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/hello.copy.c"
+  "${CMAKE_CURRENT_BINARY_DIR}/hello.copy2.c")
 
 include(CheckNoPrefixSubDir.cmake)

+ 1 - 1
Tests/RunCMake/Ninja/RunCMakeTest.cmake

@@ -67,7 +67,7 @@ run_CMP0058(WARN-by)
 run_CMP0058(NEW-no)
 run_CMP0058(NEW-by)
 
-run_cmake(CustomCommandDepfile)
+run_cmake_with_options(CustomCommandDepfile -DCMAKE_BUILD_TYPE=Debug)
 run_cmake(CustomCommandJobPool)
 run_cmake(JobPoolUsesTerminal)
 

+ 6 - 1
Tests/RunCMake/NinjaMultiConfig/CustomCommandDepfile-check.cmake

@@ -1,5 +1,10 @@
 set(log "${RunCMake_BINARY_DIR}/CustomCommandDepfile-build/CMakeFiles/impl-Debug.ninja")
 file(READ "${log}" build_file)
+
+set(RunCMake_TEST_FAILED)
 if(NOT "${build_file}" MATCHES "depfile = test\\.d")
-  set(RunCMake_TEST_FAILED "Log file:\n ${log}\ndoes not have expected line: depfile = test.d")
+  list(APPEND RunCMake_TEST_FAILED "Log file:\n ${log}\ndoes not have expected line: depfile = test.d")
+endif()
+if(NOT "${build_file}" MATCHES "depfile = test_Debug\\.d")
+  list(APPEND RunCMake_TEST_FAILED "\nLog file:\n ${log}\ndoes not have expected line: depfile = test_Debug.d")
 endif()

+ 12 - 1
Tests/RunCMake/NinjaMultiConfig/CustomCommandDepfile.cmake

@@ -6,4 +6,15 @@ add_custom_command(
   WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
   DEPFILE "test.d"
   )
-add_custom_target(copy ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/main.copy.c")
+
+add_custom_command(
+  OUTPUT main.copy2.c
+  COMMAND "${CMAKE_COMMAND}" -E copy
+          "${CMAKE_CURRENT_SOURCE_DIR}/main.c"
+          main.copy2.c
+  WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
+  DEPFILE "test_$<CONFIG>.d"
+  )
+
+add_custom_target(copy ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/main.copy.c"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/main.copy2.c")