Browse Source

Merge topic 'compiler_id_gen_exp_supports_multiple_ids'

162555d7ec Help: Add release notes for updated generator expressions
808b818063 Genex: CompileLang and CompileLangAndId now match against a list of ids
9fd602bfd3 Genex: PlatformId now can match against a list of ids.
ec66af2026 Genex: CompilerId now can match against a list of ids.
2d4787fc4d Genex: Add more extensive support for an unbounded number of parameters

Acked-by: Kitware Robot <[email protected]>
Merge-request: !3405
Brad King 6 years ago
parent
commit
4b68baa776

+ 33 - 27
Help/manual/cmake-generator-expressions.7.rst

@@ -110,24 +110,30 @@ Variable Queries
   The mapping in :prop_tgt:`MAP_IMPORTED_CONFIG_<CONFIG>` is also considered by
   this expression when it is evaluated on a property on an :prop_tgt:`IMPORTED`
   target.
-``$<PLATFORM_ID:platform_id>``
-  ``1`` if the CMake's platform id matches ``platform_id``
-  otherwise ``0``.
+``$<PLATFORM_ID:platform_ids>``
+  where ``platform_ids`` is a comma-separated list.
+  ``1`` if the CMake's platform id matches any one of the entries in
+  ``platform_ids``, otherwise ``0``.
   See also the :variable:`CMAKE_SYSTEM_NAME` variable.
-``$<C_COMPILER_ID:compiler_id>``
-  ``1`` if the CMake's compiler id of the C compiler matches ``compiler_id``,
-  otherwise ``0``.
+``$<C_COMPILER_ID:compiler_ids>``
+  where ``compiler_ids`` is a comma-separated list.
+  ``1`` if the CMake's compiler id of the C compiler matches any one
+  of the entries in ``compiler_ids``, otherwise ``0``.
   See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
-``$<CXX_COMPILER_ID:compiler_id>``
-  ``1`` if the CMake's compiler id of the CXX compiler matches ``compiler_id``,
-  otherwise ``0``.
-``$<CUDA_COMPILER_ID:compiler_id>``
-  ``1`` if the CMake's compiler id of the CUDA compiler matches ``compiler_id``,
-  otherwise ``0``.
+``$<CXX_COMPILER_ID:compiler_ids>``
+  where ``compiler_ids`` is a comma-separated list.
+  ``1`` if the CMake's compiler id of the CXX compiler matches any one
+  of the entries in ``compiler_ids``, otherwise ``0``.
   See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
-``$<Fortran_COMPILER_ID:compiler_id>``
-  ``1`` if the CMake's compiler id of the Fortran compiler matches ``compiler_id``,
-  otherwise ``0``.
+``$<CUDA_COMPILER_ID:compiler_ids>``
+  where ``compiler_ids`` is a comma-separated list.
+  ``1`` if the CMake's compiler id of the CUDA compiler matches any one
+  of the entries in ``compiler_ids``, otherwise ``0``.
+  See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
+``$<Fortran_COMPILER_ID:compiler_ids>``
+  where ``compiler_ids`` is a comma-separated list.
+  ``1`` if the CMake's compiler id of the Fortran compiler matches any one
+  of the entries in ``compiler_ids``, otherwise ``0``.
   See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
 ``$<C_COMPILER_VERSION:version>``
   ``1`` if the version of the C compiler matches ``version``, otherwise ``0``.
@@ -158,20 +164,20 @@ Variable Queries
 
 .. _`Boolean COMPILE_LANGUAGE Generator Expression`:
 
-``$<COMPILE_LANG_AND_ID:language,compiler_id>``
+``$<COMPILE_LANG_AND_ID:language,compiler_ids>``
   ``1`` when the language used for compilation unit matches ``language`` and
-  the CMake's compiler id of the language compiler matches ``compiler_id``,
-  otherwise ``0``. This expression is a short form for the combination of
-  ``$<COMPILE_LANGUAGE:language>`` and ``$<LANG_COMPILER_ID:compiler_id>``.
-  This expression may be used to specify compile options,
-  compile definitions, and include directories for source files of a
+  the CMake's compiler id of the language compiler matches any one of the
+  entries in ``compiler_ids``, otherwise ``0``. This expression is a short form
+  for the combination of ``$<COMPILE_LANGUAGE:language>`` and
+  ``$<LANG_COMPILER_ID:compiler_ids>``. This expression may be used to specify
+  compile options, compile definitions, and include directories for source files of a
   particular language and compiler combination in a target. For example:
 
   .. code-block:: cmake
 
     add_executable(myapp main.cpp foo.c bar.cpp zot.cu)
     target_compile_definitions(myapp
-      PRIVATE $<$<COMPILE_LANG_AND_ID:CXX,Clang>:COMPILING_CXX_WITH_CLANG>
+      PRIVATE $<$<COMPILE_LANG_AND_ID:CXX,AppleClang,Clang>:COMPILING_CXX_WITH_CLANG>
               $<$<COMPILE_LANG_AND_ID:CXX,Intel>:COMPILING_CXX_WITH_INTEL>
               $<$<COMPILE_LANG_AND_ID:C,Clang>:COMPILING_C_WITH_CLANG>
     )
