Forráskód Böngészése

genex: Add TARGET_INTERMEDIATE_DIR expression

Fixes: #27196
Martin Duffy 3 hete
szülő
commit
f195c9ef2a
22 módosított fájl, 205 hozzáadás és 3 törlés
  1. 7 0
      Help/manual/cmake-generator-expressions.7.rst
  2. 6 0
      Help/release/dev/genex-target-intermediate-dir.rst
  3. 66 0
      Source/cmGeneratorExpressionNode.cxx
  4. 7 2
      Tests/RunCMake/CMakeLists.txt
  5. 20 1
      Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake
  6. 1 0
      Tests/RunCMake/GeneratorExpression/TARGET_INTERMEDIATE_DIR-FULL.cmake
  7. 1 0
      Tests/RunCMake/GeneratorExpression/TARGET_INTERMEDIATE_DIR-SHORT.cmake
  8. 1 0
      Tests/RunCMake/GeneratorExpression/TARGET_INTERMEDIATE_DIR-Xcode-result.txt
  9. 8 0
      Tests/RunCMake/GeneratorExpression/TARGET_INTERMEDIATE_DIR-Xcode-stderr.txt
  10. 1 0
      Tests/RunCMake/GeneratorExpression/TARGET_INTERMEDIATE_DIR-Xcode.cmake
  11. 1 0
      Tests/RunCMake/GeneratorExpression/TARGET_INTERMEDIATE_DIR-bad-arg-result.txt
  12. 8 0
      Tests/RunCMake/GeneratorExpression/TARGET_INTERMEDIATE_DIR-bad-arg-stderr.txt
  13. 2 0
      Tests/RunCMake/GeneratorExpression/TARGET_INTERMEDIATE_DIR-bad-arg.cmake
  14. 1 0
      Tests/RunCMake/GeneratorExpression/TARGET_INTERMEDIATE_DIR-bad-target-result.txt
  15. 8 0
      Tests/RunCMake/GeneratorExpression/TARGET_INTERMEDIATE_DIR-bad-target-stderr.txt
  16. 2 0
      Tests/RunCMake/GeneratorExpression/TARGET_INTERMEDIATE_DIR-bad-target.cmake
  17. 46 0
      Tests/RunCMake/GeneratorExpression/TARGET_INTERMEDIATE_DIR-build-check.cmake
  18. 1 0
      Tests/RunCMake/GeneratorExpression/TARGET_INTERMEDIATE_DIR-not-a-target-result.txt
  19. 8 0
      Tests/RunCMake/GeneratorExpression/TARGET_INTERMEDIATE_DIR-not-a-target-stderr.txt
  20. 2 0
      Tests/RunCMake/GeneratorExpression/TARGET_INTERMEDIATE_DIR-not-a-target.cmake
  21. 4 0
      Tests/RunCMake/GeneratorExpression/TARGET_INTERMEDIATE_DIR.cmake
  22. 4 0
      Tests/RunCMake/GeneratorExpression/simple.c

+ 7 - 0
Help/manual/cmake-generator-expressions.7.rst

@@ -2836,6 +2836,13 @@ In the following, the phrase "the ``tgt`` filename" means the name of the
   This generator expression can e.g. be used to create a batch file using
   :command:`file(GENERATE)` which sets the PATH environment variable accordingly.
 
+.. genex:: $<TARGET_INTERMEDIATE_DIR:tgt>
+
+  .. versionadded:: 4.2
+
+  The full path to the directory where intermediate target files, such as
+  object and dependency files, are stored.
+
 Export And Install Expressions
 ------------------------------
 

+ 6 - 0
Help/release/dev/genex-target-intermediate-dir.rst

@@ -0,0 +1,6 @@
+genex-target-intermediate-dir
+-----------------------------
+
+* The :genex:`TARGET_INTERMEDIATE_DIR` generator expression was
+  added to refer to a target's intermediate files directory in
+  the build tree.

+ 66 - 0
Source/cmGeneratorExpressionNode.cxx

@@ -3252,6 +3252,71 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
   }
 } targetPropertyNode;
 
