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
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
================================

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`.
* ``CMAKE_POLICY_WARNING_CMP0065`` controls the warning for
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
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",
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)) {
case cmPolicies::WARN:
if (this->Makefile->PolicyOptionalWarningEnabled(

View File

@ -203,7 +203,10 @@ class cmPolicy;
SELECT(POLICY, CMP0065, \
"Do not add flags to export symbols from executables without " \
"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_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(CMP0056)
run_cmake(CMP0066)
if(RunCMake_GENERATOR MATCHES "Make|Ninja")
# Use a single build tree for a few tests without cleaning.

View File

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