From 7f1bd9fe6910f7633d98dec018cc01331a46b87e Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 19 Feb 2016 13:23:48 -0500 Subject: [PATCH] try_compile: Add option to control type of target Create a `CMAKE_TRY_COMPILE_TARGET_TYPE` option to specify use of `add_library(... STATIC ...)` for the generated test project. This will be useful for cross-compiling toolchains that cannot link a binary without custom flags or scripts. --- Help/command/try_compile.rst | 3 + Help/manual/cmake-variables.7.rst | 1 + Help/release/dev/try_compile-target-type.rst | 8 ++ .../CMAKE_TRY_COMPILE_TARGET_TYPE.rst | 15 ++++ Source/cmCoreTryCompile.cxx | 73 ++++++++++++++++--- Source/cmCoreTryCompile.h | 6 +- Source/cmTryCompileCommand.cxx | 2 +- Source/cmTryRunCommand.cxx | 2 +- Tests/RunCMake/try_compile/RunCMakeTest.cmake | 4 + .../RunCMake/try_compile/TargetTypeExe.cmake | 14 ++++ .../try_compile/TargetTypeInvalid-result.txt | 1 + .../try_compile/TargetTypeInvalid-stderr.txt | 5 ++ .../try_compile/TargetTypeInvalid.cmake | 2 + .../try_compile/TargetTypeStatic.cmake | 14 ++++ Tests/RunCMake/try_compile/other.c | 1 + 15 files changed, 136 insertions(+), 15 deletions(-) create mode 100644 Help/release/dev/try_compile-target-type.rst create mode 100644 Help/variable/CMAKE_TRY_COMPILE_TARGET_TYPE.rst create mode 100644 Tests/RunCMake/try_compile/TargetTypeExe.cmake create mode 100644 Tests/RunCMake/try_compile/TargetTypeInvalid-result.txt create mode 100644 Tests/RunCMake/try_compile/TargetTypeInvalid-stderr.txt create mode 100644 Tests/RunCMake/try_compile/TargetTypeInvalid.cmake create mode 100644 Tests/RunCMake/try_compile/TargetTypeStatic.cmake create mode 100644 Tests/RunCMake/try_compile/other.c diff --git a/Help/command/try_compile.rst b/Help/command/try_compile.rst index 28dae8074..78b1bc76a 100644 --- a/Help/command/try_compile.rst +++ b/Help/command/try_compile.rst @@ -112,3 +112,6 @@ The current setting of :policy:`CMP0065` is set in the generated project. Set the :variable:`CMAKE_TRY_COMPILE_CONFIGURATION` variable to choose a build configuration. + +Set the :variable:`CMAKE_TRY_COMPILE_TARGET_TYPE` variable to specify +the type of target used for the source file signature. diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index 15eaece95..444a70603 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -292,6 +292,7 @@ Variables that Control the Build /variable/CMAKE_STATIC_LINKER_FLAGS_CONFIG /variable/CMAKE_STATIC_LINKER_FLAGS /variable/CMAKE_TRY_COMPILE_CONFIGURATION + /variable/CMAKE_TRY_COMPILE_TARGET_TYPE /variable/CMAKE_USE_RELATIVE_PATHS /variable/CMAKE_VISIBILITY_INLINES_HIDDEN /variable/CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD diff --git a/Help/release/dev/try_compile-target-type.rst b/Help/release/dev/try_compile-target-type.rst new file mode 100644 index 000000000..cc41bf309 --- /dev/null +++ b/Help/release/dev/try_compile-target-type.rst @@ -0,0 +1,8 @@ +try_compile-target-type +----------------------- + +* The :command:`try_compile` command learned to check a new + :variable:`CMAKE_TRY_COMPILE_TARGET_TYPE` variable to optionally + build a static library instead of an executable. This is useful + for cross-compiling toolchains that cannot link binaries without + custom flags or scripts. diff --git a/Help/variable/CMAKE_TRY_COMPILE_TARGET_TYPE.rst b/Help/variable/CMAKE_TRY_COMPILE_TARGET_TYPE.rst new file mode 100644 index 000000000..5fa8dfcb6 --- /dev/null +++ b/Help/variable/CMAKE_TRY_COMPILE_TARGET_TYPE.rst @@ -0,0 +1,15 @@ +CMAKE_TRY_COMPILE_TARGET_TYPE +----------------------------- + +Type of target generated for :command:`try_compile` calls using the +source file signature. Valid values are: + +``EXECUTABLE`` + Use :command:`add_executable` to name the source file in the + generated project. This is the default if no value is given. + +``STATIC_LIBRARY`` + Use :command:`add_library` with the ``STATIC`` option to name the + source file in the generated project. This avoids running the + linker and is intended for use with cross-compiling toolchains + that cannot link without custom flags or linker scripts. diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx index 4a1f770ba..b639c15a1 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -19,13 +19,42 @@ #include -int cmCoreTryCompile::TryCompileCode(std::vector const& argv) +int cmCoreTryCompile::TryCompileCode(std::vector const& argv, + bool isTryRun) { this->BinaryDirectory = argv[1].c_str(); this->OutputFile = ""; // which signature were we called with ? this->SrcFileSignature = true; + cmState::TargetType targetType = cmState::EXECUTABLE; + const char* tt = + this->Makefile->GetDefinition("CMAKE_TRY_COMPILE_TARGET_TYPE"); + if (!isTryRun && tt && *tt) + { + if (strcmp(tt, cmState::GetTargetTypeName(cmState::EXECUTABLE)) == 0) + { + targetType = cmState::EXECUTABLE; + } + else if (strcmp(tt, + cmState::GetTargetTypeName(cmState::STATIC_LIBRARY)) == 0) + { + targetType = cmState::STATIC_LIBRARY; + } + else + { + this->Makefile->IssueMessage( + cmake::FATAL_ERROR, + std::string("Invalid value '") + tt + "' for " + "CMAKE_TRY_COMPILE_TARGET_TYPE. Only " + "'" + cmState::GetTargetTypeName(cmState::EXECUTABLE) + "' and " + "'" + cmState::GetTargetTypeName(cmState::STATIC_LIBRARY) + "' " + "are allowed." + ); + return -1; + } + } + const char* sourceDirectory = argv[2].c_str(); const char* projectName = 0; std::string targetName; @@ -486,11 +515,22 @@ int cmCoreTryCompile::TryCompileCode(std::vector const& argv) fprintf(fout, "set(CMAKE_ENABLE_EXPORTS %s)\n", ee); } - /* Put the executable at a known location (for COPY_FILE). */ - fprintf(fout, "set(CMAKE_RUNTIME_OUTPUT_DIRECTORY \"%s\")\n", - this->BinaryDirectory.c_str()); - /* Create the actual executable. */ - fprintf(fout, "add_executable(%s", targetName.c_str()); + if (targetType == cmState::EXECUTABLE) + { + /* Put the executable at a known location (for COPY_FILE). */ + fprintf(fout, "set(CMAKE_RUNTIME_OUTPUT_DIRECTORY \"%s\")\n", + this->BinaryDirectory.c_str()); + /* Create the actual executable. */ + fprintf(fout, "add_executable(%s", targetName.c_str()); + } + else // if (targetType == cmState::STATIC_LIBRARY) + { + /* Put the static library at a known location (for COPY_FILE). */ + fprintf(fout, "set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY \"%s\")\n", + this->BinaryDirectory.c_str()); + /* Create the actual static library. */ + fprintf(fout, "add_library(%s STATIC", targetName.c_str()); + } for(std::vector::iterator si = sources.begin(); si != sources.end(); ++si) { @@ -549,7 +589,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector const& argv) if (this->SrcFileSignature) { std::string copyFileErrorMessage; - this->FindOutputFile(targetName); + this->FindOutputFile(targetName, targetType); if ((res==0) && !copyFile.empty()) { @@ -651,13 +691,26 @@ void cmCoreTryCompile::CleanupFiles(const char* binDir) } } -void cmCoreTryCompile::FindOutputFile(const std::string& targetName) +void cmCoreTryCompile::FindOutputFile(const std::string& targetName, + cmState::TargetType targetType) { this->FindErrorMessage = ""; this->OutputFile = ""; std::string tmpOutputFile = "/"; - tmpOutputFile += targetName; - tmpOutputFile +=this->Makefile->GetSafeDefinition("CMAKE_EXECUTABLE_SUFFIX"); + if (targetType == cmState::EXECUTABLE) + { + tmpOutputFile += targetName; + tmpOutputFile += + this->Makefile->GetSafeDefinition("CMAKE_EXECUTABLE_SUFFIX"); + } + else // if (targetType == cmState::STATIC_LIBRARY) + { + tmpOutputFile += + this->Makefile->GetSafeDefinition("CMAKE_STATIC_LIBRARY_PREFIX"); + tmpOutputFile += targetName; + tmpOutputFile += + this->Makefile->GetSafeDefinition("CMAKE_STATIC_LIBRARY_SUFFIX"); + } // a list of directories where to search for the compilation result // at first directly in the binary dir diff --git a/Source/cmCoreTryCompile.h b/Source/cmCoreTryCompile.h index 3272462d9..c2beea837 100644 --- a/Source/cmCoreTryCompile.h +++ b/Source/cmCoreTryCompile.h @@ -30,7 +30,7 @@ public: * commands, such as TryRun can access the same logic without * duplication. */ - int TryCompileCode(std::vector const& argv); + int TryCompileCode(std::vector const& argv, bool isTryRun); /** * This deletes all the files created by TryCompileCode. @@ -44,8 +44,8 @@ public: TryCompileCode. The result is stored in OutputFile. If nothing is found, the error message is stored in FindErrorMessage. */ - void FindOutputFile(const std::string& targetName); - + void FindOutputFile(const std::string& targetName, + cmState::TargetType targetType); cmTypeMacro(cmCoreTryCompile, cmCommand); diff --git a/Source/cmTryCompileCommand.cxx b/Source/cmTryCompileCommand.cxx index 12ce015d2..87fbbdf5d 100644 --- a/Source/cmTryCompileCommand.cxx +++ b/Source/cmTryCompileCommand.cxx @@ -28,7 +28,7 @@ bool cmTryCompileCommand return false; } - this->TryCompileCode(argv); + this->TryCompileCode(argv, false); // if They specified clean then we clean up what we can if (this->SrcFileSignature) diff --git a/Source/cmTryRunCommand.cxx b/Source/cmTryRunCommand.cxx index b9ffe5e0f..d4a36c982 100644 --- a/Source/cmTryRunCommand.cxx +++ b/Source/cmTryRunCommand.cxx @@ -135,7 +135,7 @@ bool cmTryRunCommand this->CompileResultVariable = argv[1]; // do the try compile - int res = this->TryCompileCode(tryCompile); + int res = this->TryCompileCode(tryCompile, true); // now try running the command if it compiled if (!res) diff --git a/Tests/RunCMake/try_compile/RunCMakeTest.cmake b/Tests/RunCMake/try_compile/RunCMakeTest.cmake index 6cdbafa87..43ce998b2 100644 --- a/Tests/RunCMake/try_compile/RunCMakeTest.cmake +++ b/Tests/RunCMake/try_compile/RunCMakeTest.cmake @@ -16,6 +16,10 @@ run_cmake(BadSources2) run_cmake(NonSourceCopyFile) run_cmake(NonSourceCompileDefinitions) +run_cmake(TargetTypeExe) +run_cmake(TargetTypeInvalid) +run_cmake(TargetTypeStatic) + run_cmake(CMP0056) if(RunCMake_GENERATOR MATCHES "Make|Ninja") diff --git a/Tests/RunCMake/try_compile/TargetTypeExe.cmake b/Tests/RunCMake/try_compile/TargetTypeExe.cmake new file mode 100644 index 000000000..9b6e7272f --- /dev/null +++ b/Tests/RunCMake/try_compile/TargetTypeExe.cmake @@ -0,0 +1,14 @@ +enable_language(C) +set(CMAKE_TRY_COMPILE_TARGET_TYPE EXECUTABLE) +try_compile(result ${CMAKE_CURRENT_BINARY_DIR} + SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src.c + OUTPUT_VARIABLE out + COPY_FILE ${CMAKE_CURRENT_BINARY_DIR}/copy + COPY_FILE_ERROR copy_err + ) +if(NOT result) + message(FATAL_ERROR "try_compile failed:\n${out}") +endif() +if(copy_err) + message(FATAL_ERROR "try_compile COPY_FILE failed:\n${copy_err}") +endif() diff --git a/Tests/RunCMake/try_compile/TargetTypeInvalid-result.txt b/Tests/RunCMake/try_compile/TargetTypeInvalid-result.txt new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/Tests/RunCMake/try_compile/TargetTypeInvalid-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/try_compile/TargetTypeInvalid-stderr.txt b/Tests/RunCMake/try_compile/TargetTypeInvalid-stderr.txt new file mode 100644 index 000000000..08b281a45 --- /dev/null +++ b/Tests/RunCMake/try_compile/TargetTypeInvalid-stderr.txt @@ -0,0 +1,5 @@ +^CMake Error at TargetTypeInvalid.cmake:2 \(try_compile\): + Invalid value 'INVALID' for CMAKE_TRY_COMPILE_TARGET_TYPE. Only + 'EXECUTABLE' and 'STATIC_LIBRARY' are allowed. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/try_compile/TargetTypeInvalid.cmake b/Tests/RunCMake/try_compile/TargetTypeInvalid.cmake new file mode 100644 index 000000000..0bbc4ac82 --- /dev/null +++ b/Tests/RunCMake/try_compile/TargetTypeInvalid.cmake @@ -0,0 +1,2 @@ +set(CMAKE_TRY_COMPILE_TARGET_TYPE INVALID) +try_compile(result ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/src.c) diff --git a/Tests/RunCMake/try_compile/TargetTypeStatic.cmake b/Tests/RunCMake/try_compile/TargetTypeStatic.cmake new file mode 100644 index 000000000..006b8b898 --- /dev/null +++ b/Tests/RunCMake/try_compile/TargetTypeStatic.cmake @@ -0,0 +1,14 @@ +enable_language(C) +set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) +try_compile(result ${CMAKE_CURRENT_BINARY_DIR} + SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/other.c + OUTPUT_VARIABLE out + COPY_FILE ${CMAKE_CURRENT_BINARY_DIR}/copy + COPY_FILE_ERROR copy_err + ) +if(NOT result) + message(FATAL_ERROR "try_compile failed:\n${out}") +endif() +if(copy_err) + message(FATAL_ERROR "try_compile COPY_FILE failed:\n${copy_err}") +endif() diff --git a/Tests/RunCMake/try_compile/other.c b/Tests/RunCMake/try_compile/other.c new file mode 100644 index 000000000..6c24f10b9 --- /dev/null +++ b/Tests/RunCMake/try_compile/other.c @@ -0,0 +1 @@ +int other(void) { return 0; }