+static const struct targetIntermediateDirNode
+  : public cmGeneratorExpressionNode
+{
+  targetIntermediateDirNode() {} // NOLINT(modernize-use-equals-default)
+
+  static char const* GetErrorText(std::string const& targetName)
+  {
+    static cmsys::RegularExpression propertyNameValidator("^[A-Za-z0-9_]+$");
+    if (targetName.empty()) {
+      return "$<TARGET_INTERMEDIATE_DIR:tgt> expression requires a non-empty "
+             "target name.";
+    }
+    if (!cmGeneratorExpression::IsValidTargetName(targetName)) {
+      return "Target name not supported.";
+    }
+    return nullptr;
+  }
+
+  std::string Evaluate(
+    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
+    GeneratorExpressionContent const* content,
+    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+  {
+    cmGeneratorTarget const* target = nullptr;
+    std::string targetName;
+
+    if (parameters.size() == 1) {
+      targetName = parameters[0];
+
+      if (char const* e = GetErrorText(targetName)) {
+        reportError(eval, content->GetOriginalExpression(), e);
+        return std::string();
+      }
+      cmLocalGenerator const* lg = eval->CurrentTarget
+        ? eval->CurrentTarget->GetLocalGenerator()
+        : eval->Context.LG;
+      target = lg->FindGeneratorTargetToUse(targetName);
+
+      if (!target) {
+        std::ostringstream e;
+        e << "Target \"" << targetName << "\" not found.";
+        reportError(eval, content->GetOriginalExpression(), e.str());
+        return std::string();
+      }
+      eval->AllTargets.insert(target);
+
+    } else {
+      reportError(
+        eval, content->GetOriginalExpression(),
+        "$<TARGET_INTERMEDIATE_DIR:...> expression requires one parameter");
+      return std::string();
+    }
+
+    assert(target);
+
+    if (!HasKnownObjectFileLocation(eval, content, "TARGET_INTERMEDIATE_DIR",
+                                    target)) {
+      return std::string();
+    }
+
+    return cmSystemTools::CollapseFullPath(
+      target->GetObjectDirectory(eval->Context.Config));
+  }
+} targetIntermediateDirNode;
+
 static const struct TargetNameNode : public cmGeneratorExpressionNode
 {
   TargetNameNode() {} // NOLINT(modernize-use-equals-default)
@@ -4823,6 +4888,7 @@ cmGeneratorExpressionNode const* cmGeneratorExpressionNode::GetNode(
     { "SEMICOLON", &semicolonNode },
     { "QUOTE", &quoteNode },
     { "TARGET_PROPERTY", &targetPropertyNode },
+    { "TARGET_INTERMEDIATE_DIR", &targetIntermediateDirNode },
     { "TARGET_NAME", &targetNameNode },
     { "TARGET_OBJECTS", &targetObjectsNode },
     { "TARGET_POLICY", &targetPolicyNode },

+ 7 - 2
Tests/RunCMake/CMakeLists.txt

@@ -526,8 +526,13 @@ add_RunCMake_test(GenEx-TARGET_RUNTIME_DLLS)
 add_RunCMake_test(GenEx-PATH)
 add_RunCMake_test(GenEx-PATH_EQUAL)
 add_RunCMake_test(GenEx-LIST)
-add_RunCMake_test(GeneratorExpression -DCMake_TEST_OBJC=${CMake_TEST_OBJC} -DCMake_TEST_Fortran=${CMake_TEST_Fortran}
-                                      -DCMake_TEST_CUDA=${CMake_TEST_CUDA} -DCMake_TEST_HIP=${CMake_TEST_HIP})
+add_RunCMake_test(GeneratorExpression
+  -DCMake_TEST_OBJC=${CMake_TEST_OBJC}
+  -DCMake_TEST_Fortran=${CMake_TEST_Fortran}
+  -DCMake_TEST_CUDA=${CMake_TEST_CUDA}
+  -DCMake_TEST_HIP=${CMake_TEST_HIP}
+  -DCMAKE_C_OUTPUT_EXTENSION=${CMAKE_C_OUTPUT_EXTENSION}
+)
 add_RunCMake_test(GeneratorExpressionShortCircuit)
 add_RunCMake_test(GeneratorInstance)
 add_RunCMake_test(GeneratorPlatform)

+ 20 - 1
Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake

@@ -56,7 +56,10 @@ function(run_cmake_build test)
     list(APPEND RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Release)
   endif()
 
-  run_cmake(${test})
+  block()
+    unset(RunCMake-check-file)
+    run_cmake(${test})
+  endblock()
 
   set(RunCMake_TEST_NO_CLEAN TRUE)
   run_cmake_command(${test}-build ${CMAKE_COMMAND} --build . --config Release)
@@ -138,3 +141,19 @@ run_cmake(CMP0085-WARN)
 set(RunCMake_TEST_OPTIONS -DCMAKE_POLICY_DEFAULT_CMP0085:STRING=NEW)
 run_cmake(CMP0085-NEW)
 unset(RunCMake_TEST_OPTIONS)
+
+if(RunCMake_GENERATOR STREQUAL "Xcode" AND "$ENV{CMAKE_OSX_ARCHITECTURES}" MATCHES "[;$]")
+  run_cmake(TARGET_INTERMEDIATE_DIR-Xcode)
+else()
+  block()
+    set(RunCMake-check-file TARGET_INTERMEDIATE_DIR-build-check.cmake)
+    foreach(strategy IN ITEMS SHORT FULL)
+      set(CMAKE_INTERMEDIATE_DIR_STRATEGY ${strategy})
+      set(RunCMake_TEST_OPTIONS -DCMAKE_INTERMEDIATE_DIR_STRATEGY=${strategy})
+      run_cmake_build(TARGET_INTERMEDIATE_DIR-${strategy})
+    endforeach()
+  endblock()
+endif()
+run_cmake(TARGET_INTERMEDIATE_DIR-bad-arg)
+run_cmake(TARGET_INTERMEDIATE_DIR-bad-target)
+run_cmake(TARGET_INTERMEDIATE_DIR-not-a-target)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/TARGET_INTERMEDIATE_DIR-FULL.cmake

@@ -0,0 +1 @@
+include(TARGET_INTERMEDIATE_DIR.cmake)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/TARGET_INTERMEDIATE_DIR-SHORT.cmake

@@ -0,0 +1 @@
+include(TARGET_INTERMEDIATE_DIR.cmake)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/TARGET_INTERMEDIATE_DIR-Xcode-result.txt

@@ -0,0 +1 @@
+1

+ 8 - 0
Tests/RunCMake/GeneratorExpression/TARGET_INTERMEDIATE_DIR-Xcode-stderr.txt

@@ -0,0 +1,8 @@
+CMake Error at TARGET_INTERMEDIATE_DIR\.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$\<TARGET_INTERMEDIATE_DIR:foo\>
+
+  The evaluation of the TARGET_INTERMEDIATE_DIR generator expression is only
+  suitable for consumption by CMake \(limited under Xcode with multiple
+  architectures\)\.  It is not suitable for writing out elsewhere\.

+ 1 - 0
Tests/RunCMake/GeneratorExpression/TARGET_INTERMEDIATE_DIR-Xcode.cmake

@@ -0,0 +1 @@
+include(TARGET_INTERMEDIATE_DIR.cmake)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/TARGET_INTERMEDIATE_DIR-bad-arg-result.txt

@@ -0,0 +1 @@
+1

+ 8 - 0
Tests/RunCMake/GeneratorExpression/TARGET_INTERMEDIATE_DIR-bad-arg-stderr.txt

@@ -0,0 +1,8 @@
+CMake Error at TARGET_INTERMEDIATE_DIR-bad-arg.cmake:1 \(file\):
+  Error evaluating generator expression:
+
+    \$<TARGET_INTERMEDIATE_DIR>
+
+  \$<TARGET_INTERMEDIATE_DIR> expression requires exactly one parameter.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 2 - 0
Tests/RunCMake/GeneratorExpression/TARGET_INTERMEDIATE_DIR-bad-arg.cmake

@@ -0,0 +1,2 @@
+file(GENERATE OUTPUT TARGET_INTERMEDIATE_DIR-no-arg-generated.txt
+     CONTENT "$<TARGET_INTERMEDIATE_DIR>")

+ 1 - 0
Tests/RunCMake/GeneratorExpression/TARGET_INTERMEDIATE_DIR-bad-target-result.txt

@@ -0,0 +1 @@
+1

+ 8 - 0
Tests/RunCMake/GeneratorExpression/TARGET_INTERMEDIATE_DIR-bad-target-stderr.txt

@@ -0,0 +1,8 @@
+CMake Error at TARGET_INTERMEDIATE_DIR-bad-target.cmake:1 \(file\):
+  Error evaluating generator expression:
+
+    \$<TARGET_INTERMEDIATE_DIR:!>
+
+  Target name not supported.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 2 - 0
Tests/RunCMake/GeneratorExpression/TARGET_INTERMEDIATE_DIR-bad-target.cmake

@@ -0,0 +1,2 @@
+file(GENERATE OUTPUT TARGET_INTERMEDIATE_DIR-no-arg-generated.txt
+     CONTENT "$<TARGET_INTERMEDIATE_DIR:!>")

+ 46 - 0
Tests/RunCMake/GeneratorExpression/TARGET_INTERMEDIATE_DIR-build-check.cmake

@@ -0,0 +1,46 @@
+file(READ "${RunCMake_TEST_BINARY_DIR}/TARGET_INTERMEDIATE_DIR-generated.txt" dir)
+
+# Default Case
+set(expected "foo\\.dir")
+
+# Short Object Names
+if (CMAKE_INTERMEDIATE_DIR_STRATEGY STREQUAL "SHORT")
+  if (RunCMake_GENERATOR MATCHES "Ninja|Make|Visual Studio")
+    set(expected "[\\\\/][._]o[\\\\/][0-9a-f]+")
+  endif()
+endif()
+
+# Xcode
+if (RunCMake_GENERATOR MATCHES "Xcode")
+  set(expected "foo.build")
+endif()
+
+# Append Config subdirectory
+if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  string(APPEND expected "[\\\\/]Release")
+endif()
+
+# Xcode has additional paths
+if (NOT RunCMake_GENERATOR MATCHES "Xcode")
+  string(APPEND expected "$")
+endif()
+
+if(NOT dir MATCHES "${expected}")
+  set(RunCMake_TEST_FAILED "actual content:\n [[${dir}]]\nbut expected to match:\n [[${expected}]]")
+elseif(NOT IS_DIRECTORY "${dir}")
+  set(RunCMake_TEST_FAILED "target intermediate directory does not exist: [[${dir}]]")
+else()
+  file(GLOB object_files "${dir}/*${CMAKE_C_OUTPUT_EXTENSION}")
+  if (NOT object_files)
+    set(RunCMake_TEST_FAILED "no object files found in intermediate directory: [[${dir}]]")
+  endif()
+  if (CMAKE_INTERMEDIATE_DIR_STRATEGY STREQUAL "FULL")
+    set(object_name "${dir}/simple.c${CMAKE_C_OUTPUT_EXTENSION}")
+    if (RunCMake_GENERATOR MATCHES "Xcode|Visual Studio")
+      set(object_name "${dir}/simple${CMAKE_C_OUTPUT_EXTENSION}")
+    endif()
+    if (NOT EXISTS "${object_name}")
+      set(RunCMake_TEST_FAILED "simple.c object file not found in intermediate directory: [[${dir}]]")
+    endif()
+  endif()
+endif()

+ 1 - 0
Tests/RunCMake/GeneratorExpression/TARGET_INTERMEDIATE_DIR-not-a-target-result.txt

@@ -0,0 +1 @@
+1

+ 8 - 0
Tests/RunCMake/GeneratorExpression/TARGET_INTERMEDIATE_DIR-not-a-target-stderr.txt

@@ -0,0 +1,8 @@
+CMake Error at TARGET_INTERMEDIATE_DIR-not-a-target.cmake:1 \(file\):
+  Error evaluating generator expression:
+
+    \$<TARGET_INTERMEDIATE_DIR:bar>
+
+  Target \"bar\" not found.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 2 - 0
Tests/RunCMake/GeneratorExpression/TARGET_INTERMEDIATE_DIR-not-a-target.cmake

@@ -0,0 +1,2 @@
+file(GENERATE OUTPUT TARGET_INTERMEDIATE_DIR-not-a-target-generated.txt
+     CONTENT "$<TARGET_INTERMEDIATE_DIR:bar>")

+ 4 - 0
Tests/RunCMake/GeneratorExpression/TARGET_INTERMEDIATE_DIR.cmake

@@ -0,0 +1,4 @@
+enable_language(C)
+add_executable(foo simple.c)
+file(GENERATE OUTPUT TARGET_INTERMEDIATE_DIR-generated.txt
+     CONTENT "$<TARGET_INTERMEDIATE_DIR:foo>")

+ 4 - 0
Tests/RunCMake/GeneratorExpression/simple.c

@@ -0,0 +1,4 @@
+int main(void)
+{
+  return 0;
+}