@@ -194,10 +200,10 @@ Variable Queries
               $<$<AND:$<COMPILE_LANGUAGE:C>,$<C_COMPILER_ID:Clang>>:COMPILING_C_WITH_CLANG>
     )
 
-``$<COMPILE_LANGUAGE:language>``
-  ``1`` when the language used for compilation unit matches ``language``,
-  otherwise ``0``.  This expression may be used to specify compile options,
-  compile definitions, and include directories for source files of a
+``$<COMPILE_LANGUAGE:languages>``
+  ``1`` when the language used for compilation unit matches any of the entries
+  in ``languages``, otherwise ``0``.  This expression may be used to specify
+  compile options, compile definitions, and include directories for source files of a
   particular language in a target. For example:
 
   .. code-block:: cmake
@@ -211,7 +217,7 @@ Variable Queries
               $<$<COMPILE_LANGUAGE:CUDA>:COMPILING_CUDA>
     )
     target_include_directories(myapp
-      PRIVATE $<$<COMPILE_LANGUAGE:CXX>:/opt/foo/cxx_headers>
+      PRIVATE $<$<COMPILE_LANGUAGE:CXX,CUDA>:/opt/foo/headers>
     )
 
   This specifies the use of the ``-fno-exceptions`` compile option,

+ 8 - 0
Help/release/dev/genex-comma-separated.rst

@@ -0,0 +1,8 @@
+genex-comma-separated
+---------------------
+
+* The :manual:`generator expressions <cmake-generator-expressions(7)>`
+  ``C_COMPILER_ID``, ``CXX_COMPILER_ID``, ``CUDA_COMPILER_ID``,
+  ``Fortran_COMPILER_ID``, ``COMPILE_LANGUAGE``, ``COMPILE_LANG_AND_ID``, and
+  ``PLATFORM_ID`` learned to support matching one value from a comma-separated
+  list.

+ 7 - 3
Source/cmGeneratorExpressionEvaluator.cxx

