Kaynağa Gözat

Merge topic 'try_compile-lang-std'

f72ba42b try_compile: Add policy CMP0067 to honor language standards
45aa03b9 try_compile: Add options to specify language standards
3bb2051e try_compile: Stop processing when test build system fails to generate
Brad King 9 yıl önce
ebeveyn
işleme
a0d64ecf8b

+ 31 - 1
Help/command/try_compile.rst

@@ -35,7 +35,11 @@ Try Compiling Source Files
               [COMPILE_DEFINITIONS <defs>...]
               [COMPILE_DEFINITIONS <defs>...]
               [LINK_LIBRARIES <libs>...]
               [LINK_LIBRARIES <libs>...]
               [OUTPUT_VARIABLE <var>]
               [OUTPUT_VARIABLE <var>]
-              [COPY_FILE <fileName> [COPY_FILE_ERROR <var>]])
+              [COPY_FILE <fileName> [COPY_FILE_ERROR <var>]]
+              [<LANG>_STANDARD <std>]
+              [<LANG>_STANDARD_REQUIRED <bool>]
+              [<LANG>_EXTENSIONS <bool>]
+              )
 
 
 Try building an executable from one or more source files.  The success or
 Try building an executable from one or more source files.  The success or
 failure of the ``try_compile``, i.e. ``TRUE`` or ``FALSE`` respectively, is
 failure of the ``try_compile``, i.e. ``TRUE`` or ``FALSE`` respectively, is
@@ -82,6 +86,18 @@ The options are:
 ``OUTPUT_VARIABLE <var>``
 ``OUTPUT_VARIABLE <var>``
   Store the output from the build process the given variable.
   Store the output from the build process the given variable.
 
 
+``<LANG>_STANDARD <std>``
+  Specify the :prop_tgt:`C_STANDARD` or :prop_tgt:`CXX_STANDARD`
+  target property of the generated project.
+
+``<LANG>_STANDARD_REQUIRED <bool>``
+  Specify the :prop_tgt:`C_STANDARD_REQUIRED` or
+  :prop_tgt:`CXX_STANDARD_REQUIRED` target property of the generated project.
+
+``<LANG>_EXTENSIONS <bool>``
+  Specify the :prop_tgt:`C_EXTENSIONS` or :prop_tgt:`CXX_EXTENSIONS`
+  target property of the generated project.
+
 In this version all files in ``<bindir>/CMakeFiles/CMakeTmp`` will be
 In this version all files in ``<bindir>/CMakeFiles/CMakeTmp`` will be
 cleaned automatically.  For debugging, ``--debug-trycompile`` can be
 cleaned automatically.  For debugging, ``--debug-trycompile`` can be
 passed to ``cmake`` to avoid this clean.  However, multiple sequential
 passed to ``cmake`` to avoid this clean.  However, multiple sequential
@@ -119,3 +135,17 @@ the type of target used for the source file signature.
 Set the :variable:`CMAKE_TRY_COMPILE_PLATFORM_VARIABLES` variable to specify
 Set the :variable:`CMAKE_TRY_COMPILE_PLATFORM_VARIABLES` variable to specify
 variables that must be propagated into the test project.  This variable is
 variables that must be propagated into the test project.  This variable is
 meant for use only in toolchain files.
 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).

+ 8 - 0
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
 to determine whether to report an error on use of deprecated macros or
 functions.
 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
 Policies Introduced by CMake 3.7
 ================================
 ================================
 
 

+ 34 - 0
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

+ 9 - 0
Help/release/dev/try_compile-lang-std.rst

