Browse Source

target_compile_options: ensure BEFORE keyword is handled in all scopes

Fixes: #20200
Marc Chevrier 5 years ago
parent
commit
2678e31053

+ 1 - 0
Help/manual/cmake-policies.7.rst

@@ -57,6 +57,7 @@ Policies Introduced by CMake 3.17
 .. toctree::
 .. toctree::
    :maxdepth: 1
    :maxdepth: 1
 
 
+   CMP0101: target_compile_options honors BEFORE keyword in all scopes. </policy/CMP0101>
    CMP0100: Let AUTOMOC and AUTOUIC process .hh header files. </policy/CMP0100>
    CMP0100: Let AUTOMOC and AUTOUIC process .hh header files. </policy/CMP0100>
    CMP0099: Link properties are transitive over private dependency on static libraries. </policy/CMP0099>
    CMP0099: Link properties are transitive over private dependency on static libraries. </policy/CMP0099>
    CMP0098: FindFLEX runs flex in CMAKE_CURRENT_BINARY_DIR when executing. </policy/CMP0098>
    CMP0098: FindFLEX runs flex in CMAKE_CURRENT_BINARY_DIR when executing. </policy/CMP0098>

+ 20 - 0
Help/policy/CMP0101.rst

@@ -0,0 +1,20 @@
+CMP0101
+-------
+
+:command:`target_compile_options` now honors ``BEFORE`` keyword in all scopes.
+
+In CMake 3.16 and below the :command:`target_compile_options` ignores the
+``BEFORE`` keyword in private scope. CMake 3.17 and later honors
+``BEFORE`` keyword in all scopes. This policy provides compatibility for
+projects that have not been updated to expect the new behavior.
+
+The ``OLD`` behavior for this policy is to not honor ``BEFORE`` keyword in
+private scope. The ``NEW`` behavior of this policy is to honor
+``BEFORE`` keyword in all scopes.
+
+This policy was introduced in CMake version 3.17.  Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+Unlike many policies, CMake version |release| does *not* warn
+when this policy is not set and simply uses ``OLD`` behavior.
+
+.. include:: DEPRECATED.txt

+ 5 - 0
Help/release/dev/target_compile_options-BEFORE-keyword.rst

@@ -0,0 +1,5 @@
+target_compile_options-BEFORE-keyword
+-------------------------------------
+
+* :command:`target_compile_options` command learns to honor ``BEFORE`` keyword
+  in all scopes. See policy :policy:`CMP0101`.

+ 3 - 0
Source/cmPolicies.h

@@ -299,6 +299,9 @@ class cmMakefile;
          "libraries.",                                                        \
          "libraries.",                                                        \
          3, 17, 0, cmPolicies::WARN)                                          \
          3, 17, 0, cmPolicies::WARN)                                          \
   SELECT(POLICY, CMP0100, "Let AUTOMOC and AUTOUIC process .hh files.", 3,    \
   SELECT(POLICY, CMP0100, "Let AUTOMOC and AUTOUIC process .hh files.", 3,    \
+         17, 0, cmPolicies::WARN)                                             \
+  SELECT(POLICY, CMP0101,                                                     \
+         "target_compile_options honors BEFORE keyword in all scopes.", 3,    \
          17, 0, cmPolicies::WARN)
          17, 0, cmPolicies::WARN)
 
 
 #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
 #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)

+ 9 - 2
Source/cmTargetCompileOptionsCommand.cxx

@@ -5,6 +5,7 @@
 #include "cmListFileCache.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmMessageType.h"
+#include "cmPolicies.h"
 #include "cmStringAlgorithms.h"
 #include "cmStringAlgorithms.h"
 #include "cmTarget.h"
 #include "cmTarget.h"
 #include "cmTargetPropCommandBase.h"
 #include "cmTargetPropCommandBase.h"
@@ -27,10 +28,16 @@ private:
 
 
   bool HandleDirectContent(cmTarget* tgt,
   bool HandleDirectContent(cmTarget* tgt,
                            const std::vector<std::string>& content,
                            const std::vector<std::string>& content,
-                           bool /*prepend*/, bool /*system*/) override
+                           bool prepend, bool /*system*/) override
   {
   {
+    cmPolicies::PolicyStatus policyStatus =
+      this->Makefile->GetPolicyStatus(cmPolicies::CMP0101);
+    if (policyStatus == cmPolicies::OLD || policyStatus == cmPolicies::WARN) {
+      prepend = false;
+    }
+
     cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
     cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
-    tgt->InsertCompileOption(this->Join(content), lfbt);
+    tgt->InsertCompileOption(this->Join(content), lfbt, prepend);
     return true; // Successfully handled.
     return true; // Successfully handled.
   }
   }
 
 

