Bläddra i källkod

GenEx: add expressions related to linker

Introduce the following genex:
* <LANG>_COMPILER_LINKER_ID
* <LANG>_COMPILER_LINKER_FRONTEND_VARIANT

Fixes: #26991
Marc Chevrier 4 månader sedan
förälder
incheckning
60fb5a5792
22 ändrade filer med 578 tillägg och 3 borttagningar
  1. 205 2
      Help/manual/cmake-generator-expressions.7.rst
  2. 8 0
      Help/release/dev/GenEx-COMPILER_LINKER.rst
  3. 161 0
      Source/cmGeneratorExpressionNode.cxx
  4. 2 1
      Tests/RunCMake/CMakeLists.txt
  5. 19 0
      Tests/RunCMake/GeneratorExpression/COMPILER_LINKER.cmake
  6. 9 0
      Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.C.FRONTEND_VARIANT-stderr.txt
  7. 9 0
      Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.C.ID-stderr.txt
  8. 9 0
      Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.CUDA.FRONTEND_VARIANT-stderr.txt
  9. 9 0
      Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.CUDA.ID-stderr.txt
  10. 9 0
      Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.CXX.FRONTEND_VARIANT-stderr.txt
  11. 9 0
      Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.CXX.ID-stderr.txt
  12. 9 0
      Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.Fortran.FRONTEND_VARIANT-stderr.txt
  13. 9 0
      Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.Fortran.ID-stderr.txt
  14. 9 0
      Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.HIP.FRONTEND_VARIANT-stderr.txt
  15. 9 0
      Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.HIP.ID-stderr.txt
  16. 9 0
      Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.OBJC.FRONTEND_VARIANT-stderr.txt
  17. 9 0
      Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.OBJC.ID-stderr.txt
  18. 9 0
      Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.OBJCXX.FRONTEND_VARIANT-stderr.txt
  19. 9 0
      Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.OBJCXX.ID-stderr.txt
  20. 4 0
      Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.cmake
  21. 43 0
      Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake
  22. 10 0
      Tests/RunCMake/GeneratorExpression/compiler_linker.c

+ 205 - 2
Help/manual/cmake-generator-expressions.7.rst

@@ -1420,8 +1420,8 @@ Compile Context
   Note that for proper evaluation of this expression requires policy :policy:`CMP0099`
   to be set to ``NEW``.
 
-Linker Language And ID
-^^^^^^^^^^^^^^^^^^^^^^
+Link Language and ID
+^^^^^^^^^^^^^^^^^^^^
 
 .. genex:: $<LINK_LANGUAGE>
 
@@ -1827,6 +1827,209 @@ Link Context
   (see :genex:`$<DEVICE_LINK:list>` generator expression). This expression can
   only be used to specify link options.
 
