Pārlūkot izejas kodu

Genex: Enable COMPILE_LANGUAGE for COMPILE_OPTIONS with Visual Studio

Since commit v3.9.0-rc4~3^2~1 (VS: Fix target_compile_options for CUDA,
2017-06-21), the evaluation of `COMPILE_LANGUAGE` receives the proper
language.  The set of compile flags used for a target's C and C++
sources is based on the linker language.  By default this is always the
C++ flags if any C++ sources appear in the target, and otherwise the C
flags.  Therefore we can define the `COMPILE_LANGUAGE` generator
expression in `COMPILE_OPTIONS` to match the selected language.

This is not exactly the same as for other generators, but is the best VS
can do.  It is also sufficient for many use cases since the set of
allowed flags for C and C++ is almost the same in Visual Studio.
Furthermore, since the VS generator moves many of the flags to
declarative `.vcxproj` elements, it will automatically avoid passing
C++ flags for C sources.

Issue: #17435
Brad King 8 gadi atpakaļ
vecāks
revīzija
2ae880fa8f

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

@@ -97,7 +97,7 @@ Available logical expressions are:
   compile features and a list of supported compilers.
 ``$<COMPILE_LANGUAGE:lang>``
   ``1`` when the language used for compilation unit matches ``lang``,
-  otherwise ``0``.  This expression used to specify compile options for
+  otherwise ``0``.  This expression may be used to specify compile options for
   source files of a particular language in a target. For example, to specify
   the use of the ``-fno-exceptions`` compile option (compiler id checks
   elided):
@@ -109,10 +109,12 @@ Available logical expressions are:
       PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions>
     )
 
-  This generator expression has limited use because it is not possible to
-  use it with the Visual Studio generators.  Portable buildsystems would
-  not use this expression, and would create separate libraries for each
-  source file language instead:
+  Note that with :ref:`Visual Studio Generators` there is no way to represent
+  target-wide flags separately for ``C`` and ``CXX`` languages.  Under these
+  generators, target-wide flags for both C and C++ sources will be evaluated
+  using ``CXX`` if there are any C++ sources and otherwise using ``C``.
+  A workaround is to create separate libraries for each source file language
+  instead:
 
   .. code-block:: cmake
 

+ 7 - 0
Help/release/dev/extend-compile-language-genex.rst

@@ -0,0 +1,7 @@
+extend-compile-language-genex
+-----------------------------
+
+* The ``COMPILE_LANGUAGE`` :manual:`generator expression
+  <cmake-generator-expressions(7)>` may now be used with
+  :ref:`Visual Studio Generators` in :prop_tgt:`COMPILE_OPTIONS`
+  and :command:`file(GENERATE)`.

+ 2 - 3
Source/cmGeneratorExpressionNode.cxx