+ 1 - 1
Tests/RunCMake/CMakeLists.txt

@@ -450,7 +450,7 @@ add_RunCMake_test(target_link_options -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_I
 
 
 add_RunCMake_test(target_compile_definitions)
 add_RunCMake_test(target_compile_definitions)
 add_RunCMake_test(target_compile_features)
 add_RunCMake_test(target_compile_features)
-add_RunCMake_test(target_compile_options)
+add_RunCMake_test(target_compile_options -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID})
 add_RunCMake_test(target_include_directories)
 add_RunCMake_test(target_include_directories)
 add_RunCMake_test(target_sources)
 add_RunCMake_test(target_sources)
 add_RunCMake_test(CheckModules)
 add_RunCMake_test(CheckModules)

+ 8 - 0
Tests/RunCMake/target_compile_options/BEFORE_keyword.cmake

@@ -0,0 +1,8 @@
+
+add_executable (CMP0101_OLD CMP0101.c)
+target_compile_options (main PRIVATE -UBEFORE_KEYWORD)
+target_compile_options (main BEFORE PRIVATE -DBEFORE_KEYWORD)
+
+add_executable (CMP0101_NEW CMP0101.c)
+target_compile_options (main PRIVATE -UBEFORE_KEYWORD)
+target_compile_options (main BEFORE PRIVATE -DBEFORE_KEYWORD)

+ 1 - 0
Tests/RunCMake/target_compile_options/CMP0101-BEFORE_keyword-NEW-result.txt

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

+ 1 - 0
Tests/RunCMake/target_compile_options/CMP0101-BEFORE_keyword-OLD-result.txt

@@ -0,0 +1 @@
+.*

+ 1 - 0
Tests/RunCMake/target_compile_options/CMP0101-BEFORE_keyword-OLD-stdout.txt

@@ -0,0 +1 @@
+BEFORE not honored

+ 15 - 0
Tests/RunCMake/target_compile_options/CMP0101-BEFORE_keyword.cmake

@@ -0,0 +1,15 @@
+
+enable_language(C)
+
+cmake_policy (SET CMP0101 OLD)
+
+add_executable (CMP0101_OLD CMP0101.c)
+target_compile_options (CMP0101_OLD PRIVATE -UBEFORE_KEYWORD)
+target_compile_options (CMP0101_OLD BEFORE PRIVATE -DBEFORE_KEYWORD)
+
+
+cmake_policy (SET CMP0101 NEW)
+
+add_executable (CMP0101_NEW CMP0101.c)
+target_compile_options (CMP0101_NEW PRIVATE -UBEFORE_KEYWORD)
+target_compile_options (CMP0101_NEW BEFORE PRIVATE -DBEFORE_KEYWORD)

+ 9 - 0
Tests/RunCMake/target_compile_options/CMP0101.c

@@ -0,0 +1,9 @@
+
+#if defined(BEFORE_KEYWORD)
+#  error "BEFORE not honored"
+#endif
+
+int main()
+{
+  return 0;
+}

+ 18 - 0
Tests/RunCMake/target_compile_options/RunCMakeTest.cmake

@@ -1,3 +1,21 @@
 include(RunCMake)
 include(RunCMake)
 
 
 run_cmake(empty_keyword_args)
 run_cmake(empty_keyword_args)
+
+if (CMAKE_C_COMPILER_ID MATCHES "GNU|Clang")
+  macro(run_cmake_target test subtest target)
+    set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test}-build)
+    set(RunCMake_TEST_OUTPUT_MERGE 1)
+    set(RunCMake_TEST_NO_CLEAN 1)
+    run_cmake_command(${test}-${subtest} ${CMAKE_COMMAND} --build . --target ${target} ${ARGN})
+
+    unset(RunCMake_TEST_BINARY_DIR)
+    unset(RunCMake_TEST_OUTPUT_MERGE)
+    unset(RunCMake_TEST_NO_CLEAN)
+  endmacro()
+
+  run_cmake(CMP0101-BEFORE_keyword)
+
+  run_cmake_target(CMP0101-BEFORE_keyword OLD CMP0101_OLD)
+  run_cmake_target(CMP0101-BEFORE_keyword NEW CMP0101_NEW)
+endif()