+Linker ID and Frontend-Variant
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+See also the :variable:`CMAKE_<LANG>_COMPILER_LINKER_ID` and
+:variable:`CMAKE_<LANG>_COMPILER_LINKER_FRONTEND_VARIANT` variables, which are
+closely related to most of the expressions in this sub-section.
+
+.. genex:: $<C_COMPILER_LINKER_ID>
+
+  .. versionadded:: 4.2
+
+  CMake's linker id of the C linker used.
+
+.. genex:: $<C_COMPILER_LINKER_ID:linker_ids>
+
+  .. versionadded:: 4.2
+
+  where ``linker_ids`` is a comma-separated list.
+  ``1`` if CMake's linker id of the C linker matches any one
+  of the entries in ``linker_ids``, otherwise ``0``.
+
+.. genex:: $<CXX_COMPILER_LINKER_ID>
+
+  .. versionadded:: 4.2
+
+  CMake's linker id of the C++ linker used.
+
+.. genex:: $<CXX_COMPILER_LINKER_ID:linker_ids>
+
+  .. versionadded:: 4.2
+
+  where ``linker_ids`` is a comma-separated list.
+  ``1`` if CMake's linker id of the C++ linker matches any one
+  of the entries in ``linker_ids``, otherwise ``0``.
+
+.. genex:: $<CUDA_COMPILER_LINKER_ID>
+
+  .. versionadded:: 4.2
+
+  CMake's linker id of the CUDA linker used.
+
+.. genex:: $<CUDA_COMPILER_LINKER_ID:linker_ids>
+
+  .. versionadded:: 4.2
+
+  where ``linker_ids`` is a comma-separated list.
+  ``1`` if CMake's linker id of the CUDA linker matches any one
+  of the entries in ``linker_ids``, otherwise ``0``.
+
+.. genex:: $<OBJC_COMPILER_LINKER_ID>
+
+  .. versionadded:: 4.2
+
+  CMake's linker id of the Objective-C linker used.
+
+.. genex:: $<OBJC_COMPILER_LINKER_ID:linker_ids>
+
+  .. versionadded:: 4.2
+
+  where ``linker_ids`` is a comma-separated list.
+  ``1`` if CMake's linker id of the Objective-C linker matches any one
+  of the entries in ``linker_ids``, otherwise ``0``.
+
+.. genex:: $<OBJCXX_COMPILER_LINKER_ID>
+
+  .. versionadded:: 4.2
+
+  CMake's linker id of the Objective-C++ linker used.
+
+.. genex:: $<OBJCXX_COMPILER_LINKER_ID:linker_ids>
+
+  .. versionadded:: 4.2
+
+  where ``linker_ids`` is a comma-separated list.
+  ``1`` if CMake's linker id of the Objective-C++ linker matches any one
+  of the entries in ``linker_ids``, otherwise ``0``.
+
+.. genex:: $<Fortran_COMPILER_LINKER_ID>
+
+  .. versionadded:: 4.2
+
+  CMake's linker id of the Fortran linker used.
+
+.. genex:: $<Fortran_COMPILER_LINKER_ID:linker_ids>
+
+  .. versionadded:: 4.2
+
+  where ``linker_ids`` is a comma-separated list.
+  ``1`` if CMake's linker id of the Fortran linker matches any one
+  of the entries in ``linker_ids``, otherwise ``0``.
+
+.. genex:: $<HIP_COMPILER_LINKER_ID>
+
+  .. versionadded:: 4.2
+
+  CMake's linker id of the HIP linker used.
+
+.. genex:: $<HIP_COMPILER_LINKER_ID:linker_ids>
+
+  .. versionadded:: 4.2
+
+  where ``linker_ids`` is a comma-separated list.
+  ``1`` if CMake's linker id of the HIP linker matches any one
+  of the entries in ``linker_ids``, otherwise ``0``.
+
+.. genex:: $<C_COMPILER_LINKER_FRONTEND_VARIANT>
+
+  .. versionadded:: 4.2
+
+  CMake's linker frontend variant of the C linker used.
+
+.. genex:: $<C_COMPILER_LINKER_FRONTEND_VARIANT:variant_ids>
+
+  .. versionadded:: 4.2
+
+  where ``variant_ids`` is a comma-separated list.
+  ``1`` if CMake's linker frontend variant of the C linker matches any one
+  of the entries in ``variant_ids``, otherwise ``0``.
+
+.. genex:: $<CXX_COMPILER_LINKER_FRONTEND_VARIANT>
+
+  .. versionadded:: 4.2
+
+  CMake's linker frontend variant of the C++ linker used.
+
+.. genex:: $<CXX_COMPILER_LINKER_FRONTEND_VARIANT:variant_ids>
+
+  .. versionadded:: 4.2
+
+  where ``variant_ids`` is a comma-separated list.
+  ``1`` if CMake's linker frontend variant of the C++ linker matches any one
+  of the entries in ``variant_ids``, otherwise ``0``.
+
+.. genex:: $<CUDA_COMPILER_LINKER_FRONTEND_VARIANT>
+
+  .. versionadded:: 4.2
+
+  CMake's linker frontend variant of the CUDA linker used.
+
+.. genex:: $<CUDA_COMPILER_LINKER_FRONTEND_VARIANT:variant_ids>
+
+  .. versionadded:: 4.2
+
+  where ``variant_ids`` is a comma-separated list.
+  ``1`` if CMake's linker frontend variant of the CUDA linker matches any one
+  of the entries in ``variant_ids``, otherwise ``0``.
+
+.. genex:: $<OBJC_COMPILER_LINKER_FRONTEND_VARIANT>
+
+  .. versionadded:: 4.2
+
+  CMake's linker frontend variant of the Objective-C linker used.
+
+.. genex:: $<OBJC_COMPILER_LINKER_FRONTEND_VARIANT:variant_ids>
+
+  .. versionadded:: 4.2
+
+  where ``variant_ids`` is a comma-separated list.
+  ``1`` if CMake's linker frontend variant of the Objective-C linker matches
+  any one of the entries in ``variant_ids``, otherwise ``0``.
+
+.. genex:: $<OBJCXX_COMPILER_LINKER_FRONTEND_VARIANT>
+
+  .. versionadded:: 4.2
+
+  CMake's linker frontend variant of the Objective-C++ linker used.
+
+.. genex:: $<OBJCXX_COMPILER_LINKER_FRONTEND_VARIANT:variant_ids>
+
+  .. versionadded:: 4.2
+
+  where ``variant_ids`` is a comma-separated list.
+  ``1`` if CMake's linker frontend variant of the Objective-C++ linker matches
+  any one of the entries in ``variant_ids``, otherwise ``0``.
+
+.. genex:: $<Fortran_COMPILER_LINKER_FRONTEND_VARIANT>
+
+  .. versionadded:: 4.2
+
+  CMake's linker frontend variant of the Fortran linker used.
+
+.. genex:: $<Fortran_COMPILER_LINKER_FRONTEND_VARIANT:variant_ids>
+
+  .. versionadded:: 4.2
+
+  where ``variant_ids`` is a comma-separated list.
+  ``1`` if CMake's linker frontend variant of the Fortran linker matches
+  any one of the entries in ``variant_ids``, otherwise ``0``.
+
+.. genex:: $<HIP_COMPILER_LINKER_FRONTEND_VARIANT>
+
+  .. versionadded:: 4.2
+
+  CMake's linker frontend variant of the HIP linker used.
+
+.. genex:: $<HIP_COMPILER_LINKER_FRONTEND_VARIANT:variant_ids>
+
+  .. versionadded:: 4.2
+
+  where ``variant_ids`` is a comma-separated list.
+  ``1`` if CMake's linker frontend variant of the HIP linker matches
+  any one of the entries in ``variant_ids``, otherwise ``0``.
+
 
 .. _`Target-Dependent Expressions`:
 

