diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst index 43f4637fb..0cfe98389 100644 --- a/Help/manual/cmake-policies.7.rst +++ b/Help/manual/cmake-policies.7.rst @@ -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. + Policies Introduced by CMake 3.4 ================================ diff --git a/Help/policy/CMP0066.rst b/Help/policy/CMP0066.rst new file mode 100644 index 000000000..d1dcb0ec6 --- /dev/null +++ b/Help/policy/CMP0066.rst @@ -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__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__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__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__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 >` +variable to control the warning. + +.. include:: DEPRECATED.txt diff --git a/Help/release/dev/try_compile-config-flags.rst b/Help/release/dev/try_compile-config-flags.rst new file mode 100644 index 000000000..ebfd6a4cc --- /dev/null +++ b/Help/release/dev/try_compile-config-flags.rst @@ -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__FLAGS_DEBUG`) + in the generated test project. Previously only the default such flags + for the current toolchain were used. See policy :policy:`CMP0066`. diff --git a/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst b/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst index 582f9e495..36cf75f59 100644 --- a/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst +++ b/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst @@ -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 diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx index 805d8e864..e9367b133 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -334,6 +334,43 @@ int cmCoreTryCompile::TryCompileCode(std::vector 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::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( diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index ff49e3163..0c8ff6039 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -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) \ diff --git a/Tests/RunCMake/try_compile/CMP0066-stderr.txt b/Tests/RunCMake/try_compile/CMP0066-stderr.txt new file mode 100644 index 000000000..b14e2900e --- /dev/null +++ b/Tests/RunCMake/try_compile/CMP0066-stderr.txt @@ -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.$ diff --git a/Tests/RunCMake/try_compile/CMP0066-stdout.txt b/Tests/RunCMake/try_compile/CMP0066-stdout.txt new file mode 100644 index 000000000..1eb2f8352 --- /dev/null +++ b/Tests/RunCMake/try_compile/CMP0066-stdout.txt @@ -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 diff --git a/Tests/RunCMake/try_compile/CMP0066.cmake b/Tests/RunCMake/try_compile/CMP0066.cmake new file mode 100644 index 000000000..4b95251a0 --- /dev/null +++ b/Tests/RunCMake/try_compile/CMP0066.cmake @@ -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() diff --git a/Tests/RunCMake/try_compile/RunCMakeTest.cmake b/Tests/RunCMake/try_compile/RunCMakeTest.cmake index 4f30f1d40..522433aee 100644 --- a/Tests/RunCMake/try_compile/RunCMakeTest.cmake +++ b/Tests/RunCMake/try_compile/RunCMakeTest.cmake @@ -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. diff --git a/Tests/RunCMake/try_compile/src.c b/Tests/RunCMake/try_compile/src.c index 8488f4e58..5e513825c 100644 --- a/Tests/RunCMake/try_compile/src.c +++ b/Tests/RunCMake/try_compile/src.c @@ -2,3 +2,6 @@ int main(void) { return 0; } +#ifdef PP_ERROR +#error PP_ERROR is defined +#endif