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];
|
||||
bool didOutputVariable = false;
|
||||
bool didCopyFile = false;
|
||||
bool useSources = argv[2] == "SOURCES";
|
||||
std::vector<std::string> sources;
|
||||
|
||||
enum Doing { DoingNone, DoingCMakeFlags, DoingCompileDefinitions,
|
||||
DoingLinkLibraries, DoingOutputVariable, DoingCopyFile };
|
||||
Doing doing = DoingNone;
|
||||
DoingLinkLibraries, DoingOutputVariable, DoingCopyFile,
|
||||
DoingSources };
|
||||
Doing doing = useSources? DoingSources : DoingNone;
|
||||
for(size_t i=3; i < argv.size(); ++i)
|
||||
{
|
||||
if(argv[i] == "CMAKE_FLAGS")
|
||||
|
@ -118,6 +121,10 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv)
|
|||
copyFile = argv[i].c_str();
|
||||
doing = DoingNone;
|
||||
}
|
||||
else if(doing == DoingSources)
|
||||
{
|
||||
sources.push_back(argv[i]);
|
||||
}
|
||||
else if(i == 3)
|
||||
{
|
||||
this->SrcFileSignature = false;
|
||||
|
@ -149,6 +156,13 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv)
|
|||
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
|
||||
// signature
|
||||
if (this->SrcFileSignature)
|
||||
|
@ -193,6 +207,44 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv)
|
|||
std::string ccFile = this->BinaryDirectory + "/CMakeCache.txt";
|
||||
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...
|
||||
// first create the directories
|
||||
sourceDirectory = this->BinaryDirectory.c_str();
|
||||
|
@ -209,10 +261,6 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv)
|
|||
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");
|
||||
fprintf(fout, "cmake_minimum_required(VERSION %u.%u.%u.%u)\n",
|
||||
cmVersion::GetMajorVersion(), cmVersion::GetMinorVersion(),
|
||||
|
@ -222,57 +270,39 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv)
|
|||
fprintf(fout, "SET(CMAKE_MODULE_PATH %s)\n", def);
|
||||
}
|
||||
|
||||
const char* rulesOverrideBase = "CMAKE_USER_MAKE_RULES_OVERRIDE";
|
||||
std::string rulesOverrideLang =
|
||||
rulesOverrideBase + (lang ? std::string("_") + lang : std::string(""));
|
||||
if(const char* rulesOverridePath =
|
||||
this->Makefile->GetDefinition(rulesOverrideLang.c_str()))
|
||||
std::string projectLangs;
|
||||
for(std::set<std::string>::iterator li = testLangs.begin();
|
||||
li != testLangs.end(); ++li)
|
||||
{
|
||||
fprintf(fout, "SET(%s \"%s\")\n",
|
||||
rulesOverrideLang.c_str(), rulesOverridePath);
|
||||
}
|
||||
else if(const char* rulesOverridePath2 =
|
||||
this->Makefile->GetDefinition(rulesOverrideBase))
|
||||
{
|
||||
fprintf(fout, "SET(%s \"%s\")\n",
|
||||
rulesOverrideBase, rulesOverridePath2);
|
||||
}
|
||||
|
||||
if(lang)
|
||||
{
|
||||
fprintf(fout, "PROJECT(CMAKE_TRY_COMPILE %s)\n", lang);
|
||||
}
|
||||
else
|
||||
{
|
||||
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)
|
||||
projectLangs += " " + *li;
|
||||
std::string rulesOverrideBase = "CMAKE_USER_MAKE_RULES_OVERRIDE";
|
||||
std::string rulesOverrideLang = rulesOverrideBase + "_" + *li;
|
||||
if(const char* rulesOverridePath =
|
||||
this->Makefile->GetDefinition(rulesOverrideLang.c_str()))
|
||||
{
|
||||
err << " " << *l;
|
||||
fprintf(fout, "SET(%s \"%s\")\n",
|
||||
rulesOverrideLang.c_str(), rulesOverridePath);
|
||||
}
|
||||
else if(const char* rulesOverridePath2 =
|
||||
this->Makefile->GetDefinition(rulesOverrideBase.c_str()))
|
||||
{
|
||||
fprintf(fout, "SET(%s \"%s\")\n",
|
||||
rulesOverrideBase.c_str(), rulesOverridePath2);
|
||||
}
|
||||
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, "PROJECT(CMAKE_TRY_COMPILE%s)\n", projectLangs.c_str());
|
||||
fprintf(fout, "SET(CMAKE_VERBOSE_MAKEFILE 1)\n");
|
||||
fprintf(fout, "SET(CMAKE_%s_FLAGS \"", lang);
|
||||
const char* flags = this->Makefile->GetDefinition(langFlags.c_str());
|
||||
if(flags)
|
||||
for(std::set<std::string>::iterator li = testLangs.begin();
|
||||
li != testLangs.end(); ++li)
|
||||
{
|
||||
fprintf(fout, " %s ", 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, " ${COMPILE_DEFINITIONS}\")\n");
|
||||
}
|
||||
fprintf(fout, " ${COMPILE_DEFINITIONS}\")\n");
|
||||
fprintf(fout, "INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES})\n");
|
||||
fprintf(fout, "SET(CMAKE_SUPPRESS_REGENERATION 1)\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",
|
||||
this->BinaryDirectory.c_str());
|
||||
/* 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)
|
||||
{
|
||||
fprintf(fout,
|
||||
|
@ -371,12 +413,6 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv)
|
|||
}
|
||||
fclose(fout);
|
||||
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();
|
||||
|
|
|
@ -64,16 +64,16 @@ public:
|
|||
"Specify targetName to build a specific target instead of the 'all' or "
|
||||
"'ALL_BUILD' target."
|
||||
"\n"
|
||||
" try_compile(RESULT_VAR <bindir> <srcfile>\n"
|
||||
" try_compile(RESULT_VAR <bindir> <srcfile|SOURCES srcfile...>\n"
|
||||
" [CMAKE_FLAGS flags...]\n"
|
||||
" [COMPILE_DEFINITIONS flags...]\n"
|
||||
" [LINK_LIBRARIES libs...]\n"
|
||||
" [OUTPUT_VARIABLE <var>]\n"
|
||||
" [COPY_FILE <fileName>])\n"
|
||||
"Try building a source file into an executable. "
|
||||
"In this form the user need only supply a source file that defines "
|
||||
"a 'main'. "
|
||||
"CMake will create a CMakeLists.txt file to build the source "
|
||||
"Try building an executable from one or more source files. "
|
||||
"In this form the user need only supply one or more source files "
|
||||
"that include a definition for 'main'. "
|
||||
"CMake will create a CMakeLists.txt file to build the source(s) "
|
||||
"as an executable. "
|
||||
"Specify COPY_FILE to get a copy of the linked executable at the "
|
||||
"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(NoOutputVariable)
|
||||
run_cmake(NoOutputVariable2)
|
||||
run_cmake(NoSources)
|
||||
run_cmake(BadLinkLibraries)
|
||||
run_cmake(BadSources1)
|
||||
run_cmake(BadSources2)
|
||||
run_cmake(NonSourceCopyFile)
|
||||
run_cmake(NonSourceCompileDefinitions)
|
||||
|
|
|
@ -71,6 +71,24 @@ if(SHOULD_FAIL)
|
|||
message(SEND_ERROR "Should fail passed ${TRY_OUT}")
|
||||
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(SHOULD_PASS)
|
||||
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