+ 8 - 0
Help/release/dev/GenEx-COMPILER_LINKER.rst

@@ -0,0 +1,8 @@
+GenEx-COMPILER_LINKER
+---------------------
+
+* The :genex:`<LANG>_COMPILER_LINKER_ID <C_COMPILER_LINKER_ID>` and
+  :genex:`<LANG>_COMPILER_LINKER_FRONTEND_VARIANT <C_COMPILER_LINKER_FRONTEND_VARIANT>`
+  families of generator expressions were added to access the value of the
+  associated :variable:`CMAKE_<LANG>_COMPILER_LINKER_ID` and
+  :variable:`CMAKE_<LANG>_COMPILER_LINKER_FRONTEND_VARIANT` variables.

+ 161 - 0
Source/cmGeneratorExpressionNode.cxx

@@ -2561,6 +2561,146 @@ static const struct LinkLanguageAndIdNode : public cmGeneratorExpressionNode
   }
 } linkLanguageAndIdNode;
 
+struct CompilerLinkerIdNode : public cmGeneratorExpressionNode
+{
+  CompilerLinkerIdNode(char const* lang)
+    : Language(lang)
+  {
+  }
+
+  int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
+
+  std::string Evaluate(
+    std::vector<std::string> const& parameters,
+    cmGeneratorExpressionContext* context,
+    GeneratorExpressionContent const* content,
+    cmGeneratorExpressionDAGChecker* dagChecker) const override
+  {
+    if (!context->HeadTarget) {
+      reportError(
+        context, content->GetOriginalExpression(),
+        cmStrCat(
+          "$<", this->Language,
+          "_COMPILER_LINKER_ID> may only be used with binary targets. It may "
+          "not be used with add_custom_command or add_custom_target."));
+      return {};
+    }
+    return this->EvaluateWithLanguage(parameters, context, content, dagChecker,
+                                      this->Language);
+  }
+
+  std::string EvaluateWithLanguage(std::vector<std::string> const& parameters,
+                                   cmGeneratorExpressionContext* context,
+                                   GeneratorExpressionContent const* content,
+                                   cmGeneratorExpressionDAGChecker* /*unused*/,
+                                   std::string const& lang) const
+  {
+    std::string const& compilerLinkerId =
+      context->LG->GetMakefile()->GetSafeDefinition(
+        cmStrCat("CMAKE_", lang, "_COMPILER_LINKER_ID"));
+    if (parameters.empty()) {
+      return compilerLinkerId;
+    }
+    if (compilerLinkerId.empty()) {
+      return parameters.front().empty() ? "1" : "0";
+    }
+    static cmsys::RegularExpression compilerLinkerIdValidator(
+      "^[A-Za-z0-9_]*$");
+
+    for (auto const& param : parameters) {
+      if (!compilerLinkerIdValidator.find(param)) {
+        reportError(context, content->GetOriginalExpression(),
+                    "Expression syntax not recognized.");
+        return std::string();
+      }
+
+      if (param == compilerLinkerId) {
+        return "1";
+      }
+    }
+    return "0";
+  }
+
+  char const* const Language;
+};
+
+static CompilerLinkerIdNode const cCompilerLinkerIdNode("C"),
+  cxxCompilerLinkerIdNode("CXX"), cudaCompilerLinkerIdNode("CUDA"),
+  objcCompilerLinkerIdNode("OBJC"), objcxxCompilerLinkerIdNode("OBJCXX"),
+  fortranCompilerLinkerIdNode("Fortran"), hipCompilerLinkerIdNode("HIP");
+
+struct CompilerLinkerFrontendVariantNode : public cmGeneratorExpressionNode
+{
+  CompilerLinkerFrontendVariantNode(char const* lang)
+    : Language(lang)
+  {
+  }
+
+  int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
+
+  std::string Evaluate(
+    std::vector<std::string> const& parameters,
+    cmGeneratorExpressionContext* context,
+    GeneratorExpressionContent const* content,
+    cmGeneratorExpressionDAGChecker* dagChecker) const override
+  {
+    if (!context->HeadTarget) {
+      reportError(
+        context, content->GetOriginalExpression(),
+        cmStrCat(
+          "$<", this->Language,
+          "_COMPILER_LINKER_FRONTEND_VARIANT> may only be used with binary "
+          "targets. It may not be used with add_custom_command or "
+          "add_custom_target."));
+      return {};
+    }
+    return this->EvaluateWithLanguage(parameters, context, content, dagChecker,
+                                      this->Language);
+  }
+
+  std::string EvaluateWithLanguage(std::vector<std::string> const& parameters,
+                                   cmGeneratorExpressionContext* context,
+                                   GeneratorExpressionContent const* content,
+                                   cmGeneratorExpressionDAGChecker* /*unused*/,
+                                   std::string const& lang) const
+  {
+    std::string const& compilerLinkerFrontendVariant =
+      context->LG->GetMakefile()->GetSafeDefinition(
+        cmStrCat("CMAKE_", lang, "_COMPILER_LINKER_FRONTEND_VARIANT"));
+    if (parameters.empty()) {
+      return compilerLinkerFrontendVariant;
+    }
+    if (compilerLinkerFrontendVariant.empty()) {
+      return parameters.front().empty() ? "1" : "0";
+    }
+    static cmsys::RegularExpression compilerLinkerFrontendVariantValidator(
+      "^[A-Za-z0-9_]*$");
+
+    for (auto const& param : parameters) {
+      if (!compilerLinkerFrontendVariantValidator.find(param)) {
+        reportError(context, content->GetOriginalExpression(),
+                    "Expression syntax not recognized.");
+        return {};
+      }
+      if (param == compilerLinkerFrontendVariant) {
+        return "1";
+      }
+    }
+    return "0";
+  }
+
+  char const* const Language;
+};
+
+static CompilerLinkerFrontendVariantNode const
+  cCompilerLinkerFrontendVariantNode("C"),
+  cxxCompilerLinkerFrontendVariantNode("CXX"),
+  cudaCompilerLinkerFrontendVariantNode("CUDA"),
+  objcCompilerLinkerFrontendVariantNode("OBJC"),
+  objcxxCompilerLinkerFrontendVariantNode("OBJCXX"),
+  fortranCompilerLinkerFrontendVariantNode("Fortran"),
+  hipCompilerLinkerFrontendVariantNode("HIP");
+
 static const struct LinkLibraryNode : public cmGeneratorExpressionNode
 {
   LinkLibraryNode() {} // NOLINT(modernize-use-equals-default)
@@ -4641,6 +4781,27 @@ cmGeneratorExpressionNode const* cmGeneratorExpressionNode::GetNode(
     { "COMPILE_LANGUAGE", &languageNode },
     { "LINK_LANG_AND_ID", &linkLanguageAndIdNode },
     { "LINK_LANGUAGE", &linkLanguageNode },
+    { "C_COMPILER_LINKER_ID", &cCompilerLinkerIdNode },
+    { "CXX_COMPILER_LINKER_ID", &cxxCompilerLinkerIdNode },
+    { "OBJC_COMPILER_LINKER_ID", &objcCompilerLinkerIdNode },
+    { "OBJCXX_COMPILER_LINKER_ID", &objcxxCompilerLinkerIdNode },
+    { "CUDA_COMPILER_LINKER_ID", &cudaCompilerLinkerIdNode },
+    { "Fortran_COMPILER_LINKER_ID", &fortranCompilerLinkerIdNode },
+    { "HIP_COMPILER_LINKER_ID", &hipCompilerLinkerIdNode },
+    { "C_COMPILER_LINKER_FRONTEND_VARIANT",
+      &cCompilerLinkerFrontendVariantNode },
+    { "CXX_COMPILER_LINKER_FRONTEND_VARIANT",
+      &cxxCompilerLinkerFrontendVariantNode },
+    { "CUDA_COMPILER_LINKER_FRONTEND_VARIANT",
+      &cudaCompilerLinkerFrontendVariantNode },
+    { "OBJC_COMPILER_LINKER_FRONTEND_VARIANT",
+      &objcCompilerLinkerFrontendVariantNode },
+    { "OBJCXX_COMPILER_LINKER_FRONTEND_VARIANT",
+      &objcxxCompilerLinkerFrontendVariantNode },
+    { "Fortran_COMPILER_LINKER_FRONTEND_VARIANT",
+      &fortranCompilerLinkerFrontendVariantNode },
+    { "HIP_COMPILER_LINKER_FRONTEND_VARIANT",
+      &hipCompilerLinkerFrontendVariantNode },
     { "LINK_LIBRARY", &linkLibraryNode },
     { "LINK_GROUP", &linkGroupNode },
     { "HOST_LINK", &hostLinkNode },

+ 2 - 1
Tests/RunCMake/CMakeLists.txt

@@ -521,7 +521,8 @@ 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)
+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(GeneratorExpressionShortCircuit)
 add_RunCMake_test(GeneratorInstance)
 add_RunCMake_test(GeneratorPlatform)

+ 19 - 0
Tests/RunCMake/GeneratorExpression/COMPILER_LINKER.cmake

@@ -0,0 +1,19 @@
+
+set(languages C ${LANG})
+list(REMOVE_DUPLICATES languages)
+
+enable_language(${languages})
+
+include(CTest)
+
+set(VAR "${CMAKE_${LANG}_COMPILER_LINKER_${TYPE}}")
+if(NOT VAR)
+  set(VAR "UNDEF")
+endif()
+
+add_executable(COMPILER_LINKER compiler_linker.c)
+target_compile_definitions(COMPILER_LINKER PRIVATE "VAR=${VAR}"
+                                                   "GENEX=$<IF:$<BOOL:$<${LANG}_COMPILER_LINKER_${TYPE}>>,$<${LANG}_COMPILER_LINKER_${TYPE}>,UNDEF>")
+
+add_test(NAME COMPILER_LINKER.${LANG}.${TYPE}
+         COMMAND COMPILER_LINKER)

+ 9 - 0
Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.C.FRONTEND_VARIANT-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<C_COMPILER_LINKER_FRONTEND_VARIANT>
+
+  \$<C_COMPILER_LINKER_FRONTEND_VARIANT> may only be used with binary targets.
+  It may not be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 9 - 0
Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.C.ID-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<C_COMPILER_LINKER_ID>
+
+  \$<C_COMPILER_LINKER_ID> may only be used with binary targets.  It may not
+  be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 9 - 0
Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.CUDA.FRONTEND_VARIANT-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<CUDA_COMPILER_LINKER_FRONTEND_VARIANT>
+
+  \$<CUDA_COMPILER_LINKER_FRONTEND_VARIANT> may only be used with binary
+  targets.  It may not be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 9 - 0
Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.CUDA.ID-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<CUDA_COMPILER_LINKER_ID>
+
+  \$<CUDA_COMPILER_LINKER_ID> may only be used with binary targets.  It may
+  not be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 9 - 0
Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.CXX.FRONTEND_VARIANT-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<CXX_COMPILER_LINKER_FRONTEND_VARIANT>
+
+  \$<CXX_COMPILER_LINKER_FRONTEND_VARIANT> may only be used with binary
+  targets.  It may not be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 9 - 0
Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.CXX.ID-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<CXX_COMPILER_LINKER_ID>
+
+  \$<CXX_COMPILER_LINKER_ID> may only be used with binary targets.  It may not
+  be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 9 - 0
Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.Fortran.FRONTEND_VARIANT-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<Fortran_COMPILER_LINKER_FRONTEND_VARIANT>
+
+  \$<Fortran_COMPILER_LINKER_FRONTEND_VARIANT> may only be used with binary
+  targets.  It may not be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 9 - 0
Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.Fortran.ID-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<Fortran_COMPILER_LINKER_ID>
+
+  \$<Fortran_COMPILER_LINKER_ID> may only be used with binary targets.  It may
+  not be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 9 - 0
Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.HIP.FRONTEND_VARIANT-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<HIP_COMPILER_LINKER_FRONTEND_VARIANT>
+
+  \$<HIP_COMPILER_LINKER_FRONTEND_VARIANT> may only be used with binary
+  targets.  It may not be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 9 - 0
Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.HIP.ID-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<HIP_COMPILER_LINKER_ID>
+
+  \$<HIP_COMPILER_LINKER_ID> may only be used with binary targets.  It may not
+  be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 9 - 0
Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.OBJC.FRONTEND_VARIANT-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<OBJC_COMPILER_LINKER_FRONTEND_VARIANT>
+
+  \$<OBJC_COMPILER_LINKER_FRONTEND_VARIANT> may only be used with binary
+  targets.  It may not be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 9 - 0
Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.OBJC.ID-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<OBJC_COMPILER_LINKER_ID>
+
+  \$<OBJC_COMPILER_LINKER_ID> may only be used with binary targets.  It may
+  not be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 9 - 0
Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.OBJCXX.FRONTEND_VARIANT-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<OBJCXX_COMPILER_LINKER_FRONTEND_VARIANT>
+
+  \$<OBJCXX_COMPILER_LINKER_FRONTEND_VARIANT> may only be used with binary
+  targets.  It may not be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 9 - 0
Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.OBJCXX.ID-stderr.txt

@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<OBJCXX_COMPILER_LINKER_ID>
+
+  \$<OBJCXX_COMPILER_LINKER_ID> may only be used with binary targets.  It may
+  not be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)

