diff options
author | Brad King <brad.king@kitware.com> | 2016-12-01 20:46:34 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2016-12-06 13:58:42 (GMT) |
commit | f72ba42b7c643b1b217d1b8f6684cec3289e7201 (patch) | |
tree | 7277ccca7c933e26b2cfc4aba2401477d7125408 | |
parent | 45aa03b97aeeb512264ac2bfbb2028330be254d1 (diff) | |
download | CMake-f72ba42b7c643b1b217d1b8f6684cec3289e7201.zip CMake-f72ba42b7c643b1b217d1b8f6684cec3289e7201.tar.gz CMake-f72ba42b7c643b1b217d1b8f6684cec3289e7201.tar.bz2 |
try_compile: Add policy CMP0067 to honor language standards
Projects use `try_compile` to check if they will be able to compile some
particular source code. When a language standard variable like
`CMAKE_CXX_STANDARD` is set, then the project intends to compile source
code using a compiler mode for that standard. Therefore it makes sense
for `try_compile` to use that standard in the test project too.
Unfortunately this was not done when support for the
`CMAKE_CXX_STANDARD` variable was first implemented. Add a policy to
introduce the improved behavior in a compatible way.
Closes: #16456
-rw-r--r-- | Help/command/try_compile.rst | 14 | ||||
-rw-r--r-- | Help/manual/cmake-policies.7.rst | 8 | ||||
-rw-r--r-- | Help/policy/CMP0067.rst | 34 | ||||
-rw-r--r-- | Help/release/dev/try_compile-lang-std.rst | 4 | ||||
-rw-r--r-- | Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst | 2 | ||||
-rw-r--r-- | Source/cmCoreTryCompile.cxx | 79 | ||||
-rw-r--r-- | Source/cmCoreTryCompile.h | 4 | ||||
-rw-r--r-- | Source/cmPolicies.h | 5 | ||||
-rw-r--r-- | Tests/RunCMake/try_compile/CMP0067-stderr.txt | 25 | ||||
-rw-r--r-- | Tests/RunCMake/try_compile/CMP0067.cmake | 40 | ||||
-rw-r--r-- | Tests/RunCMake/try_compile/CStandardGNU.cmake | 12 | ||||
-rw-r--r-- | Tests/RunCMake/try_compile/CxxStandardGNU.cmake | 12 | ||||
-rw-r--r-- | Tests/RunCMake/try_compile/RunCMakeTest.cmake | 1 |
13 files changed, 239 insertions, 1 deletions
diff --git a/Help/command/try_compile.rst b/Help/command/try_compile.rst index 3f16b63..cde3776 100644 --- a/Help/command/try_compile.rst +++ b/Help/command/try_compile.rst @@ -135,3 +135,17 @@ the type of target used for the source file signature. Set the :variable:`CMAKE_TRY_COMPILE_PLATFORM_VARIABLES` variable to specify variables that must be propagated into the test project. This variable is meant for use only in toolchain files. + +If :policy:`CMP0067` is set to ``NEW``, or any of the ``<LANG>_STANDARD``, +``<LANG>_STANDARD_REQUIRED``, or ``<LANG>_EXTENSIONS`` options are used, +then the language standard variables are honored: + +* :variable:`CMAKE_C_STANDARD` +* :variable:`CMAKE_C_STANDARD_REQUIRED` +* :variable:`CMAKE_C_EXTENSIONS` +* :variable:`CMAKE_CXX_STANDARD` +* :variable:`CMAKE_CXX_STANDARD_REQUIRED` +* :variable:`CMAKE_CXX_EXTENSIONS` + +Their values are used to set the corresponding target properties in +the generated project (unless overridden by an explicit option). diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst index 0cfe983..3266958 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.8 +================================ + +.. toctree:: + :maxdepth: 1 + + CMP0067: Honor language standard in try_compile() source-file signature. </policy/CMP0067> + Policies Introduced by CMake 3.7 ================================ diff --git a/Help/policy/CMP0067.rst b/Help/policy/CMP0067.rst new file mode 100644 index 0000000..d52ba7f --- /dev/null +++ b/Help/policy/CMP0067.rst @@ -0,0 +1,34 @@ +CMP0067 +------- + +Honor language standard in :command:`try_compile` source-file signature. + +The :command:`try_compile` source file signature is intended to allow +callers to check whether they will be able to compile a given source file +with the current toolchain. In order to match compiler behavior, any +language standard mode should match. However, CMake 3.7 and below did not +do this. CMake 3.8 and above prefer to honor the language standard settings +for ``C`` and ``CXX`` (C++) using the values of the variables: + +* :variable:`CMAKE_C_STANDARD` +* :variable:`CMAKE_C_STANDARD_REQUIRED` +* :variable:`CMAKE_C_EXTENSIONS` +* :variable:`CMAKE_CXX_STANDARD` +* :variable:`CMAKE_CXX_STANDARD_REQUIRED` +* :variable:`CMAKE_CXX_EXTENSIONS` + +This policy provides compatibility for projects that do not expect +the language standard settings to be used automatically. + +The ``OLD`` behavior of this policy is to ignore language standard +setting variables when generating the ``try_compile`` test project. +The ``NEW`` behavior of this policy is to honor language standard +setting variables. + +This policy was introduced in CMake version 3.8. 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_CMP0067 <CMAKE_POLICY_WARNING_CMP<NNNN>>` +variable to control the warning. + +.. include:: DEPRECATED.txt diff --git a/Help/release/dev/try_compile-lang-std.rst b/Help/release/dev/try_compile-lang-std.rst index 64d082b..849cecc 100644 --- a/Help/release/dev/try_compile-lang-std.rst +++ b/Help/release/dev/try_compile-lang-std.rst @@ -3,3 +3,7 @@ try_compile-lang-std * The :command:`try_compile` command source file signature gained new options to specify the language standard to use in the generated test project. + +* The :command:`try_compile` command source file signature now honors + language standard variables like :variable:`CMAKE_CXX_STANDARD`. + See policy :policy:`CMP0067`. diff --git a/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst b/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst index 36cf75f..aa23b65 100644 --- a/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst +++ b/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst @@ -17,6 +17,8 @@ warn by default: policy :policy:`CMP0065`. * ``CMAKE_POLICY_WARNING_CMP0066`` controls the warning for policy :policy:`CMP0066`. +* ``CMAKE_POLICY_WARNING_CMP0067`` controls the warning for + policy :policy:`CMP0067`. 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 3b72440..1b7180c 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -54,6 +54,17 @@ static void writeProperty(FILE* fout, std::string const& targetName, cmOutputConverter::EscapeForCMake(value).c_str()); } +std::string cmCoreTryCompile::LookupStdVar(std::string const& var, + bool warnCMP0067) +{ + std::string value = this->Makefile->GetSafeDefinition(var); + if (warnCMP0067 && !value.empty()) { + value.clear(); + this->WarnCMP0067.push_back(var); + } + return value; +} + int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, bool isTryRun) { @@ -620,6 +631,74 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, bool const testC = testLangs.find("C") != testLangs.end(); bool const testCxx = testLangs.find("CXX") != testLangs.end(); + bool warnCMP0067 = false; + bool honorStandard = true; + + if (!didCStandard && !didCxxStandard && !didCStandardRequired && + !didCxxStandardRequired && !didCExtensions && !didCxxExtensions) { + switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0067)) { + case cmPolicies::WARN: + warnCMP0067 = this->Makefile->PolicyOptionalWarningEnabled( + "CMAKE_POLICY_WARNING_CMP0067"); + case cmPolicies::OLD: + // OLD behavior is to not honor the language standard variables. + honorStandard = false; + break; + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + this->Makefile->IssueMessage( + cmake::FATAL_ERROR, + cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0067)); + case cmPolicies::NEW: + // NEW behavior is to honor the language standard variables. + // We already initialized honorStandard to true. + break; + } + } + + if (honorStandard || warnCMP0067) { + if (testC) { + if (!didCStandard) { + cStandard = this->LookupStdVar("CMAKE_C_STANDARD", warnCMP0067); + } + if (!didCStandardRequired) { + cStandardRequired = + this->LookupStdVar("CMAKE_C_STANDARD_REQUIRED", warnCMP0067); + } + if (!didCExtensions) { + cExtensions = this->LookupStdVar("CMAKE_C_EXTENSIONS", warnCMP0067); + } + } + if (testCxx) { + if (!didCxxStandard) { + cxxStandard = this->LookupStdVar("CMAKE_CXX_STANDARD", warnCMP0067); + } + if (!didCxxStandardRequired) { + cxxStandardRequired = + this->LookupStdVar("CMAKE_CXX_STANDARD_REQUIRED", warnCMP0067); + } + if (!didCxxExtensions) { + cxxExtensions = + this->LookupStdVar("CMAKE_CXX_EXTENSIONS", warnCMP0067); + } + } + } + + if (!this->WarnCMP0067.empty()) { + std::ostringstream w; + /* clang-format off */ + w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0067) << "\n" + "For compatibility with older versions of CMake, try_compile " + "is not honoring language standard variables in the test project:\n" + ; + /* clang-format on */ + for (std::vector<std::string>::iterator vi = this->WarnCMP0067.begin(); + vi != this->WarnCMP0067.end(); ++vi) { + w << " " << *vi << "\n"; + } + this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, w.str()); + } + if (testC) { if (!cStandard.empty()) { writeProperty(fout, targetName, "C_STANDARD", cStandard); diff --git a/Source/cmCoreTryCompile.h b/Source/cmCoreTryCompile.h index 1c94f09..4b96aed 100644 --- a/Source/cmCoreTryCompile.h +++ b/Source/cmCoreTryCompile.h @@ -47,6 +47,10 @@ protected: std::string OutputFile; std::string FindErrorMessage; bool SrcFileSignature; + +private: + std::vector<std::string> WarnCMP0067; + std::string LookupStdVar(std::string const& var, bool warnCMP0067); }; #endif diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index 9b86435..62e67c7 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -197,7 +197,10 @@ class cmMakefile; 3, 4, 0, cmPolicies::WARN) \ SELECT(POLICY, CMP0066, \ "Honor per-config flags in try_compile() source-file signature.", 3, \ - 7, 0, cmPolicies::WARN) + 7, 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0067, \ + "Honor language standard in try_compile() source-file signature.", \ + 3, 8, 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/CMP0067-stderr.txt b/Tests/RunCMake/try_compile/CMP0067-stderr.txt new file mode 100644 index 0000000..e2677ed --- /dev/null +++ b/Tests/RunCMake/try_compile/CMP0067-stderr.txt @@ -0,0 +1,25 @@ +before try_compile with CMP0067 WARN-enabled but no variables +after try_compile with CMP0067 WARN-enabled but no variables +before try_compile with CMP0067 WARN-default +after try_compile with CMP0067 WARN-default +before try_compile with CMP0067 WARN-enabled +CMake Warning \(dev\) at CMP0067.cmake:[0-9]+ \(try_compile\): + Policy CMP0067 is not set: Honor language standard in try_compile\(\) + source-file signature. Run "cmake --help-policy CMP0067" 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 + language standard variables in the test project: + + CMAKE_C_STANDARD + +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) +This warning is for project developers. Use -Wno-dev to suppress it. + +after try_compile with CMP0067 WARN-enabled +before try_compile with CMP0067 OLD +after try_compile with CMP0067 OLD +before try_compile with CMP0067 NEW +after try_compile with CMP0067 NEW diff --git a/Tests/RunCMake/try_compile/CMP0067.cmake b/Tests/RunCMake/try_compile/CMP0067.cmake new file mode 100644 index 0000000..dd05d96 --- /dev/null +++ b/Tests/RunCMake/try_compile/CMP0067.cmake @@ -0,0 +1,40 @@ +enable_language(C) + +set(CMAKE_POLICY_WARNING_CMP0067 ON) +message("before try_compile with CMP0067 WARN-enabled but no variables") +try_compile(RESULT ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/src.c + ) +message("after try_compile with CMP0067 WARN-enabled but no variables") +set(CMAKE_POLICY_WARNING_CMP0067 OFF) + +#----------------------------------------------------------------------------- + +set(CMAKE_C_STANDARD 90) + +message("before try_compile with CMP0067 WARN-default") +try_compile(RESULT ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/src.c + ) +message("after try_compile with CMP0067 WARN-default") + +set(CMAKE_POLICY_WARNING_CMP0067 ON) +message("before try_compile with CMP0067 WARN-enabled") +try_compile(RESULT ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/src.c + ) +message("after try_compile with CMP0067 WARN-enabled") + +cmake_policy(SET CMP0067 OLD) +message("before try_compile with CMP0067 OLD") +try_compile(RESULT ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/src.c + ) +message("after try_compile with CMP0067 OLD") + +cmake_policy(SET CMP0066 NEW) +message("before try_compile with CMP0067 NEW") +try_compile(RESULT ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/src.c + ) +message("after try_compile with CMP0067 NEW") diff --git a/Tests/RunCMake/try_compile/CStandardGNU.cmake b/Tests/RunCMake/try_compile/CStandardGNU.cmake index 29ce315..79ae874 100644 --- a/Tests/RunCMake/try_compile/CStandardGNU.cmake +++ b/Tests/RunCMake/try_compile/CStandardGNU.cmake @@ -9,3 +9,15 @@ try_compile(result ${CMAKE_CURRENT_BINARY_DIR} if(NOT result) message(FATAL_ERROR "try_compile failed:\n${out}") endif() + +cmake_policy(SET CMP0067 NEW) +set(CMAKE_C_STANDARD 99) +set(CMAKE_C_STANDARD_REQUIRED 1) +set(CMAKE_C_EXTENSIONS 0) +try_compile(result ${CMAKE_CURRENT_BINARY_DIR} + SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/CStandardGNU.c + OUTPUT_VARIABLE out + ) +if(NOT result) + message(FATAL_ERROR "try_compile failed:\n${out}") +endif() diff --git a/Tests/RunCMake/try_compile/CxxStandardGNU.cmake b/Tests/RunCMake/try_compile/CxxStandardGNU.cmake index cc16bea..e714fe4 100644 --- a/Tests/RunCMake/try_compile/CxxStandardGNU.cmake +++ b/Tests/RunCMake/try_compile/CxxStandardGNU.cmake @@ -9,3 +9,15 @@ try_compile(result ${CMAKE_CURRENT_BINARY_DIR} if(NOT result) message(FATAL_ERROR "try_compile failed:\n${out}") endif() + +cmake_policy(SET CMP0067 NEW) +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED 1) +set(CMAKE_CXX_EXTENSIONS 0) +try_compile(result ${CMAKE_CURRENT_BINARY_DIR} + SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/CxxStandardGNU.cxx + OUTPUT_VARIABLE out + ) +if(NOT result) + message(FATAL_ERROR "try_compile failed:\n${out}") +endif() diff --git a/Tests/RunCMake/try_compile/RunCMakeTest.cmake b/Tests/RunCMake/try_compile/RunCMakeTest.cmake index dadcf35..d1b0217 100644 --- a/Tests/RunCMake/try_compile/RunCMakeTest.cmake +++ b/Tests/RunCMake/try_compile/RunCMakeTest.cmake @@ -44,6 +44,7 @@ endif() run_cmake(CMP0056) run_cmake(CMP0066) +run_cmake(CMP0067) if(RunCMake_GENERATOR MATCHES "Make|Ninja") # Use a single build tree for a few tests without cleaning. |