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.
This commit is contained in:
Brad King 2016-02-19 13:23:48 -05:00
parent 509b1f08ea
commit 7f1bd9fe69
15 changed files with 136 additions and 15 deletions

View File

@ -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 Set the :variable:`CMAKE_TRY_COMPILE_CONFIGURATION` variable to choose
a build configuration. a build configuration.
Set the :variable:`CMAKE_TRY_COMPILE_TARGET_TYPE` variable to specify
the type of target used for the source file signature.

View File

@ -292,6 +292,7 @@ Variables that Control the Build
/variable/CMAKE_STATIC_LINKER_FLAGS_CONFIG /variable/CMAKE_STATIC_LINKER_FLAGS_CONFIG
/variable/CMAKE_STATIC_LINKER_FLAGS /variable/CMAKE_STATIC_LINKER_FLAGS
/variable/CMAKE_TRY_COMPILE_CONFIGURATION /variable/CMAKE_TRY_COMPILE_CONFIGURATION
/variable/CMAKE_TRY_COMPILE_TARGET_TYPE
/variable/CMAKE_USE_RELATIVE_PATHS /variable/CMAKE_USE_RELATIVE_PATHS
/variable/CMAKE_VISIBILITY_INLINES_HIDDEN /variable/CMAKE_VISIBILITY_INLINES_HIDDEN
/variable/CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD /variable/CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD

View File

@ -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.

View File

@ -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.

View File

@ -19,13 +19,42 @@
#include <assert.h> #include <assert.h>
int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv) int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
bool isTryRun)
{ {
this->BinaryDirectory = argv[1].c_str(); this->BinaryDirectory = argv[1].c_str();
this->OutputFile = ""; this->OutputFile = "";
// which signature were we called with ? // which signature were we called with ?
this->SrcFileSignature = true; 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* sourceDirectory = argv[2].c_str();
const char* projectName = 0; const char* projectName = 0;
std::string targetName; std::string targetName;
@ -486,11 +515,22 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv)
fprintf(fout, "set(CMAKE_ENABLE_EXPORTS %s)\n", ee); fprintf(fout, "set(CMAKE_ENABLE_EXPORTS %s)\n", ee);
} }
/* Put the executable at a known location (for COPY_FILE). */ if (targetType == cmState::EXECUTABLE)
fprintf(fout, "set(CMAKE_RUNTIME_OUTPUT_DIRECTORY \"%s\")\n", {
this->BinaryDirectory.c_str()); /* Put the executable at a known location (for COPY_FILE). */
/* Create the actual executable. */ fprintf(fout, "set(CMAKE_RUNTIME_OUTPUT_DIRECTORY \"%s\")\n",
fprintf(fout, "add_executable(%s", targetName.c_str()); 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<std::string>::iterator si = sources.begin(); for(std::vector<std::string>::iterator si = sources.begin();
si != sources.end(); ++si) si != sources.end(); ++si)
{ {
@ -549,7 +589,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv)
if (this->SrcFileSignature) if (this->SrcFileSignature)
{ {
std::string copyFileErrorMessage; std::string copyFileErrorMessage;
this->FindOutputFile(targetName); this->FindOutputFile(targetName, targetType);
if ((res==0) && !copyFile.empty()) 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->FindErrorMessage = "";
this->OutputFile = ""; this->OutputFile = "";
std::string tmpOutputFile = "/"; std::string tmpOutputFile = "/";
tmpOutputFile += targetName; if (targetType == cmState::EXECUTABLE)
tmpOutputFile +=this->Makefile->GetSafeDefinition("CMAKE_EXECUTABLE_SUFFIX"); {
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 // a list of directories where to search for the compilation result
// at first directly in the binary dir // at first directly in the binary dir

View File

@ -30,7 +30,7 @@ public:
* commands, such as TryRun can access the same logic without * commands, such as TryRun can access the same logic without
* duplication. * duplication.
*/ */
int TryCompileCode(std::vector<std::string> const& argv); int TryCompileCode(std::vector<std::string> const& argv, bool isTryRun);
/** /**
* This deletes all the files created by TryCompileCode. * This deletes all the files created by TryCompileCode.
@ -44,8 +44,8 @@ public:
TryCompileCode. The result is stored in OutputFile. If nothing is found, TryCompileCode. The result is stored in OutputFile. If nothing is found,
the error message is stored in FindErrorMessage. 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); cmTypeMacro(cmCoreTryCompile, cmCommand);

View File

@ -28,7 +28,7 @@ bool cmTryCompileCommand
return false; return false;
} }
this->TryCompileCode(argv); this->TryCompileCode(argv, false);
// if They specified clean then we clean up what we can // if They specified clean then we clean up what we can
if (this->SrcFileSignature) if (this->SrcFileSignature)

View File

@ -135,7 +135,7 @@ bool cmTryRunCommand
this->CompileResultVariable = argv[1]; this->CompileResultVariable = argv[1];
// do the try compile // do the try compile
int res = this->TryCompileCode(tryCompile); int res = this->TryCompileCode(tryCompile, true);
// now try running the command if it compiled // now try running the command if it compiled
if (!res) if (!res)

View File

@ -16,6 +16,10 @@ run_cmake(BadSources2)
run_cmake(NonSourceCopyFile) run_cmake(NonSourceCopyFile)
run_cmake(NonSourceCompileDefinitions) run_cmake(NonSourceCompileDefinitions)
run_cmake(TargetTypeExe)
run_cmake(TargetTypeInvalid)
run_cmake(TargetTypeStatic)
run_cmake(CMP0056) run_cmake(CMP0056)
if(RunCMake_GENERATOR MATCHES "Make|Ninja") if(RunCMake_GENERATOR MATCHES "Make|Ninja")

View File

@ -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()

View File

@ -0,0 +1 @@
1

View File

@ -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\)

View File

@ -0,0 +1,2 @@
set(CMAKE_TRY_COMPILE_TARGET_TYPE INVALID)
try_compile(result ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/src.c)

View File

@ -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()

View File

@ -0,0 +1 @@
int other(void) { return 0; }