@@ -0,0 +1,9 @@
+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`.

+ 2 - 0
Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst

@@ -17,6 +17,8 @@ warn by default:
   policy :policy:`CMP0065`.
   policy :policy:`CMP0065`.
 * ``CMAKE_POLICY_WARNING_CMP0066`` controls the warning for
 * ``CMAKE_POLICY_WARNING_CMP0066`` controls the warning for
   policy :policy:`CMP0066`.
   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
 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

+ 207 - 0
Source/cmCoreTryCompile.cxx

@@ -46,6 +46,25 @@ static std::string const kCMAKE_TRY_COMPILE_PLATFORM_VARIABLES =
   "CMAKE_TRY_COMPILE_PLATFORM_VARIABLES";
   "CMAKE_TRY_COMPILE_PLATFORM_VARIABLES";
 static std::string const kCMAKE_WARN_DEPRECATED = "CMAKE_WARN_DEPRECATED";
 static std::string const kCMAKE_WARN_DEPRECATED = "CMAKE_WARN_DEPRECATED";
 
 
+static void writeProperty(FILE* fout, std::string const& targetName,
+                          std::string const& prop, std::string const& value)
+{
+  fprintf(fout, "set_property(TARGET %s PROPERTY %s %s)\n", targetName.c_str(),
+          cmOutputConverter::EscapeForCMake(prop).c_str(),
+          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,
 int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
                                      bool isTryRun)
                                      bool isTryRun)
 {
 {
@@ -87,6 +106,12 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
   std::string outputVariable;
   std::string outputVariable;
   std::string copyFile;
   std::string copyFile;
   std::string copyFileError;
   std::string copyFileError;
+  std::string cStandard;
+  std::string cxxStandard;
+  std::string cStandardRequired;
+  std::string cxxStandardRequired;
+  std::string cExtensions;
+  std::string cxxExtensions;
   std::vector<std::string> targets;
   std::vector<std::string> targets;
   std::string libsToLink = " ";
   std::string libsToLink = " ";
   bool useOldLinkLibs = true;
   bool useOldLinkLibs = true;
@@ -94,6 +119,12 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
   bool didOutputVariable = false;
   bool didOutputVariable = false;
   bool didCopyFile = false;
   bool didCopyFile = false;
   bool didCopyFileError = false;
   bool didCopyFileError = false;
+  bool didCStandard = false;
+  bool didCxxStandard = false;
+  bool didCStandardRequired = false;
+  bool didCxxStandardRequired = false;
+  bool didCExtensions = false;
+  bool didCxxExtensions = false;
   bool useSources = argv[2] == "SOURCES";
   bool useSources = argv[2] == "SOURCES";
   std::vector<std::string> sources;
   std::vector<std::string> sources;
 
 
@@ -106,6 +137,12 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
     DoingOutputVariable,
     DoingOutputVariable,
     DoingCopyFile,
     DoingCopyFile,
     DoingCopyFileError,
     DoingCopyFileError,
+    DoingCStandard,
+    DoingCxxStandard,
+    DoingCStandardRequired,
+    DoingCxxStandardRequired,
+    DoingCExtensions,
+    DoingCxxExtensions,
     DoingSources
     DoingSources
   };
   };
   Doing doing = useSources ? DoingSources : DoingNone;
   Doing doing = useSources ? DoingSources : DoingNone;
@@ -126,6 +163,24 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
     } else if (argv[i] == "COPY_FILE_ERROR") {
     } else if (argv[i] == "COPY_FILE_ERROR") {
       doing = DoingCopyFileError;
       doing = DoingCopyFileError;
       didCopyFileError = true;
       didCopyFileError = true;
+    } else if (argv[i] == "C_STANDARD") {
+      doing = DoingCStandard;
+      didCStandard = true;
+    } else if (argv[i] == "CXX_STANDARD") {
+      doing = DoingCxxStandard;
+      didCxxStandard = true;
+    } else if (argv[i] == "C_STANDARD_REQUIRED") {
+      doing = DoingCStandardRequired;
+      didCStandardRequired = true;
+    } else if (argv[i] == "CXX_STANDARD_REQUIRED") {
+      doing = DoingCxxStandardRequired;
+      didCxxStandardRequired = true;
+    } else if (argv[i] == "C_EXTENSIONS") {
+      doing = DoingCExtensions;
+      didCExtensions = true;
+    } else if (argv[i] == "CXX_EXTENSIONS") {
+      doing = DoingCxxExtensions;
+      didCxxExtensions = true;
     } else if (doing == DoingCMakeFlags) {
     } else if (doing == DoingCMakeFlags) {
       cmakeFlags.push_back(argv[i]);
       cmakeFlags.push_back(argv[i]);
     } else if (doing == DoingCompileDefinitions) {
     } else if (doing == DoingCompileDefinitions) {
@@ -166,6 +221,24 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
     } else if (doing == DoingCopyFileError) {
     } else if (doing == DoingCopyFileError) {
       copyFileError = argv[i];
       copyFileError = argv[i];
       doing = DoingNone;
       doing = DoingNone;
+    } else if (doing == DoingCStandard) {
+      cStandard = argv[i];
+      doing = DoingNone;
+    } else if (doing == DoingCxxStandard) {
+      cxxStandard = argv[i];
+      doing = DoingNone;
+    } else if (doing == DoingCStandardRequired) {
+      cStandardRequired = argv[i];
+      doing = DoingNone;
+    } else if (doing == DoingCxxStandardRequired) {
+      cxxStandardRequired = argv[i];
+      doing = DoingNone;
+    } else if (doing == DoingCExtensions) {
+      cExtensions = argv[i];
+      doing = DoingNone;
+    } else if (doing == DoingCxxExtensions) {
+      cxxExtensions = argv[i];
+      doing = DoingNone;
     } else if (doing == DoingSources) {
     } else if (doing == DoingSources) {
       sources.push_back(argv[i]);
       sources.push_back(argv[i]);
     } else if (i == 3) {
     } else if (i == 3) {
@@ -213,6 +286,42 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
     return -1;
     return -1;
   }
   }
 
 
+  if (didCStandard && !this->SrcFileSignature) {
+    this->Makefile->IssueMessage(
+      cmake::FATAL_ERROR, "C_STANDARD allowed only in source file signature.");
+    return -1;
+  }
+  if (didCxxStandard && !this->SrcFileSignature) {
+    this->Makefile->IssueMessage(
+      cmake::FATAL_ERROR,
+      "CXX_STANDARD allowed only in source file signature.");
+    return -1;
+  }
+  if (didCStandardRequired && !this->SrcFileSignature) {
+    this->Makefile->IssueMessage(
+      cmake::FATAL_ERROR,
+      "C_STANDARD_REQUIRED allowed only in source file signature.");
+    return -1;
+  }
+  if (didCxxStandardRequired && !this->SrcFileSignature) {
+    this->Makefile->IssueMessage(
+      cmake::FATAL_ERROR,
+      "CXX_STANDARD_REQUIRED allowed only in source file signature.");
+    return -1;
+  }
+  if (didCExtensions && !this->SrcFileSignature) {
+    this->Makefile->IssueMessage(
+      cmake::FATAL_ERROR,
+      "C_EXTENSIONS allowed only in source file signature.");
+    return -1;
+  }
+  if (didCxxExtensions && !this->SrcFileSignature) {
+    this->Makefile->IssueMessage(
+      cmake::FATAL_ERROR,
+      "CXX_EXTENSIONS allowed only in source file signature.");
+    return -1;
+  }
+
   // compute the binary dir when TRY_COMPILE is called with a src file
   // compute the binary dir when TRY_COMPILE is called with a src file
   // signature
   // signature
   if (this->SrcFileSignature) {
   if (this->SrcFileSignature) {
@@ -518,6 +627,104 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
       }
       }
     }
     }
     fprintf(fout, ")\n");
     fprintf(fout, ")\n");
+
+    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);
+      }
+      if (!cStandardRequired.empty()) {
+        writeProperty(fout, targetName, "C_STANDARD_REQUIRED",
+                      cStandardRequired);
+      }
+      if (!cExtensions.empty()) {
+        writeProperty(fout, targetName, "C_EXTENSIONS", cExtensions);
+      }
+    }
+
+    if (testCxx) {
+      if (!cxxStandard.empty()) {
+        writeProperty(fout, targetName, "CXX_STANDARD", cxxStandard);
+      }
+      if (!cxxStandardRequired.empty()) {
+        writeProperty(fout, targetName, "CXX_STANDARD_REQUIRED",
+                      cxxStandardRequired);
+      }
+      if (!cxxExtensions.empty()) {
+        writeProperty(fout, targetName, "CXX_EXTENSIONS", cxxExtensions);
+      }
+    }
+
     if (useOldLinkLibs) {
     if (useOldLinkLibs) {
       fprintf(fout, "target_link_libraries(%s ${LINK_LIBRARIES})\n",
       fprintf(fout, "target_link_libraries(%s ${LINK_LIBRARIES})\n",
               targetName.c_str());
               targetName.c_str());

+ 4 - 0
Source/cmCoreTryCompile.h

@@ -47,6 +47,10 @@ protected:
   std::string OutputFile;
   std::string OutputFile;
   std::string FindErrorMessage;
   std::string FindErrorMessage;
   bool SrcFileSignature;
   bool SrcFileSignature;
+
+private:
+  std::vector<std::string> WarnCMP0067;
+  std::string LookupStdVar(std::string const& var, bool warnCMP0067);
 };
 };
 
 
 #endif
 #endif

+ 10 - 6
Source/cmMakefile.cxx

@@ -3158,8 +3158,10 @@ int cmMakefile::TryCompile(const std::string& srcdir,
   cmGlobalGenerator* gg =
   cmGlobalGenerator* gg =
     cm.CreateGlobalGenerator(this->GetGlobalGenerator()->GetName());
     cm.CreateGlobalGenerator(this->GetGlobalGenerator()->GetName());
   if (!gg) {
   if (!gg) {
-    cmSystemTools::Error(
-      "Internal CMake error, TryCompile bad GlobalGenerator");
+    this->IssueMessage(cmake::INTERNAL_ERROR, "Global generator '" +
+                         this->GetGlobalGenerator()->GetName() +
+                         "' could not be created.");
+    cmSystemTools::SetFatalErrorOccured();
     // return to the original directory
     // return to the original directory
     cmSystemTools::ChangeDirectory(cwd);
     cmSystemTools::ChangeDirectory(cwd);
     this->IsSourceFileTryCompile = false;
     this->IsSourceFileTryCompile = false;
@@ -3222,8 +3224,9 @@ int cmMakefile::TryCompile(const std::string& srcdir,
                      cmStateEnums::INTERNAL);
                      cmStateEnums::INTERNAL);
   }
   }
   if (cm.Configure() != 0) {
   if (cm.Configure() != 0) {
-    cmSystemTools::Error(
-      "Internal CMake error, TryCompile configure of cmake failed");
+    this->IssueMessage(cmake::FATAL_ERROR,
+                       "Failed to configure test project build system.");
+    cmSystemTools::SetFatalErrorOccured();
     // return to the original directory
     // return to the original directory
     cmSystemTools::ChangeDirectory(cwd);
     cmSystemTools::ChangeDirectory(cwd);
     this->IsSourceFileTryCompile = false;
     this->IsSourceFileTryCompile = false;
@@ -3231,8 +3234,9 @@ int cmMakefile::TryCompile(const std::string& srcdir,
   }
   }
 
 
   if (cm.Generate() != 0) {
   if (cm.Generate() != 0) {
-    cmSystemTools::Error(
-      "Internal CMake error, TryCompile generation of cmake failed");
+    this->IssueMessage(cmake::FATAL_ERROR,
+                       "Failed to generate test project build system.");
+    cmSystemTools::SetFatalErrorOccured();
     // return to the original directory
     // return to the original directory
     cmSystemTools::ChangeDirectory(cwd);
     cmSystemTools::ChangeDirectory(cwd);
     this->IsSourceFileTryCompile = false;
     this->IsSourceFileTryCompile = false;

+ 4 - 1
Source/cmPolicies.h

@@ -197,7 +197,10 @@ class cmMakefile;
          3, 4, 0, cmPolicies::WARN)                                           \
          3, 4, 0, cmPolicies::WARN)                                           \
   SELECT(POLICY, CMP0066,                                                     \
   SELECT(POLICY, CMP0066,                                                     \
          "Honor per-config flags in try_compile() source-file signature.", 3, \
          "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_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)                                         \

+ 12 - 0
Tests/RunCMake/CMakeLists.txt

@@ -215,6 +215,18 @@ add_RunCMake_test(project -DCMake_TEST_RESOURCES=${CMake_TEST_RESOURCES})
 add_RunCMake_test(return)
 add_RunCMake_test(return)
 add_RunCMake_test(set_property)
 add_RunCMake_test(set_property)
 add_RunCMake_test(string)
 add_RunCMake_test(string)
+foreach(var
+    CMAKE_C_COMPILER_ID
+    CMAKE_C_COMPILER_VERSION
+    CMAKE_C_STANDARD_DEFAULT
+    CMAKE_CXX_COMPILER_ID
+    CMAKE_CXX_COMPILER_VERSION
+    CMAKE_CXX_STANDARD_DEFAULT
+    )
+  if(DEFINED ${var})
+    list(APPEND try_compile_ARGS -D${var}=${${var}})
+  endif()
+endforeach()
 add_RunCMake_test(try_compile)
 add_RunCMake_test(try_compile)
 add_RunCMake_test(try_run)
 add_RunCMake_test(try_run)
 add_RunCMake_test(set)
 add_RunCMake_test(set)

+ 25 - 0
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

+ 40 - 0
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")

+ 1 - 0
Tests/RunCMake/try_compile/CStandard-result.txt

@@ -0,0 +1 @@
+1

+ 7 - 0
Tests/RunCMake/try_compile/CStandard-stderr.txt

@@ -0,0 +1,7 @@
+^CMake Error at .*/Tests/RunCMake/try_compile/CStandard-build/CMakeFiles/CMakeTmp/CMakeLists.txt:[0-9]+ \(add_executable\):
+  C_STANDARD is set to invalid value '3'
++
+CMake Error at CStandard.cmake:[0-9]+ \(try_compile\):
+  Failed to generate test project build system.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)$

+ 7 - 0
Tests/RunCMake/try_compile/CStandard.cmake

@@ -0,0 +1,7 @@
+enable_language(C)
+try_compile(result ${CMAKE_CURRENT_BINARY_DIR}
+  SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src.c
+  C_STANDARD 3
+  OUTPUT_VARIABLE out
+  )
+message("try_compile output:\n${out}")

+ 10 - 0
Tests/RunCMake/try_compile/CStandardGNU.c

@@ -0,0 +1,10 @@
+#if __STDC_VERSION__ != 199901L
+#error "Not GNU C 99 mode!"
+#endif
+#ifndef __STRICT_ANSI__
+#error "Not GNU C strict ANSI!"
+#endif
+int main(void)
+{
+  return 0;
+}

+ 23 - 0
Tests/RunCMake/try_compile/CStandardGNU.cmake

@@ -0,0 +1,23 @@
+enable_language(C)
+try_compile(result ${CMAKE_CURRENT_BINARY_DIR}
+  SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/CStandardGNU.c
+  C_STANDARD 99
+  C_STANDARD_REQUIRED 1
+  C_EXTENSIONS 0
+  OUTPUT_VARIABLE out
+  )
+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()

+ 9 - 0
Tests/RunCMake/try_compile/CStandardNoDefault.cmake

@@ -0,0 +1,9 @@
+enable_language(C)
+try_compile(result ${CMAKE_CURRENT_BINARY_DIR}
+  SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src.c
+  C_STANDARD 3 # bogus, but not used
+  OUTPUT_VARIABLE out
+  )
+if(NOT result)
+  message(FATAL_ERROR "try_compile failed:\n${out}")
+endif()

+ 1 - 0
Tests/RunCMake/try_compile/CxxStandard-result.txt

@@ -0,0 +1 @@
+1

+ 7 - 0
Tests/RunCMake/try_compile/CxxStandard-stderr.txt

@@ -0,0 +1,7 @@
+^CMake Error at .*/Tests/RunCMake/try_compile/CxxStandard-build/CMakeFiles/CMakeTmp/CMakeLists.txt:[0-9]+ \(add_executable\):
+  CXX_STANDARD is set to invalid value '3'
++
+CMake Error at CxxStandard.cmake:[0-9]+ \(try_compile\):
+  Failed to generate test project build system.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)$

+ 7 - 0
Tests/RunCMake/try_compile/CxxStandard.cmake

@@ -0,0 +1,7 @@
+enable_language(CXX)
+try_compile(result ${CMAKE_CURRENT_BINARY_DIR}
+  SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src.cxx
+  CXX_STANDARD 3
+  OUTPUT_VARIABLE out
+  )
+message("try_compile output:\n${out}")

+ 23 - 0
Tests/RunCMake/try_compile/CxxStandardGNU.cmake

@@ -0,0 +1,23 @@
+enable_language(CXX)
+try_compile(result ${CMAKE_CURRENT_BINARY_DIR}
+  SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/CxxStandardGNU.cxx
+  CXX_STANDARD 11
+  CXX_STANDARD_REQUIRED 1
+  CXX_EXTENSIONS 0
+  OUTPUT_VARIABLE out
+  )
+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()

+ 11 - 0
Tests/RunCMake/try_compile/CxxStandardGNU.cxx

@@ -0,0 +1,11 @@
+#if __cplusplus != 201103L &&                                                 \
+  !(__cplusplus < 201103L && defined(__GXX_EXPERIMENTAL_CXX0X__))
+#error "Not GNU C++ 11 mode!"
+#endif
+#ifndef __STRICT_ANSI__
+#error "Not GNU C++ strict ANSI!"
+#endif
+int main()
+{
+  return 0;
+}

+ 9 - 0
Tests/RunCMake/try_compile/CxxStandardNoDefault.cmake

@@ -0,0 +1,9 @@
+enable_language(CXX)
+try_compile(result ${CMAKE_CURRENT_BINARY_DIR}
+  SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src.cxx
+  CXX_STANDARD 3 # bogus, but not used
+  OUTPUT_VARIABLE out
+  )
+if(NOT result)
+  message(FATAL_ERROR "try_compile failed:\n${out}")
+endif()

+ 18 - 0
Tests/RunCMake/try_compile/RunCMakeTest.cmake

@@ -25,8 +25,26 @@ run_cmake(TargetTypeExe)
 run_cmake(TargetTypeInvalid)
 run_cmake(TargetTypeInvalid)
 run_cmake(TargetTypeStatic)
 run_cmake(TargetTypeStatic)
 
 
+if(CMAKE_C_STANDARD_DEFAULT)
+  run_cmake(CStandard)
+elseif(DEFINED CMAKE_C_STANDARD_DEFAULT)
+  run_cmake(CStandardNoDefault)
+endif()
+if(CMAKE_CXX_STANDARD_DEFAULT)
+  run_cmake(CxxStandard)
+elseif(DEFINED CMAKE_CXX_STANDARD_DEFAULT)
+  run_cmake(CxxStandardNoDefault)
+endif()
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.4)
+  run_cmake(CStandardGNU)
+endif()
+if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.4)
+  run_cmake(CxxStandardGNU)
+endif()
+
 run_cmake(CMP0056)
 run_cmake(CMP0056)
 run_cmake(CMP0066)
 run_cmake(CMP0066)
+run_cmake(CMP0067)
 
 
 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.

+ 4 - 0
Tests/RunCMake/try_compile/src.cxx

@@ -0,0 +1,4 @@
+int main()
+{
+  return 0;
+}