try_compile: Add signature to allow multiple SOURCES
Extend the signature try_compile(RESULT_VAR <bindir> <srcfile> ...) to allow multiple sources as try_compile(RESULT_VAR <bindir> SOURCES <srcfile>... ...) Process the sources to generate a CMakeLists.txt that enables all needed languages. Teach the TryCompile test to try cases with two sources of the same language and of mixed languages. Teach RunCMake.try_compile to cover error cases for the signature.
This commit is contained in:
parent
bb879bcf2d
commit
482f1122ad
|
@ -38,10 +38,13 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv)
|
||||||
char targetNameBuf[64];
|
char targetNameBuf[64];
|
||||||
bool didOutputVariable = false;
|
bool didOutputVariable = false;
|
||||||
bool didCopyFile = false;
|
bool didCopyFile = false;
|
||||||
|
bool useSources = argv[2] == "SOURCES";
|
||||||
|
std::vector<std::string> sources;
|
||||||
|
|
||||||
enum Doing { DoingNone, DoingCMakeFlags, DoingCompileDefinitions,
|
enum Doing { DoingNone, DoingCMakeFlags, DoingCompileDefinitions,
|
||||||
DoingLinkLibraries, DoingOutputVariable, DoingCopyFile };
|
DoingLinkLibraries, DoingOutputVariable, DoingCopyFile,
|
||||||
Doing doing = DoingNone;
|
DoingSources };
|
||||||
|
Doing doing = useSources? DoingSources : DoingNone;
|
||||||
for(size_t i=3; i < argv.size(); ++i)
|
for(size_t i=3; i < argv.size(); ++i)
|
||||||
{
|
{
|
||||||
if(argv[i] == "CMAKE_FLAGS")
|
if(argv[i] == "CMAKE_FLAGS")
|
||||||
|
@ -118,6 +121,10 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv)
|
||||||
copyFile = argv[i].c_str();
|
copyFile = argv[i].c_str();
|
||||||
doing = DoingNone;
|
doing = DoingNone;
|
||||||
}
|
}
|
||||||
|
else if(doing == DoingSources)
|
||||||
|
{
|
||||||
|
sources.push_back(argv[i]);
|
||||||
|
}
|
||||||
else if(i == 3)
|
else if(i == 3)
|
||||||
{
|
{
|
||||||
this->SrcFileSignature = false;
|
this->SrcFileSignature = false;
|
||||||
|
@ -149,6 +156,13 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(useSources && sources.empty())
|
||||||
|
{
|
||||||
|
this->Makefile->IssueMessage(cmake::FATAL_ERROR,
|
||||||
|
"SOURCES must be followed by at least one source file");
|
||||||
|
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)
|
||||||
|
@ -193,6 +207,44 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv)
|
||||||
std::string ccFile = this->BinaryDirectory + "/CMakeCache.txt";
|
std::string ccFile = this->BinaryDirectory + "/CMakeCache.txt";
|
||||||
cmSystemTools::RemoveFile(ccFile.c_str());
|
cmSystemTools::RemoveFile(ccFile.c_str());
|
||||||
|
|
||||||
|
// Choose sources.
|
||||||
|
if(!useSources)
|
||||||
|
{
|
||||||
|
sources.push_back(argv[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detect languages to enable.
|
||||||
|
cmGlobalGenerator* gg =
|
||||||
|
this->Makefile->GetCMakeInstance()->GetGlobalGenerator();
|
||||||
|
std::set<std::string> testLangs;
|
||||||
|
for(std::vector<std::string>::iterator si = sources.begin();
|
||||||
|
si != sources.end(); ++si)
|
||||||
|
{
|
||||||
|
std::string ext = cmSystemTools::GetFilenameLastExtension(*si);
|
||||||
|
if(const char* lang = gg->GetLanguageFromExtension(ext.c_str()))
|
||||||
|
{
|
||||||
|
testLangs.insert(lang);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cmOStringStream err;
|
||||||
|
err << "Unknown extension \"" << ext << "\" for file\n"
|
||||||
|
<< " " << *si << "\n"
|
||||||
|
<< "try_compile() works only for enabled languages. "
|
||||||
|
<< "Currently these are:\n ";
|
||||||
|
std::vector<std::string> langs;
|
||||||
|
gg->GetEnabledLanguages(langs);
|
||||||
|
for(std::vector<std::string>::iterator l = langs.begin();
|
||||||
|
l != langs.end(); ++l)
|
||||||
|
{
|
||||||
|
err << " " << *l;
|
||||||
|
}
|
||||||
|
err << "\nSee project() command to enable other languages.";
|
||||||
|
this->Makefile->IssueMessage(cmake::FATAL_ERROR, err.str());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// we need to create a directory and CMakeLists file etc...
|
// we need to create a directory and CMakeLists file etc...
|
||||||
// first create the directories
|
// first create the directories
|
||||||
sourceDirectory = this->BinaryDirectory.c_str();
|
sourceDirectory = this->BinaryDirectory.c_str();
|
||||||
|
@ -209,10 +261,6 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string source = argv[2];
|
|
||||||
std::string ext = cmSystemTools::GetFilenameLastExtension(source);
|
|
||||||
const char* lang =(this->Makefile->GetCMakeInstance()->GetGlobalGenerator()
|
|
||||||
->GetLanguageFromExtension(ext.c_str()));
|
|
||||||
const char* def = this->Makefile->GetDefinition("CMAKE_MODULE_PATH");
|
const char* def = this->Makefile->GetDefinition("CMAKE_MODULE_PATH");
|
||||||
fprintf(fout, "cmake_minimum_required(VERSION %u.%u.%u.%u)\n",
|
fprintf(fout, "cmake_minimum_required(VERSION %u.%u.%u.%u)\n",
|
||||||
cmVersion::GetMajorVersion(), cmVersion::GetMinorVersion(),
|
cmVersion::GetMajorVersion(), cmVersion::GetMinorVersion(),
|
||||||
|
@ -222,9 +270,13 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv)
|
||||||
fprintf(fout, "SET(CMAKE_MODULE_PATH %s)\n", def);
|
fprintf(fout, "SET(CMAKE_MODULE_PATH %s)\n", def);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* rulesOverrideBase = "CMAKE_USER_MAKE_RULES_OVERRIDE";
|
std::string projectLangs;
|
||||||
std::string rulesOverrideLang =
|
for(std::set<std::string>::iterator li = testLangs.begin();
|
||||||
rulesOverrideBase + (lang ? std::string("_") + lang : std::string(""));
|
li != testLangs.end(); ++li)
|
||||||
|
{
|
||||||
|
projectLangs += " " + *li;
|
||||||
|
std::string rulesOverrideBase = "CMAKE_USER_MAKE_RULES_OVERRIDE";
|
||||||
|
std::string rulesOverrideLang = rulesOverrideBase + "_" + *li;
|
||||||
if(const char* rulesOverridePath =
|
if(const char* rulesOverridePath =
|
||||||
this->Makefile->GetDefinition(rulesOverrideLang.c_str()))
|
this->Makefile->GetDefinition(rulesOverrideLang.c_str()))
|
||||||
{
|
{
|
||||||
|
@ -232,47 +284,25 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv)
|
||||||
rulesOverrideLang.c_str(), rulesOverridePath);
|
rulesOverrideLang.c_str(), rulesOverridePath);
|
||||||
}
|
}
|
||||||
else if(const char* rulesOverridePath2 =
|
else if(const char* rulesOverridePath2 =
|
||||||
this->Makefile->GetDefinition(rulesOverrideBase))
|
this->Makefile->GetDefinition(rulesOverrideBase.c_str()))
|
||||||
{
|
{
|
||||||
fprintf(fout, "SET(%s \"%s\")\n",
|
fprintf(fout, "SET(%s \"%s\")\n",
|
||||||
rulesOverrideBase, rulesOverridePath2);
|
rulesOverrideBase.c_str(), rulesOverridePath2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(lang)
|
|
||||||
{
|
|
||||||
fprintf(fout, "PROJECT(CMAKE_TRY_COMPILE %s)\n", lang);
|
|
||||||
}
|
}
|
||||||
else
|
fprintf(fout, "PROJECT(CMAKE_TRY_COMPILE%s)\n", projectLangs.c_str());
|
||||||
{
|
|
||||||
fclose(fout);
|
|
||||||
cmOStringStream err;
|
|
||||||
err << "Unknown extension \"" << ext << "\" for file\n"
|
|
||||||
<< " " << source << "\n"
|
|
||||||
<< "try_compile() works only for enabled languages. "
|
|
||||||
<< "Currently these are:\n ";
|
|
||||||
std::vector<std::string> langs;
|
|
||||||
this->Makefile->GetCMakeInstance()->GetGlobalGenerator()->
|
|
||||||
GetEnabledLanguages(langs);
|
|
||||||
for(std::vector<std::string>::iterator l = langs.begin();
|
|
||||||
l != langs.end(); ++l)
|
|
||||||
{
|
|
||||||
err << " " << *l;
|
|
||||||
}
|
|
||||||
err << "\nSee project() command to enable other languages.";
|
|
||||||
this->Makefile->IssueMessage(cmake::FATAL_ERROR, err.str());
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
std::string langFlags = "CMAKE_";
|
|
||||||
langFlags += lang;
|
|
||||||
langFlags += "_FLAGS";
|
|
||||||
fprintf(fout, "SET(CMAKE_VERBOSE_MAKEFILE 1)\n");
|
fprintf(fout, "SET(CMAKE_VERBOSE_MAKEFILE 1)\n");
|
||||||
fprintf(fout, "SET(CMAKE_%s_FLAGS \"", lang);
|
for(std::set<std::string>::iterator li = testLangs.begin();
|
||||||
const char* flags = this->Makefile->GetDefinition(langFlags.c_str());
|
li != testLangs.end(); ++li)
|
||||||
if(flags)
|
{
|
||||||
|
fprintf(fout, "SET(CMAKE_%s_FLAGS \"", li->c_str());
|
||||||
|
std::string langFlags = "CMAKE_" + *li + "_FLAGS";
|
||||||
|
if(const char* flags = this->Makefile->GetDefinition(langFlags.c_str()))
|
||||||
{
|
{
|
||||||
fprintf(fout, " %s ", flags);
|
fprintf(fout, " %s ", flags);
|
||||||
}
|
}
|
||||||
fprintf(fout, " ${COMPILE_DEFINITIONS}\")\n");
|
fprintf(fout, " ${COMPILE_DEFINITIONS}\")\n");
|
||||||
|
}
|
||||||
fprintf(fout, "INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES})\n");
|
fprintf(fout, "INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES})\n");
|
||||||
fprintf(fout, "SET(CMAKE_SUPPRESS_REGENERATION 1)\n");
|
fprintf(fout, "SET(CMAKE_SUPPRESS_REGENERATION 1)\n");
|
||||||
fprintf(fout, "LINK_DIRECTORIES(${LINK_DIRECTORIES})\n");
|
fprintf(fout, "LINK_DIRECTORIES(${LINK_DIRECTORIES})\n");
|
||||||
|
@ -357,7 +387,19 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv)
|
||||||
fprintf(fout, "SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY \"%s\")\n",
|
fprintf(fout, "SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY \"%s\")\n",
|
||||||
this->BinaryDirectory.c_str());
|
this->BinaryDirectory.c_str());
|
||||||
/* Create the actual executable. */
|
/* Create the actual executable. */
|
||||||
fprintf(fout, "ADD_EXECUTABLE(%s \"%s\")\n", targetName, source.c_str());
|
fprintf(fout, "ADD_EXECUTABLE(%s", targetName);
|
||||||
|
for(std::vector<std::string>::iterator si = sources.begin();
|
||||||
|
si != sources.end(); ++si)
|
||||||
|
{
|
||||||
|
fprintf(fout, " \"%s\"", si->c_str());
|
||||||
|
|
||||||
|
// Add dependencies on any non-temporary sources.
|
||||||
|
if(si->find("CMakeTmp") == si->npos)
|
||||||
|
{
|
||||||
|
this->Makefile->AddCMakeDependFile(si->c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(fout, ")\n");
|
||||||
if (useOldLinkLibs)
|
if (useOldLinkLibs)
|
||||||
{
|
{
|
||||||
fprintf(fout,
|
fprintf(fout,
|
||||||
|
@ -371,12 +413,6 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv)
|
||||||
}
|
}
|
||||||
fclose(fout);
|
fclose(fout);
|
||||||
projectName = "CMAKE_TRY_COMPILE";
|
projectName = "CMAKE_TRY_COMPILE";
|
||||||
// if the source is not in CMakeTmp
|
|
||||||
if(source.find("CMakeTmp") == source.npos)
|
|
||||||
{
|
|
||||||
this->Makefile->AddCMakeDependFile(source.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool erroroc = cmSystemTools::GetErrorOccuredFlag();
|
bool erroroc = cmSystemTools::GetErrorOccuredFlag();
|
||||||
|
|
|
@ -64,16 +64,16 @@ public:
|
||||||
"Specify targetName to build a specific target instead of the 'all' or "
|
"Specify targetName to build a specific target instead of the 'all' or "
|
||||||
"'ALL_BUILD' target."
|
"'ALL_BUILD' target."
|
||||||
"\n"
|
"\n"
|
||||||
" try_compile(RESULT_VAR <bindir> <srcfile>\n"
|
" try_compile(RESULT_VAR <bindir> <srcfile|SOURCES srcfile...>\n"
|
||||||
" [CMAKE_FLAGS flags...]\n"
|
" [CMAKE_FLAGS flags...]\n"
|
||||||
" [COMPILE_DEFINITIONS flags...]\n"
|
" [COMPILE_DEFINITIONS flags...]\n"
|
||||||
" [LINK_LIBRARIES libs...]\n"
|
" [LINK_LIBRARIES libs...]\n"
|
||||||
" [OUTPUT_VARIABLE <var>]\n"
|
" [OUTPUT_VARIABLE <var>]\n"
|
||||||
" [COPY_FILE <fileName>])\n"
|
" [COPY_FILE <fileName>])\n"
|
||||||
"Try building a source file into an executable. "
|
"Try building an executable from one or more source files. "
|
||||||
"In this form the user need only supply a source file that defines "
|
"In this form the user need only supply one or more source files "
|
||||||
"a 'main'. "
|
"that include a definition for 'main'. "
|
||||||
"CMake will create a CMakeLists.txt file to build the source "
|
"CMake will create a CMakeLists.txt file to build the source(s) "
|
||||||
"as an executable. "
|
"as an executable. "
|
||||||
"Specify COPY_FILE to get a copy of the linked executable at the "
|
"Specify COPY_FILE to get a copy of the linked executable at the "
|
||||||
"given fileName."
|
"given fileName."
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
1
|
|
@ -0,0 +1,12 @@
|
||||||
|
CMake Error at BadSources1.cmake:1 \(try_compile\):
|
||||||
|
Unknown extension ".c" for file
|
||||||
|
|
||||||
|
.*/Tests/RunCMake/try_compile/src.c
|
||||||
|
|
||||||
|
try_compile\(\) works only for enabled languages. Currently these are:
|
||||||
|
|
||||||
|
NONE
|
||||||
|
|
||||||
|
See project\(\) command to enable other languages.
|
||||||
|
Call Stack \(most recent call first\):
|
||||||
|
CMakeLists.txt:3 \(include\)
|
|
@ -0,0 +1 @@
|
||||||
|
try_compile(RESULT ${CMAKE_CURRENT_BINARY_DIR} SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src.c)
|
|
@ -0,0 +1 @@
|
||||||
|
1
|
|
@ -0,0 +1,12 @@
|
||||||
|
CMake Error at BadSources2.cmake:2 \(try_compile\):
|
||||||
|
Unknown extension ".cxx" for file
|
||||||
|
|
||||||
|
.*/Tests/RunCMake/try_compile/src.cxx
|
||||||
|
|
||||||
|
try_compile\(\) works only for enabled languages. Currently these are:
|
||||||
|
|
||||||
|
C NONE( RC)?
|
||||||
|
|
||||||
|
See project\(\) command to enable other languages.
|
||||||
|
Call Stack \(most recent call first\):
|
||||||
|
CMakeLists.txt:3 \(include\)
|
|
@ -0,0 +1,5 @@
|
||||||
|
enable_language(C)
|
||||||
|
try_compile(RESULT ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src.cxx
|
||||||
|
)
|
|
@ -0,0 +1 @@
|
||||||
|
1
|
|
@ -0,0 +1,4 @@
|
||||||
|
CMake Error at NoSources.cmake:1 \(try_compile\):
|
||||||
|
SOURCES must be followed by at least one source file
|
||||||
|
Call Stack \(most recent call first\):
|
||||||
|
CMakeLists.txt:3 \(include\)
|
|
@ -0,0 +1 @@
|
||||||
|
try_compile(RESULT ${CMAKE_CURRENT_BINARY_DIR} SOURCES)
|
|
@ -7,6 +7,9 @@ run_cmake(NoCopyFile)
|
||||||
run_cmake(NoCopyFile2)
|
run_cmake(NoCopyFile2)
|
||||||
run_cmake(NoOutputVariable)
|
run_cmake(NoOutputVariable)
|
||||||
run_cmake(NoOutputVariable2)
|
run_cmake(NoOutputVariable2)
|
||||||
|
run_cmake(NoSources)
|
||||||
run_cmake(BadLinkLibraries)
|
run_cmake(BadLinkLibraries)
|
||||||
|
run_cmake(BadSources1)
|
||||||
|
run_cmake(BadSources2)
|
||||||
run_cmake(NonSourceCopyFile)
|
run_cmake(NonSourceCopyFile)
|
||||||
run_cmake(NonSourceCompileDefinitions)
|
run_cmake(NonSourceCompileDefinitions)
|
||||||
|
|
|
@ -71,6 +71,24 @@ if(SHOULD_FAIL)
|
||||||
message(SEND_ERROR "Should fail passed ${TRY_OUT}")
|
message(SEND_ERROR "Should fail passed ${TRY_OUT}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# try to compile two files that should compile
|
||||||
|
try_compile(SHOULD_PASS
|
||||||
|
${TryCompile_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp
|
||||||
|
SOURCES ${TryCompile_SOURCE_DIR}/pass2a.c ${TryCompile_SOURCE_DIR}/pass2b.cxx
|
||||||
|
OUTPUT_VARIABLE TRY_OUT)
|
||||||
|
if(NOT SHOULD_PASS)
|
||||||
|
message(SEND_ERROR "should pass failed ${TRY_OUT}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# try to compile two files that should not compile
|
||||||
|
try_compile(SHOULD_FAIL
|
||||||
|
${TryCompile_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp
|
||||||
|
SOURCES ${TryCompile_SOURCE_DIR}/fail2a.c ${TryCompile_SOURCE_DIR}/fail2b.c
|
||||||
|
OUTPUT_VARIABLE TRY_OUT)
|
||||||
|
if(SHOULD_FAIL)
|
||||||
|
message(SEND_ERROR "Should fail passed ${TRY_OUT}")
|
||||||
|
endif()
|
||||||
|
|
||||||
if(NOT SHOULD_FAIL)
|
if(NOT SHOULD_FAIL)
|
||||||
if(SHOULD_PASS)
|
if(SHOULD_PASS)
|
||||||
message("All Tests passed, ignore all previous output.")
|
message("All Tests passed, ignore all previous output.")
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
int main(void) { return 0; }
|
|
@ -0,0 +1 @@
|
||||||
|
does_not_compile
|
|
@ -0,0 +1,2 @@
|
||||||
|
extern int pass2b(void);
|
||||||
|
int main() { return pass2b(); }
|
|
@ -0,0 +1 @@
|
||||||
|
extern "C" int pass2b(void) { return 0; }
|
Loading…
Reference in New Issue