summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2016-12-01 19:24:02 (GMT)
committerBrad King <brad.king@kitware.com>2016-12-06 13:58:41 (GMT)
commit45aa03b97aeeb512264ac2bfbb2028330be254d1 (patch)
tree883f2e60ea1539fa93f988b0e32dd983a043e020
parent3bb2051eef5c3a07f99e9e6549187211758317d6 (diff)
downloadCMake-45aa03b97aeeb512264ac2bfbb2028330be254d1.zip
CMake-45aa03b97aeeb512264ac2bfbb2028330be254d1.tar.gz
CMake-45aa03b97aeeb512264ac2bfbb2028330be254d1.tar.bz2
try_compile: Add options to specify language standards
Give `try_compile` callers a way to control the `CXX_STANDARD`, `CXX_STANDARD_REQUIRED`, and `CXX_EXTENSIONS` properties of the generated test target (or the `C` equivalents) in order to compile a test source for a particular language standard. Issue: #16456
-rw-r--r--Help/command/try_compile.rst18
-rw-r--r--Help/release/dev/try_compile-lang-std.rst5
-rw-r--r--Source/cmCoreTryCompile.cxx128
-rw-r--r--Tests/RunCMake/CMakeLists.txt12
-rw-r--r--Tests/RunCMake/try_compile/CStandard-result.txt1
-rw-r--r--Tests/RunCMake/try_compile/CStandard-stderr.txt7
-rw-r--r--Tests/RunCMake/try_compile/CStandard.cmake7
-rw-r--r--Tests/RunCMake/try_compile/CStandardGNU.c10
-rw-r--r--Tests/RunCMake/try_compile/CStandardGNU.cmake11
-rw-r--r--Tests/RunCMake/try_compile/CStandardNoDefault.cmake9
-rw-r--r--Tests/RunCMake/try_compile/CxxStandard-result.txt1
-rw-r--r--Tests/RunCMake/try_compile/CxxStandard-stderr.txt7
-rw-r--r--Tests/RunCMake/try_compile/CxxStandard.cmake7
-rw-r--r--Tests/RunCMake/try_compile/CxxStandardGNU.cmake11
-rw-r--r--Tests/RunCMake/try_compile/CxxStandardGNU.cxx11
-rw-r--r--Tests/RunCMake/try_compile/CxxStandardNoDefault.cmake9
-rw-r--r--Tests/RunCMake/try_compile/RunCMakeTest.cmake17
-rw-r--r--Tests/RunCMake/try_compile/src.cxx4
18 files changed, 274 insertions, 1 deletions
diff --git a/Help/command/try_compile.rst b/Help/command/try_compile.rst
index 7830deb..3f16b63 100644
--- a/Help/command/try_compile.rst
+++ b/Help/command/try_compile.rst
@@ -35,7 +35,11 @@ Try Compiling Source Files
[COMPILE_DEFINITIONS <defs>...]
[LINK_LIBRARIES <libs>...]
[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
failure of the ``try_compile``, i.e. ``TRUE`` or ``FALSE`` respectively, is
@@ -82,6 +86,18 @@ The options are:
``OUTPUT_VARIABLE <var>``
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
cleaned automatically. For debugging, ``--debug-trycompile`` can be
passed to ``cmake`` to avoid this clean. However, multiple sequential
diff --git a/Help/release/dev/try_compile-lang-std.rst b/Help/release/dev/try_compile-lang-std.rst
new file mode 100644
index 0000000..64d082b
--- /dev/null
+++ b/Help/release/dev/try_compile-lang-std.rst
@@ -0,0 +1,5 @@
+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.
diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx
index fbad778..3b72440 100644
--- a/Source/cmCoreTryCompile.cxx
+++ b/Source/cmCoreTryCompile.cxx
@@ -46,6 +46,14 @@ static std::string const kCMAKE_TRY_COMPILE_PLATFORM_VARIABLES =
"CMAKE_TRY_COMPILE_PLATFORM_VARIABLES";
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());
+}
+
int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
bool isTryRun)
{
@@ -87,6 +95,12 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
std::string outputVariable;
std::string copyFile;
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::string libsToLink = " ";
bool useOldLinkLibs = true;
@@ -94,6 +108,12 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
bool didOutputVariable = false;
bool didCopyFile = 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";
std::vector<std::string> sources;
@@ -106,6 +126,12 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
DoingOutputVariable,
DoingCopyFile,
DoingCopyFileError,
+ DoingCStandard,
+ DoingCxxStandard,
+ DoingCStandardRequired,
+ DoingCxxStandardRequired,
+ DoingCExtensions,
+ DoingCxxExtensions,
DoingSources
};
Doing doing = useSources ? DoingSources : DoingNone;
@@ -126,6 +152,24 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
} else if (argv[i] == "COPY_FILE_ERROR") {
doing = DoingCopyFileError;
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) {
cmakeFlags.push_back(argv[i]);
} else if (doing == DoingCompileDefinitions) {
@@ -166,6 +210,24 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
} else if (doing == DoingCopyFileError) {
copyFileError = argv[i];
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) {
sources.push_back(argv[i]);
} else if (i == 3) {
@@ -213,6 +275,42 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
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
// signature
if (this->SrcFileSignature) {
@@ -518,6 +616,36 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
}
}
fprintf(fout, ")\n");
+
+ bool const testC = testLangs.find("C") != testLangs.end();
+ bool const testCxx = testLangs.find("CXX") != testLangs.end();
+
+ 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) {
fprintf(fout, "target_link_libraries(%s ${LINK_LIBRARIES})\n",
targetName.c_str());
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index c02b917..1b88d46 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/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(set_property)
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_run)
add_RunCMake_test(set)
diff --git a/Tests/RunCMake/try_compile/CStandard-result.txt b/Tests/RunCMake/try_compile/CStandard-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/try_compile/CStandard-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/try_compile/CStandard-stderr.txt b/Tests/RunCMake/try_compile/CStandard-stderr.txt
new file mode 100644
index 0000000..209afcc
--- /dev/null
+++ b/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\)$
diff --git a/Tests/RunCMake/try_compile/CStandard.cmake b/Tests/RunCMake/try_compile/CStandard.cmake
new file mode 100644
index 0000000..2849ed4
--- /dev/null
+++ b/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}")
diff --git a/Tests/RunCMake/try_compile/CStandardGNU.c b/Tests/RunCMake/try_compile/CStandardGNU.c
new file mode 100644
index 0000000..ac26c15
--- /dev/null
+++ b/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;
+}
diff --git a/Tests/RunCMake/try_compile/CStandardGNU.cmake b/Tests/RunCMake/try_compile/CStandardGNU.cmake
new file mode 100644
index 0000000..29ce315
--- /dev/null
+++ b/Tests/RunCMake/try_compile/CStandardGNU.cmake
@@ -0,0 +1,11 @@
+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()
diff --git a/Tests/RunCMake/try_compile/CStandardNoDefault.cmake b/Tests/RunCMake/try_compile/CStandardNoDefault.cmake
new file mode 100644
index 0000000..97e72ea
--- /dev/null
+++ b/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()
diff --git a/Tests/RunCMake/try_compile/CxxStandard-result.txt b/Tests/RunCMake/try_compile/CxxStandard-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/try_compile/CxxStandard-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/try_compile/CxxStandard-stderr.txt b/Tests/RunCMake/try_compile/CxxStandard-stderr.txt
new file mode 100644
index 0000000..ec7245f
--- /dev/null
+++ b/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\)$
diff --git a/Tests/RunCMake/try_compile/CxxStandard.cmake b/Tests/RunCMake/try_compile/CxxStandard.cmake
new file mode 100644
index 0000000..bcb49b9
--- /dev/null
+++ b/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}")
diff --git a/Tests/RunCMake/try_compile/CxxStandardGNU.cmake b/Tests/RunCMake/try_compile/CxxStandardGNU.cmake
new file mode 100644
index 0000000..cc16bea
--- /dev/null
+++ b/Tests/RunCMake/try_compile/CxxStandardGNU.cmake
@@ -0,0 +1,11 @@
+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()
diff --git a/Tests/RunCMake/try_compile/CxxStandardGNU.cxx b/Tests/RunCMake/try_compile/CxxStandardGNU.cxx
new file mode 100644
index 0000000..7990a78
--- /dev/null
+++ b/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;
+}
diff --git a/Tests/RunCMake/try_compile/CxxStandardNoDefault.cmake b/Tests/RunCMake/try_compile/CxxStandardNoDefault.cmake
new file mode 100644
index 0000000..35caa9d
--- /dev/null
+++ b/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()
diff --git a/Tests/RunCMake/try_compile/RunCMakeTest.cmake b/Tests/RunCMake/try_compile/RunCMakeTest.cmake
index 4934bcd..dadcf35 100644
--- a/Tests/RunCMake/try_compile/RunCMakeTest.cmake
+++ b/Tests/RunCMake/try_compile/RunCMakeTest.cmake
@@ -25,6 +25,23 @@ run_cmake(TargetTypeExe)
run_cmake(TargetTypeInvalid)
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(CMP0066)
diff --git a/Tests/RunCMake/try_compile/src.cxx b/Tests/RunCMake/try_compile/src.cxx
new file mode 100644
index 0000000..f8b643a
--- /dev/null
+++ b/Tests/RunCMake/try_compile/src.cxx
@@ -0,0 +1,4 @@
+int main()
+{
+ return 0;
+}