try_compile: Add policy CMP0066 to honor CMAKE_<LANG>_FLAGS_<CONFIG>

In the `try_compile` source file signature we propagate the caller's
value of `CMAKE_<LANG>_FLAGS` into the test project.  Extend this to
propagate `CMAKE_<LANG>_FLAGS_<CONFIG>` too instead of always using the
default value in the test project.  This will be useful, for example, to
allow the MSVC runtime library to be changed (e.g. `-MDd` => `-MTd`).
However, some projects may currently depend on this not being done,
so we need to activate the behavior using a policy.

This change was originally made by commit v3.6.0-rc1~160^2 (try_compile:
Honor CMAKE_<LANG>_FLAGS_<CONFIG> changes, 2016-04-11) but without the
policy and so had to be reverted during the 3.6 release candidate cycle.

Fixes #16174.
This commit is contained in:
Brad King 2016-06-28 15:10:18 -04:00
parent 8d79375818
commit d582c23a47
11 changed files with 166 additions and 1 deletions

View File

@ -51,6 +51,14 @@ The :variable:`CMAKE_MINIMUM_REQUIRED_VERSION` variable may also be used
to determine whether to report an error on use of deprecated macros or to determine whether to report an error on use of deprecated macros or
functions. functions.
Policies Introduced by CMake 3.7
================================
.. toctree::
:maxdepth: 1
CMP0066: Honor per-config flags in try_compile() source-file signature. </policy/CMP0066>
Policies Introduced by CMake 3.4 Policies Introduced by CMake 3.4
================================ ================================

27
Help/policy/CMP0066.rst Normal file
View File

@ -0,0 +1,27 @@
CMP0066
-------
Honor per-config flags in :command:`try_compile` source-file signature.
The source file signature of the :command:`try_compile` command uses the value
of the :variable:`CMAKE_<LANG>_FLAGS` variable in the test project so that the
test compilation works as it would in the main project. However, CMake 3.6 and
below do not also honor config-specific compiler flags such as those in the
:variable:`CMAKE_<LANG>_FLAGS_DEBUG` variable. CMake 3.7 and above prefer to
honor config-specific compiler flags too. This policy provides compatibility
for projects that do not expect config-specific compiler flags to be used.
The ``OLD`` behavior of this policy is to ignore config-specific flag
variables like :variable:`CMAKE_<LANG>_FLAGS_DEBUG` and only use CMake's
built-in defaults for the current compiler and platform.
The ``NEW`` behavior of this policy is to honor config-specific flag
variabldes like :variable:`CMAKE_<LANG>_FLAGS_DEBUG`.
This policy was introduced in CMake version 3.7. 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_CMP0066 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
variable to control the warning.
.. include:: DEPRECATED.txt

View File

@ -0,0 +1,7 @@
try_compile-config-flags
------------------------
* The :command:`try_compile` command source file signature now honors
configuration-specific flags (e.g. :variable:`CMAKE_<LANG>_FLAGS_DEBUG`)
in the generated test project. Previously only the default such flags
for the current toolchain were used. See policy :policy:`CMP0066`.

View File

@ -15,6 +15,8 @@ warn by default:
policy :policy:`CMP0060`. policy :policy:`CMP0060`.
* ``CMAKE_POLICY_WARNING_CMP0065`` controls the warning for * ``CMAKE_POLICY_WARNING_CMP0065`` controls the warning for
policy :policy:`CMP0065`. policy :policy:`CMP0065`.
* ``CMAKE_POLICY_WARNING_CMP0066`` controls the warning for
policy :policy:`CMP0066`.
This variable should not be set by a project in CMake code. Project This variable should not be set by a project in CMake code. Project
developers running CMake may set this variable in their cache to developers running CMake may set this variable in their cache to

View File