@@ -166,9 +166,13 @@ std::string GeneratorExpressionContent::EvaluateParameters(
     reportError(context, this->GetOriginalExpression(),
                 "$<" + identifier +
                   "> expression requires at least one parameter.");
-  }
-  if (numExpected == cmGeneratorExpressionNode::OneOrZeroParameters &&
-      parameters.size() > 1) {
+  } else if (numExpected == cmGeneratorExpressionNode::TwoOrMoreParameters &&
+             parameters.size() < 2) {
+    reportError(context, this->GetOriginalExpression(),
+                "$<" + identifier +
+                  "> expression requires at least two parameters.");
+  } else if (numExpected == cmGeneratorExpressionNode::OneOrZeroParameters &&
+             parameters.size() > 1) {
     reportError(context, this->GetOriginalExpression(),
                 "$<" + identifier +
                   "> expression requires one or zero parameters.");

+ 44 - 32
Source/cmGeneratorExpressionNode.cxx

@@ -632,7 +632,7 @@ struct CompilerIdNode : public cmGeneratorExpressionNode
   {
   }
 
-  int NumExpectedParameters() const override { return OneOrZeroParameters; }
+  int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
 
   std::string Evaluate(
     const std::vector<std::string>& parameters,
@@ -664,36 +664,39 @@ struct CompilerIdNode : public cmGeneratorExpressionNode
     if (parameters.empty()) {
       return compilerId;
     }
-    static cmsys::RegularExpression compilerIdValidator("^[A-Za-z0-9_]*$");
-    if (!compilerIdValidator.find(parameters.front())) {
-      reportError(context, content->GetOriginalExpression(),
-                  "Expression syntax not recognized.");
-      return std::string();
-    }
     if (compilerId.empty()) {
       return parameters.front().empty() ? "1" : "0";
     }
+    static cmsys::RegularExpression compilerIdValidator("^[A-Za-z0-9_]*$");
 
-    if (strcmp(parameters.front().c_str(), compilerId.c_str()) == 0) {
-      return "1";
-    }
+    for (auto& param : parameters) {
 
-    if (cmsysString_strcasecmp(parameters.front().c_str(),
-                               compilerId.c_str()) == 0) {
-      switch (context->LG->GetPolicyStatus(cmPolicies::CMP0044)) {
-        case cmPolicies::WARN: {
-          std::ostringstream e;
-          e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0044);
-          context->LG->GetCMakeInstance()->IssueMessage(
-            MessageType::AUTHOR_WARNING, e.str(), context->Backtrace);
-          CM_FALLTHROUGH;
+      if (!compilerIdValidator.find(param)) {
+        reportError(context, content->GetOriginalExpression(),
+                    "Expression syntax not recognized.");
+        return std::string();
+      }
+
+      if (strcmp(param.c_str(), compilerId.c_str()) == 0) {
+        return "1";
+      }
+
+      if (cmsysString_strcasecmp(param.c_str(), compilerId.c_str()) == 0) {
+        switch (context->LG->GetPolicyStatus(cmPolicies::CMP0044)) {
+          case cmPolicies::WARN: {
+            std::ostringstream e;
+            e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0044);
+            context->LG->GetCMakeInstance()->IssueMessage(
+              MessageType::AUTHOR_WARNING, e.str(), context->Backtrace);
+            CM_FALLTHROUGH;
+          }
+          case cmPolicies::OLD:
+            return "1";
+          case cmPolicies::NEW:
+          case cmPolicies::REQUIRED_ALWAYS:
+          case cmPolicies::REQUIRED_IF_USED:
+            break;
         }
-        case cmPolicies::OLD:
-          return "1";
-        case cmPolicies::NEW:
-        case cmPolicies::REQUIRED_ALWAYS:
-        case cmPolicies::REQUIRED_IF_USED:
-          break;
       }
     }
     return "0";
@@ -773,7 +776,7 @@ struct PlatformIdNode : public cmGeneratorExpressionNode
 {
   PlatformIdNode() {} // NOLINT(modernize-use-equals-default)
 
-  int NumExpectedParameters() const override { return OneOrZeroParameters; }
+  int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
 
   std::string Evaluate(
     const std::vector<std::string>& parameters,
@@ -791,8 +794,10 @@ struct PlatformIdNode : public cmGeneratorExpressionNode
       return parameters.front().empty() ? "1" : "0";
     }
 
-    if (parameters.front() == platformId) {
-      return "1";
+    for (auto& param : parameters) {
+      if (param == platformId) {
+        return "1";
+      }
     }
     return "0";
   }
@@ -946,7 +951,7 @@ static const struct CompileLanguageNode : public cmGeneratorExpressionNode
 {
   CompileLanguageNode() {} // NOLINT(modernize-use-equals-default)
 
-  int NumExpectedParameters() const override { return OneOrZeroParameters; }
+  int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
 
   std::string Evaluate(
     const std::vector<std::string>& parameters,
@@ -977,7 +982,13 @@ static const struct CompileLanguageNode : public cmGeneratorExpressionNode
     if (parameters.empty()) {
       return context->Language;
     }
-    return context->Language == parameters.front() ? "1" : "0";
+
+    for (auto& param : parameters) {
+      if (context->Language == param) {
+        return "1";
+      }
+    }
+    return "0";
   }
 } languageNode;
 
@@ -985,7 +996,7 @@ static const struct CompileLanguageAndIdNode : public cmGeneratorExpressionNode
 {
   CompileLanguageAndIdNode() {} // NOLINT(modernize-use-equals-default)
 
-  int NumExpectedParameters() const override { return 2; }
+  int NumExpectedParameters() const override { return TwoOrMoreParameters; }
 
   std::string Evaluate(
     const std::vector<std::string>& parameters,
@@ -1018,7 +1029,8 @@ static const struct CompileLanguageAndIdNode : public cmGeneratorExpressionNode
 
     const std::string& lang = context->Language;
     if (lang == parameters.front()) {
-      std::vector<std::string> idParameter = { parameters[1] };
+      std::vector<std::string> idParameter((parameters.cbegin() + 1),
+                                           parameters.cend());
       return CompilerIdNode{ lang.c_str() }.EvaluateWithLanguage(
         idParameter, context, content, dagChecker, lang);
     }

+ 3 - 1
Source/cmGeneratorExpressionNode.h

@@ -20,7 +20,9 @@ struct cmGeneratorExpressionNode
   {
     DynamicParameters = 0,
     OneOrMoreParameters = -1,
-    OneOrZeroParameters = -2
+    TwoOrMoreParameters = -2,
+    ZeroOrMoreParameters = -3,
+    OneOrZeroParameters = -4
   };
   virtual ~cmGeneratorExpressionNode() = default;
 

+ 1 - 0
Tests/CMakeCommands/target_compile_definitions/CMakeLists.txt

@@ -34,6 +34,7 @@ target_compile_definitions(consumer
     CONSUMER_LANG_$<COMPILE_LANGUAGE>
     LANG_IS_CXX=$<COMPILE_LANGUAGE:CXX>
     LANG_IS_C=$<COMPILE_LANGUAGE:C>
+    LANG_IS_C_OR_CXX=$<COMPILE_LANGUAGE:C,CXX>
 )
 if(CMAKE_GENERATOR MATCHES "Visual Studio|Xcode")
   target_compile_definitions(consumer

+ 4 - 0
Tests/CMakeCommands/target_compile_definitions/consumer.c

@@ -35,6 +35,10 @@
 #  endif
 #endif
 
+#if !LANG_IS_C_OR_CXX
+#  error Expected LANG_IS_C_OR_CXX
+#endif
+
 void consumer_c()
 {
 }

+ 14 - 2
Tests/CMakeCommands/target_compile_options/CMakeLists.txt

@@ -7,9 +7,11 @@ add_executable(target_compile_options
   "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp"
 )
 target_compile_options(target_compile_options
-  PRIVATE $<$<CXX_COMPILER_ID:GNU>:-DMY_PRIVATE_DEFINE>
+  PRIVATE $<$<CXX_COMPILER_ID:AppleClang,Clang,GNU>:-DMY_PRIVATE_DEFINE>
   PUBLIC $<$<COMPILE_LANG_AND_ID:CXX,GNU>:-DMY_PUBLIC_DEFINE>
+  PUBLIC $<$<COMPILE_LANG_AND_ID:CXX,GNU,Clang,AppleClang>:-DMY_MUTLI_COMP_PUBLIC_DEFINE>
   INTERFACE $<$<CXX_COMPILER_ID:GNU>:-DMY_INTERFACE_DEFINE>
+  INTERFACE $<$<CXX_COMPILER_ID:GNU,Clang,AppleClang>:-DMY_MULTI_COMP_INTERFACE_DEFINE>
 )
 
 if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
@@ -17,6 +19,11 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
     PRIVATE
       "DO_GNU_TESTS"
   )
+elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+  target_compile_definitions(target_compile_options
+    PRIVATE
+      "DO_CLANG_TESTS"
+  )
 endif()
 
 add_executable(consumer
@@ -40,7 +47,7 @@ if(CMAKE_GENERATOR MATCHES "Visual Studio")
 endif()
 
 target_compile_options(consumer
-  PRIVATE $<$<CXX_COMPILER_ID:GNU>:$<TARGET_PROPERTY:target_compile_options,INTERFACE_COMPILE_OPTIONS>>
+  PRIVATE $<$<CXX_COMPILER_ID:GNU,Clang,AppleClang>:$<TARGET_PROPERTY:target_compile_options,INTERFACE_COMPILE_OPTIONS>>
 )
 
 if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
@@ -48,6 +55,11 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
     PRIVATE
       "DO_GNU_TESTS"
   )
+elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+  target_compile_definitions(consumer
+    PRIVATE
+      "DO_CLANG_TESTS"
+  )
 endif()
 
 # Test no items

+ 24 - 0
Tests/CMakeCommands/target_compile_options/consumer.cpp

@@ -13,6 +13,30 @@
 #    error Expected MY_INTERFACE_DEFINE
 #  endif
 
+#  ifndef MY_MULTI_COMP_INTERFACE_DEFINE
+#    error Expected MY_MULTI_COMP_INTERFACE_DEFINE
+#  endif
+
+#  ifndef MY_MUTLI_COMP_PUBLIC_DEFINE
+#    error Expected MY_MUTLI_COMP_PUBLIC_DEFINE
+#  endif
+
+#endif
+
+#ifdef DO_CLANG_TESTS
+
+#  ifdef MY_PRIVATE_DEFINE
+#    error Unexpected MY_PRIVATE_DEFINE
+#  endif
+
+#  ifndef MY_MULTI_COMP_INTERFACE_DEFINE
+#    error Expected MY_MULTI_COMP_INTERFACE_DEFINE
+#  endif
+
+#  ifndef MY_MUTLI_COMP_PUBLIC_DEFINE
+#    error Expected MY_MUTLI_COMP_PUBLIC_DEFINE
+#  endif
+
 #endif
 
 #ifndef CONSUMER_LANG_CXX

+ 20 - 0
Tests/CMakeCommands/target_compile_options/main.cpp

@@ -9,12 +9,32 @@
 #    error Expected MY_PUBLIC_DEFINE
 #  endif
 
+#  ifndef MY_MUTLI_COMP_PUBLIC_DEFINE
+#    error Expected MY_MUTLI_COMP_PUBLIC_DEFINE
+#  endif
+
 #  ifdef MY_INTERFACE_DEFINE
 #    error Unexpected MY_INTERFACE_DEFINE
 #  endif
 
 #endif
 
+#ifdef DO_CLANG_TESTS
+
+#  ifndef MY_PRIVATE_DEFINE
+#    error Expected MY_PRIVATE_DEFINE
+#  endif
+
+#  ifdef MY_PUBLIC_DEFINE
+#    error Unexpected MY_PUBLIC_DEFINE
+#  endif
+
+#  ifndef MY_MUTLI_COMP_PUBLIC_DEFINE
+#    error Expected MY_MUTLI_COMP_PUBLIC_DEFINE
+#  endif
+
+#endif
+
 int main()
 {
   return 0;

+ 1 - 0
Tests/GeneratorExpression/CMakeLists.txt

@@ -220,6 +220,7 @@ add_custom_target(check-part3 ALL
     -Dtest_early_termination_2=$<$<1:>:,
     -Dsystem_name=${CMAKE_HOST_SYSTEM_NAME}
     -Dtest_platform_id=$<PLATFORM_ID>
+    -Dtest_platform_id_supported=$<PLATFORM_ID:Linux,Windows,Darwin>
     -Dtest_platform_id_Linux=$<PLATFORM_ID:Linux>
     -Dtest_platform_id_Windows=$<PLATFORM_ID:Windows>
     -Dtest_platform_id_Darwin=$<PLATFORM_ID:Darwin>

+ 5 - 0
Tests/GeneratorExpression/check-part3.cmake

@@ -28,11 +28,16 @@ check(test_early_termination_2 "$<:,")
 check(test_platform_id "${system_name}")
 foreach(system Linux Windows Darwin)
   if(system_name STREQUAL system)
+    check(test_platform_id_supported 1)
     check(test_platform_id_${system} 1)
+    set(platform_supported 1)
   else()
     check(test_platform_id_${system} 0)
   endif()
 endforeach()
+if(NOT platform_supported)
+  check(test_platform_id_supported 0)
+endif()
 check(lower_case "mi,xed")
 check(upper_case "MIX,ED")
 check(make_c_identifier "_4f_oo__bar__")

+ 1 - 2
Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-add_custom_command-stderr.txt

@@ -3,7 +3,6 @@ CMake Error at COMPILE_LANG_AND_ID-add_custom_command.cmake:2 \(add_custom_comma
 
     \$<COMPILE_LANG_AND_ID>
 
-  \$<COMPILE_LANG_AND_ID> expression requires 2 comma separated parameters,
-  but got 0 instead.
+  \$<COMPILE_LANG_AND_ID> expression requires at least two parameters.
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)

+ 1 - 2
Tests/RunCMake/GeneratorExpression/COMPILE_LANG_AND_ID-target_sources-stderr.txt

@@ -3,7 +3,6 @@ CMake Error at COMPILE_LANG_AND_ID-target_sources.cmake:2 \(target_sources\):
 
     \$<COMPILE_LANG_AND_ID>
 
-  \$<COMPILE_LANG_AND_ID> expression requires 2 comma separated parameters,
-  but got 0 instead.
+  \$<COMPILE_LANG_AND_ID> expression requires at least two parameters.
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)

+ 1 - 1
Tests/RunCMake/PolicyScope/dir1/CMakeLists.txt

@@ -2,4 +2,4 @@
 
 add_library(foo STATIC foo.cpp)
 string(TOLOWER ${CMAKE_CXX_COMPILER_ID} compiler_id)
-target_compile_definitions(foo PRIVATE Foo=$<CXX_COMPILER_ID:${compiler_id}>)
+target_compile_definitions(foo PRIVATE Foo=$<CXX_COMPILER_ID:invalid,${compiler_id}>)