+ 4 - 0
Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.cmake

@@ -0,0 +1,4 @@
+add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/copied_file.c"
+  COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/empty.c" "${CMAKE_CURRENT_BINARY_DIR}/copied_file$<${LANG}_COMPILER_LINKER_${TYPE}>.c"
+)
+add_custom_target(drive DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/copied_file.c")

+ 43 - 0
Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake

@@ -48,6 +48,49 @@ run_cmake(FILTER-InvalidOperator)
 run_cmake(FILTER-Exclude)
 run_cmake(FILTER-Include)
 
+function(run_linker_genex test lang type)
+  set(options_args CHECK_RESULT EXECUTE)
+  cmake_parse_arguments(PARSE_ARGV 3 RLG "${options_args}" "" "")
+
+  set(RunCMake_TEST_VARIANT_DESCRIPTION ".${lang}.${type}")
+  set(test_name ${test}${RunCMake_TEST_VARIANT_DESCRIPTION})
+  set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/${test_name}-build")
+  if(NOT RunCMake_GENERATOR_IS_MULTI_CONFIG)
+    list(APPEND options -DCMAKE_BUILD_TYPE=Release)
+  endif()
+  if(RLG_CHECK_RESULT)
+    set(RunCMake_TEST_EXPECT_RESULT 1)
+    file(READ "${RunCMake_SOURCE_DIR}/${test_name}-stderr.txt" RunCMake_TEST_EXPECT_stderr)
+  endif()
+  run_cmake_with_options(${test} -DLANG=${lang} -DTYPE=${type})
+  set(RunCMake_TEST_NO_CLEAN 1)
+  unset(RunCMake_TEST_VARIANT_DESCRIPTION)
+  if(RLG_EXECUTE)
+    run_cmake_command(${test_name}-build "${CMAKE_COMMAND}" --build . --config Release)
+    run_cmake_command(${test_name}-run "${CMAKE_CTEST_COMMAND}" -C Release -V)
+  endif()
+endfunction()
+function(exec_linker_genex test lang type)
+  run_linker_genex(${ARGV} EXECUTE)
+endfunction()
+
+set(languages C CXX)
+foreach(lang IN ITEMS OBJC Fortran CUDA HIP)
+  if(CMake_TEST_${lang})
+    list(APPEND languages ${lang})
+    if(lang STREQUAL OBJC)
+    list(APPEND languages OBJCXX)
+    endif()
+  endif()
+endforeach()
+
+foreach(lang IN LISTS languages)
+  foreach(type IN ITEMS ID FRONTEND_VARIANT)
+    run_linker_genex(NonValidTarget-COMPILER_LINKER ${lang} ${type} CHECK_RESULT)
+    exec_linker_genex(COMPILER_LINKER ${lang} ${type})
+  endforeach()
+endforeach()
+
 if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
   set(RunCMake_TEST_OPTIONS [==[-DCMAKE_CONFIGURATION_TYPES=CustomConfig]==])
 else()

+ 10 - 0
Tests/RunCMake/GeneratorExpression/compiler_linker.c

@@ -0,0 +1,10 @@
+
+#include <string.h>
+
+#define xstr(s) str(s)
+#define str(s) #s
+
+int main(void)
+{
+  return strcmp(xstr(VAR), xstr(GENEX)) == 0 ? 0 : 1;
+}