@ -334,6 +334,43 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
" ${COMPILE_DEFINITIONS}\")\n", " ${COMPILE_DEFINITIONS}\")\n",
li->c_str(), li->c_str()); li->c_str(), li->c_str());
} }
switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0066)) {
case cmPolicies::WARN:
if (this->Makefile->PolicyOptionalWarningEnabled(
"CMAKE_POLICY_WARNING_CMP0066")) {
std::ostringstream w;
/* clang-format off */
w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0066) << "\n"
"For compatibility with older versions of CMake, try_compile "
"is not honoring caller config-specific compiler flags "
"(e.g. CMAKE_C_FLAGS_DEBUG) in the test project."
;
/* clang-format on */
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,
cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0066));
case cmPolicies::NEW: {
// NEW behavior is to pass config-specific compiler flags.
static std::string const cfgDefault = "DEBUG";
std::string const cfg =
!tcConfig.empty() ? cmSystemTools::UpperCase(tcConfig) : cfgDefault;
for (std::set<std::string>::iterator li = testLangs.begin();
li != testLangs.end(); ++li) {
std::string const langFlagsCfg = "CMAKE_" + *li + "_FLAGS_" + cfg;
const char* flagsCfg = this->Makefile->GetDefinition(langFlagsCfg);
fprintf(fout, "set(%s %s)\n", langFlagsCfg.c_str(),
cmOutputConverter::EscapeForCMake(flagsCfg ? flagsCfg : "")
.c_str());
}
} break;
}
switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0056)) { switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0056)) {
case cmPolicies::WARN: case cmPolicies::WARN:
if (this->Makefile->PolicyOptionalWarningEnabled( if (this->Makefile->PolicyOptionalWarningEnabled(

View File

@ -203,7 +203,10 @@ class cmPolicy;
SELECT(POLICY, CMP0065, \ SELECT(POLICY, CMP0065, \
"Do not add flags to export symbols from executables without " \ "Do not add flags to export symbols from executables without " \
"the ENABLE_EXPORTS target property.", \ "the ENABLE_EXPORTS target property.", \
3, 4, 0, cmPolicies::WARN) 3, 4, 0, cmPolicies::WARN) \
SELECT(POLICY, CMP0066, \
"Honor per-config flags in try_compile() source-file signature.", 3, \
7, 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)
#define CM_FOR_EACH_POLICY_ID(POLICY) \ #define CM_FOR_EACH_POLICY_ID(POLICY) \

View File

@ -0,0 +1,15 @@
before try_compile with CMP0066 WARN-default
after try_compile with CMP0066 WARN-default
*
CMake Warning \(dev\) at CMP0066.cmake:[0-9]+ \(try_compile\):
Policy CMP0066 is not set: Honor per-config flags in try_compile\(\)
source-file signature. Run "cmake --help-policy CMP0066" 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 config-specific compiler flags \(e.g. CMAKE_C_FLAGS_DEBUG\) 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.$

View File

@ -0,0 +1,4 @@
-- try_compile with CMP0066 WARN-default worked as expected
-- try_compile with CMP0066 WARN-enabled worked as expected
-- try_compile with CMP0066 OLD worked as expected
-- try_compile with CMP0066 NEW worked as expected

View File

@ -0,0 +1,58 @@
enable_language(C)
set(CMAKE_C_FLAGS_RELEASE "-DPP_ERROR ${CMAKE_C_FLAGS_DEBUG}")
set(CMAKE_TRY_COMPILE_CONFIGURATION Release)
#-----------------------------------------------------------------------------
message("before try_compile with CMP0066 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 with CMP0066 WARN-default failed but should have passed:\n${out}")
else()
message(STATUS "try_compile with CMP0066 WARN-default worked as expected")
endif()
message("after try_compile with CMP0066 WARN-default")
#-----------------------------------------------------------------------------
set(CMAKE_POLICY_WARNING_CMP0066 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 with CMP0066 WARN-enabled failed but should have passed:\n${out}")
else()
message(STATUS "try_compile with CMP0066 WARN-enabled worked as expected")
endif()
#-----------------------------------------------------------------------------
cmake_policy(SET CMP0066 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 with CMP0066 OLD failed but should have passed:\n${out}")
else()
message(STATUS "try_compile with CMP0066 OLD worked as expected")
endif()
#-----------------------------------------------------------------------------
cmake_policy(SET CMP0066 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 with CMP0066 NEW passed but should have failed:\n${out}")
elseif(NOT "x${out}" MATCHES "PP_ERROR is defined")
message(FATAL_ERROR "try_compile with CMP0066 NEW did not fail with PP_ERROR:\n${out}")
else()
message(STATUS "try_compile with CMP0066 NEW worked as expected")
endif()

View File

@ -25,6 +25,7 @@ run_cmake(TargetTypeInvalid)
run_cmake(TargetTypeStatic) run_cmake(TargetTypeStatic)
run_cmake(CMP0056) run_cmake(CMP0056)
run_cmake(CMP0066)
if(RunCMake_GENERATOR MATCHES "Make|Ninja") if(RunCMake_GENERATOR MATCHES "Make|Ninja")
# Use a single build tree for a few tests without cleaning. # Use a single build tree for a few tests without cleaning.

View File

@ -2,3 +2,6 @@ int main(void)
{ {
return 0; return 0;
} }
#ifdef PP_ERROR
#error PP_ERROR is defined
#endif