@@ -829,12 +829,11 @@ static const struct CompileLanguageNode : public cmGeneratorExpressionNode
     std::string genName = gg->GetName();
     if (genName.find("Visual Studio") != std::string::npos) {
       if (dagChecker && (dagChecker->EvaluatingCompileDefinitions() ||
-                         dagChecker->EvaluatingCompileOptions() ||
                          dagChecker->EvaluatingIncludeDirectories())) {
         reportError(
           context, content->GetOriginalExpression(),
-          "$<COMPILE_LANGUAGE:...> may only be used for file(GENERATE) "
-          "with the Visual Studio generator.");
+          "$<COMPILE_LANGUAGE:...> may only be used for COMPILE_OPTIONS "
+          "and file(GENERATE) with the Visual Studio generator.");
         return std::string();
       }
     } else if (genName.find("Xcode") != std::string::npos) {

+ 12 - 11
Tests/CMakeCommands/target_compile_options/CMakeLists.txt

@@ -23,18 +23,19 @@ add_executable(consumer
   "${CMAKE_CURRENT_SOURCE_DIR}/consumer.cpp"
 )
 
-if (NOT CMAKE_GENERATOR MATCHES "Visual Studio")
-  target_sources(consumer PRIVATE
-    "${CMAKE_CURRENT_SOURCE_DIR}/consumer.c"
-  )
-  target_compile_options(consumer
-    PRIVATE
-      -DCONSUMER_LANG_$<COMPILE_LANGUAGE>
-      -DLANG_IS_CXX=$<COMPILE_LANGUAGE:CXX>
-      -DLANG_IS_C=$<COMPILE_LANGUAGE:C>
-  )
+target_sources(consumer PRIVATE
+  "${CMAKE_CURRENT_SOURCE_DIR}/consumer.c"
+)
+target_compile_options(consumer
+  PRIVATE
+    -DCONSUMER_LANG_$<COMPILE_LANGUAGE>
+    -DLANG_IS_CXX=$<COMPILE_LANGUAGE:CXX>
+    -DLANG_IS_C=$<COMPILE_LANGUAGE:C>
+)
+
+if(CMAKE_GENERATOR MATCHES "Visual Studio")
   target_compile_definitions(consumer
-    PRIVATE -DTEST_LANG_DEFINES
+    PRIVATE TEST_LANG_DEFINES_FOR_VISUAL_STUDIO
   )
 endif()
 

+ 19 - 1
Tests/CMakeCommands/target_compile_options/consumer.c

@@ -1,5 +1,23 @@
 
-#ifdef TEST_LANG_DEFINES
+// Visual Studio allows only one set of flags for C and C++.
+// In a target using C++ we pick the C++ flags even for C sources.
+#ifdef TEST_LANG_DEFINES_FOR_VISUAL_STUDIO
+#ifndef CONSUMER_LANG_CXX
+#error Expected CONSUMER_LANG_CXX
+#endif
+
+#ifdef CONSUMER_LANG_C
+#error Unexpected CONSUMER_LANG_C
+#endif
+
+#if !LANG_IS_CXX
+#error Expected LANG_IS_CXX
+#endif
+
+#if LANG_IS_C
+#error Unexpected LANG_IS_C
+#endif
+#else
 #ifdef CONSUMER_LANG_CXX
 #error Unexpected CONSUMER_LANG_CXX
 #endif

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

@@ -15,7 +15,6 @@
 
 #endif
 
-#ifdef TEST_LANG_DEFINES
 #ifndef CONSUMER_LANG_CXX
 #error Expected CONSUMER_LANG_CXX
 #endif
@@ -31,7 +30,6 @@
 #if LANG_IS_C
 #error Unexpected LANG_IS_C
 #endif
-#endif
 
 int main()
 {

+ 2 - 0
Tests/CudaOnly/WithDefs/CMakeLists.txt

@@ -32,6 +32,8 @@ add_executable(CudaOnlyWithDefs ${main})
 
 target_compile_options(CudaOnlyWithDefs
   PRIVATE
+    -DCOMPILE_LANG_$<COMPILE_LANGUAGE>
+    -DLANG_IS_CUDA=$<COMPILE_LANGUAGE:CUDA>
     -Xcompiler=-DHOST_DEFINE
     $<$<CONFIG:DEBUG>:$<BUILD_INTERFACE:${debug_compile_flags}>>
   )

+ 12 - 0
Tests/CudaOnly/WithDefs/main.notcu

@@ -10,6 +10,18 @@
 #error "PACKED_DEFINE not defined!"
 #endif
 
+#ifndef COMPILE_LANG_CUDA
+#error "COMPILE_LANG_CUDA not defined!"
+#endif
+
+#ifndef LANG_IS_CUDA
+#error "LANG_IS_CUDA not defined!"
+#endif
+
+#if !LANG_IS_CUDA
+#error "Expected LANG_IS_CUDA"
+#endif
+
 static __global__ void DetermineIfValidCudaDevice()
 {
 }

+ 2 - 2
Tests/RunCMake/COMPILE_LANGUAGE-genex/CompileDefinitions-stderr-VS.txt

@@ -3,7 +3,7 @@ CMake Error at CompileDefinitions.cmake:5 \(target_compile_definitions\):
 
     \$<COMPILE_LANGUAGE:CXX>
 
-  \$<COMPILE_LANGUAGE:...> may only be used for file\(GENERATE\) with the Visual
-  Studio generator.
+  \$<COMPILE_LANGUAGE:...> may only be used for COMPILE_OPTIONS and
+  file\(GENERATE\) with the Visual Studio generator.
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)

+ 0 - 1
Tests/RunCMake/COMPILE_LANGUAGE-genex/CompileOptions-result.txt

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

+ 0 - 9
Tests/RunCMake/COMPILE_LANGUAGE-genex/CompileOptions-stderr-VS.txt

@@ -1,9 +0,0 @@
-CMake Error at CompileOptions.cmake:5 \(target_compile_options\):
-  Error evaluating generator expression:
-
-    \$<COMPILE_LANGUAGE:CXX>
-
-  \$<COMPILE_LANGUAGE:...> may only be used for file\(GENERATE\) with the Visual
-  Studio generator.
-Call Stack \(most recent call first\):
-  CMakeLists.txt:3 \(include\)

+ 0 - 5
Tests/RunCMake/COMPILE_LANGUAGE-genex/CompileOptions.cmake

@@ -1,5 +0,0 @@
-
-enable_language(CXX)
-
-add_executable(main main.cpp)
-target_compile_options(main PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-DANYTHING>)

+ 2 - 2
Tests/RunCMake/COMPILE_LANGUAGE-genex/IncludeDirectories-stderr-VS.txt

@@ -3,7 +3,7 @@ CMake Error at IncludeDirectories.cmake:5 \(target_include_directories\):
 
     \$<COMPILE_LANGUAGE:CXX>
 
-  \$<COMPILE_LANGUAGE:...> may only be used for file\(GENERATE\) with the Visual
-  Studio generator.
+  \$<COMPILE_LANGUAGE:...> may only be used for COMPILE_OPTIONS and
+  file\(GENERATE\) with the Visual Studio generator.
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)

+ 0 - 4
Tests/RunCMake/COMPILE_LANGUAGE-genex/RunCMakeTest.cmake

@@ -1,9 +1,5 @@
 include(RunCMake)
 
-if (RunCMake_GENERATOR MATCHES "Visual Studio")
-    set(RunCMake-stderr-file CompileOptions-stderr-VS.txt)
-    run_cmake(CompileOptions)
-endif()
 if (RunCMake_GENERATOR STREQUAL "Xcode")
     set(RunCMake-stderr-file CompileDefinitions-stderr-Xcode.txt)
     run_cmake(CompileDefinitions)