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:
parent
509b1f08ea
commit
7f1bd9fe69
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
|
@ -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.
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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()
|
|
@ -0,0 +1 @@
|
||||||
|
1
|
|
@ -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\)
|
|
@ -0,0 +1,2 @@
|
||||||
|
set(CMAKE_TRY_COMPILE_TARGET_TYPE INVALID)
|
||||||
|
try_compile(result ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/src.c)
|
|
@ -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()
|
|
@ -0,0 +1 @@
|
||||||
|
int other(void) { return 0; }
|
Loading…
Reference in New Issue