From 88eb5824da12940e78d57fe254f17f64cdacd659 Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Wed, 3 Dec 2014 11:02:31 -0500
Subject: try_compile: Pass linker flags into test project (#14066)

Copy CMAKE_EXE_LINKER_FLAGS into the test project generated by
try_compile, just like we already copy CMAKE_<LANG>_FLAGS.

Add CMake Policy CMP0056 to activate this behavior in a compatible way,
but do not warn by default when the policy is not set since it will
affect all try_compile calls.

Extend the RunCMake.try_compile test with a case covering this behavior
for each policy setting.
---
 Help/manual/cmake-policies.7.rst               |  1 +
 Help/policy/CMP0056.rst                        | 32 ++++++++++++
 Help/release/dev/try_compile-link-flags.rst    |  6 +++
 Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst |  2 +
 Source/cmCoreTryCompile.cxx                    | 34 +++++++++++++
 Source/cmPolicies.cxx                          |  5 ++
 Source/cmPolicies.h                            |  1 +
 Tests/RunCMake/try_compile/CMP0056-stderr.txt  | 13 +++++
 Tests/RunCMake/try_compile/CMP0056-stdout.txt  |  4 ++
 Tests/RunCMake/try_compile/CMP0056.cmake       | 67 ++++++++++++++++++++++++++
 Tests/RunCMake/try_compile/RunCMakeTest.cmake  |  2 +
 11 files changed, 167 insertions(+)
 create mode 100644 Help/policy/CMP0056.rst
 create mode 100644 Help/release/dev/try_compile-link-flags.rst
 create mode 100644 Tests/RunCMake/try_compile/CMP0056-stderr.txt
 create mode 100644 Tests/RunCMake/try_compile/CMP0056-stdout.txt
 create mode 100644 Tests/RunCMake/try_compile/CMP0056.cmake

diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst
index 742fd63..96f39e6 100644
--- a/Help/manual/cmake-policies.7.rst
+++ b/Help/manual/cmake-policies.7.rst
@@ -113,3 +113,4 @@ All Policies
    /policy/CMP0053
    /policy/CMP0054
    /policy/CMP0055
+   /policy/CMP0056
diff --git a/Help/policy/CMP0056.rst b/Help/policy/CMP0056.rst
new file mode 100644
index 0000000..3c75ff4
--- /dev/null
+++ b/Help/policy/CMP0056.rst
@@ -0,0 +1,32 @@
+CMP0056
+-------
+
+Honor link flags in :command:`try_compile` source-file signature.
+
+The :command:`try_compile` command source-file signature generates a
+``CMakeLists.txt`` file to build the source file into an executable.
+In order to compile the source the same way as it might be compiled
+by the calling project, the generated project sets the value of the
+:variable:`CMAKE_<LANG>_FLAGS` variable to that in the calling project.
+The value of the :variable:`CMAKE_EXE_LINKER_FLAGS` variable may be
+needed in some cases too, but CMake 3.1 and lower did not set it in
+the generated project.  CMake 3.2 and above prefer to set it so that
+linker flags are honored as well as compiler flags.  This policy
+provides compatibility with the pre-3.2 behavior.
+
+The OLD behavior for this policy is to not set the value of the
+:variable:`CMAKE_EXE_LINKER_FLAGS` variable in the generated test
+project.  The NEW behavior for this policy is to set the value of
+the :variable:`CMAKE_EXE_LINKER_FLAGS` variable in the test project
+to the same as it is in the calling project.
+
+If the project code does not set the policy explicitly, users may
+set it on the command line by defining the
+:variable:`CMAKE_POLICY_DEFAULT_CMP0056 <CMAKE_POLICY_DEFAULT_CMP<NNNN>>`
+variable in the cache.
+
+This policy was introduced in CMake version 3.2.  Unlike most policies,
+CMake version |release| does *not* warn by default when this policy
+is not set and simply uses OLD behavior.  See documentation of the
+:variable:`CMAKE_POLICY_WARNING_CMP0056 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
+variable to control the warning.
diff --git a/Help/release/dev/try_compile-link-flags.rst b/Help/release/dev/try_compile-link-flags.rst
new file mode 100644
index 0000000..d995e0b
--- /dev/null
+++ b/Help/release/dev/try_compile-link-flags.rst
@@ -0,0 +1,6 @@
+try_compile-link-flags
+----------------------
+
+* The :command:`try_compile` command source file signature now honors
+  link flags (e.g. :variable:`CMAKE_EXE_LINKER_FLAGS`) in the generated
+  test project.  See policy :policy:`CMP0056`.
diff --git a/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst b/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst
index b563aea..a83c807 100644
--- a/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst
+++ b/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst
@@ -9,6 +9,8 @@ warn by default:
   policy :policy:`CMP0025`.
 * ``CMAKE_POLICY_WARNING_CMP0047`` controls the warning for
   policy :policy:`CMP0047`.
+* ``CMAKE_POLICY_WARNING_CMP0056`` controls the warning for
+  policy :policy:`CMP0056`.
 
 This variable should not be set by a project in CMake code.  Project
 developers running CMake may set this variable in their cache to
diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx
index 3506323..0030b84 100644
--- a/Source/cmCoreTryCompile.cxx
+++ b/Source/cmCoreTryCompile.cxx
@@ -331,6 +331,40 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv)
       fprintf(fout, "set(CMAKE_%s_FLAGS \"${CMAKE_%s_FLAGS}"
               " ${COMPILE_DEFINITIONS}\")\n", li->c_str(), li->c_str());
       }
+    switch(this->Makefile->GetPolicyStatus(cmPolicies::CMP0056))
+      {
+      case cmPolicies::WARN:
+        if(this->Makefile->PolicyOptionalWarningEnabled(
+             "CMAKE_POLICY_WARNING_CMP0056"))
+          {
+          cmOStringStream w;
+          w << (this->Makefile->GetCMakeInstance()->GetPolicies()
+                ->GetPolicyWarning(cmPolicies::CMP0056)) << "\n"
+            "For compatibility with older versions of CMake, try_compile "
+            "is not honoring caller link flags (e.g. CMAKE_EXE_LINKER_FLAGS) "
+            "in the test project."
+            ;
+          this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, w.str());
+          }
+      case cmPolicies::OLD:
+        // OLD behavior is to do nothing.
+        break;
+      case cmPolicies::REQUIRED_IF_USED:
+      case cmPolicies::REQUIRED_ALWAYS:
+        this->Makefile->IssueMessage(
+          cmake::FATAL_ERROR,
+          this->Makefile->GetCMakeInstance()->GetPolicies()
+          ->GetRequiredPolicyError(cmPolicies::CMP0056)
+          );
+      case cmPolicies::NEW:
+        // NEW behavior is to pass linker flags.
+        {
+        const char* exeLinkFlags =
+          this->Makefile->GetDefinition("CMAKE_EXE_LINKER_FLAGS");
+        fprintf(fout, "set(CMAKE_EXE_LINKER_FLAGS %s)\n",
+                lg->EscapeForCMake(exeLinkFlags?exeLinkFlags:"").c_str());
+        } break;
+      }
     fprintf(fout, "set(CMAKE_EXE_LINKER_FLAGS \"${CMAKE_EXE_LINKER_FLAGS}"
             " ${EXE_LINKER_FLAGS}\")\n");
     fprintf(fout, "include_directories(${INCLUDE_DIRECTORIES})\n");
diff --git a/Source/cmPolicies.cxx b/Source/cmPolicies.cxx
index 64b87b7..1a27a25 100644
--- a/Source/cmPolicies.cxx
+++ b/Source/cmPolicies.cxx
@@ -369,6 +369,11 @@ cmPolicies::cmPolicies()
     CMP0055, "CMP0055",
     "Strict checking for break() command.",
     3,2,0, cmPolicies::WARN);
+
+  this->DefinePolicy(
+    CMP0056, "CMP0056",
+    "Honor link flags in try_compile() source-file signature.",
+    3,2,0, cmPolicies::WARN);
 }
 
 cmPolicies::~cmPolicies()
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index 46ecc22..c393c2f 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -112,6 +112,7 @@ public:
     CMP0054, ///< Only interpret if() arguments as variables
     /// or keywords when unquoted.
     CMP0055, ///< Strict checking for break() command.
+    CMP0056, ///< Honor link flags in try_compile() source-file signature.
 
     /** \brief Always the last entry.
      *
diff --git a/Tests/RunCMake/try_compile/CMP0056-stderr.txt b/Tests/RunCMake/try_compile/CMP0056-stderr.txt
new file mode 100644
index 0000000..5c1f0e4
--- /dev/null
+++ b/Tests/RunCMake/try_compile/CMP0056-stderr.txt
@@ -0,0 +1,13 @@
+before try_compile with CMP0056 WARN-default
+after try_compile with CMP0056 WARN-default
+*
+CMake Warning \(dev\) at CMP0056.cmake:[0-9]+ \(try_compile\):
+  Policy CMP0056 is not set: Honor link flags in try_compile\(\) source-file
+  signature.  Run "cmake --help-policy CMP0056" for policy details.  Use the
+  cmake_policy command to set the policy and suppress this warning.
+
+  For compatibility with older versions of CMake, try_compile is not honoring
+  caller link flags \(e.g.  CMAKE_EXE_LINKER_FLAGS\) in the test project.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.$
diff --git a/Tests/RunCMake/try_compile/CMP0056-stdout.txt b/Tests/RunCMake/try_compile/CMP0056-stdout.txt
new file mode 100644
index 0000000..89e7c43
--- /dev/null
+++ b/Tests/RunCMake/try_compile/CMP0056-stdout.txt
@@ -0,0 +1,4 @@
+-- try_compile with CMP0056 WARN-default worked as expected
+-- try_compile with CMP0056 WARN-enabled worked as expected
+-- try_compile with CMP0056 OLD worked as expected
+-- try_compile with CMP0056 NEW worked as expected
diff --git a/Tests/RunCMake/try_compile/CMP0056.cmake b/Tests/RunCMake/try_compile/CMP0056.cmake
new file mode 100644
index 0000000..e8d3d4a
--- /dev/null
+++ b/Tests/RunCMake/try_compile/CMP0056.cmake
@@ -0,0 +1,67 @@
+enable_language(C)
+set(obj "${CMAKE_C_OUTPUT_EXTENSION}")
+if(BORLAND)
+  set(pre -)
+endif()
+set(CMAKE_EXE_LINKER_FLAGS ${pre}BADFLAG${obj})
+
+#-----------------------------------------------------------------------------
+message("before try_compile with CMP0056 WARN-default")
+try_compile(RESULT ${CMAKE_CURRENT_BINARY_DIR}
+  ${CMAKE_CURRENT_SOURCE_DIR}/src.c
+  OUTPUT_VARIABLE out
+  )
+string(REPLACE "\n" "\n  " out "  ${out}")
+if(NOT RESULT)
+  message(FATAL_ERROR "try_compile failed but should have passed:\n${out}")
+elseif("x${out}" MATCHES "BADFLAG")
+  message(FATAL_ERROR "try_compile output mentions BADFLAG:\n${out}")
+else()
+  message(STATUS "try_compile with CMP0056 WARN-default worked as expected")
+endif()
+message("after try_compile with CMP0056 WARN-default")
+
+#-----------------------------------------------------------------------------
+set(CMAKE_POLICY_WARNING_CMP0056 ON)
+try_compile(RESULT ${CMAKE_CURRENT_BINARY_DIR}
+  ${CMAKE_CURRENT_SOURCE_DIR}/src.c
+  OUTPUT_VARIABLE out
+  )
+string(REPLACE "\n" "\n  " out "  ${out}")
+if(NOT RESULT)
+  message(FATAL_ERROR "try_compile failed but should have passed:\n${out}")
+elseif("x${out}" MATCHES "BADFLAG")
+  message(FATAL_ERROR "try_compile output mentions BADFLAG:\n${out}")
+else()
+  message(STATUS "try_compile with CMP0056 WARN-enabled worked as expected")
+endif()
+
+#-----------------------------------------------------------------------------
+cmake_policy(SET CMP0056 OLD)
+try_compile(RESULT ${CMAKE_CURRENT_BINARY_DIR}
+  ${CMAKE_CURRENT_SOURCE_DIR}/src.c
+  OUTPUT_VARIABLE out
+  )
+string(REPLACE "\n" "\n  " out "  ${out}")
+if(NOT RESULT)
+  message(FATAL_ERROR "try_compile failed but should have passed:\n${out}")
+elseif("x${out}" MATCHES "BADFLAG")
+  message(FATAL_ERROR "try_compile output mentions BADFLAG:\n${out}")
+else()
+  message(STATUS "try_compile with CMP0056 OLD worked as expected")
+endif()
+
+#-----------------------------------------------------------------------------
+cmake_policy(SET CMP0056 NEW)
+try_compile(RESULT ${CMAKE_CURRENT_BINARY_DIR}
+  ${CMAKE_CURRENT_SOURCE_DIR}/src.c
+  OUTPUT_VARIABLE out
+  )
+string(REPLACE "\n" "\n  " out "  ${out}")
+if(RESULT)
+  message(FATAL_ERROR "try_compile passed but should have failed:\n${out}")
+elseif(NOT "x${out}" MATCHES "BADFLAG")
+  message(FATAL_ERROR "try_compile did not fail with BADFLAG:\n${out}")
+else()
+  message(STATUS "try_compile with CMP0056 NEW worked as expected")
+endif()
diff --git a/Tests/RunCMake/try_compile/RunCMakeTest.cmake b/Tests/RunCMake/try_compile/RunCMakeTest.cmake
index c934458..06096b2 100644
--- a/Tests/RunCMake/try_compile/RunCMakeTest.cmake
+++ b/Tests/RunCMake/try_compile/RunCMakeTest.cmake
@@ -15,3 +15,5 @@ run_cmake(BadSources1)
 run_cmake(BadSources2)
 run_cmake(NonSourceCopyFile)
 run_cmake(NonSourceCompileDefinitions)
+
+run_cmake(CMP0056)
-- 
cgit v0.12