diff options
author | Brad King <brad.king@kitware.com> | 2013-02-25 18:12:02 (GMT) |
---|---|---|
committer | CMake Topic Stage <kwrobot@kitware.com> | 2013-02-25 18:12:02 (GMT) |
commit | b887bca6ee3651857be663fe1f2e2f2c1ed1ac1e (patch) | |
tree | 26a9d0ed2226fa86be6cbffe6ffbbd661c6a40b1 /Source | |
parent | 6e567cabea8df6f8fc8c401f4b9bfe2997c4399e (diff) | |
parent | 236133e79e2d047810eeba90915e38d9861e2a22 (diff) | |
download | CMake-b887bca6ee3651857be663fe1f2e2f2c1ed1ac1e.zip CMake-b887bca6ee3651857be663fe1f2e2f2c1ed1ac1e.tar.gz CMake-b887bca6ee3651857be663fe1f2e2f2c1ed1ac1e.tar.bz2 |
Merge topic 'try_compile-targets'
236133e Handle targets in the LINK_LIBRARIES of try_compile.
1c0597c Add a new Export generator for IMPORTED targets.
f2ab17d Keep track of all targets seen while evaluating a genex.
Diffstat (limited to 'Source')
-rw-r--r-- | Source/CMakeLists.txt | 2 | ||||
-rw-r--r-- | Source/cmCoreTryCompile.cxx | 108 | ||||
-rw-r--r-- | Source/cmExportFileGenerator.cxx | 3 | ||||
-rw-r--r-- | Source/cmExportTryCompileFileGenerator.cxx | 114 | ||||
-rw-r--r-- | Source/cmExportTryCompileFileGenerator.h | 55 | ||||
-rw-r--r-- | Source/cmGeneratorExpression.cxx | 3 | ||||
-rw-r--r-- | Source/cmGeneratorExpression.h | 8 | ||||
-rw-r--r-- | Source/cmGeneratorExpressionEvaluator.cxx | 4 | ||||
-rw-r--r-- | Source/cmGeneratorExpressionEvaluator.h | 3 | ||||
-rw-r--r-- | Source/cmTryCompileCommand.h | 8 |
10 files changed, 293 insertions, 15 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 7808f23..ab62d2b 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -176,6 +176,8 @@ set(SRCS cmExportFileGenerator.cxx cmExportInstallFileGenerator.h cmExportInstallFileGenerator.cxx + cmExportTryCompileFileGenerator.h + cmExportTryCompileFileGenerator.cxx cmExportSet.h cmExportSet.cxx cmExportSetMap.h diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx index 1ae7035..387f6ed 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -13,8 +13,11 @@ #include "cmake.h" #include "cmCacheManager.h" #include "cmGlobalGenerator.h" +#include "cmExportTryCompileFileGenerator.h" #include <cmsys/Directory.hxx> +#include <assert.h> + int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv) { this->BinaryDirectory = argv[1].c_str(); @@ -39,7 +42,8 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv) // is not used, so it matches regular command line parsing which has // the program name as arg 0 for (; i < argv.size() && argv[i] != "COMPILE_DEFINITIONS" && - argv[i] != "OUTPUT_VARIABLE"; + argv[i] != "OUTPUT_VARIABLE" && + argv[i] != "LINK_LIBRARIES"; ++i) { extraArgs++; @@ -75,7 +79,8 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv) { extraArgs++; for (i = i + 1; i < argv.size() && argv[i] != "CMAKE_FLAGS" && - argv[i] != "OUTPUT_VARIABLE"; + argv[i] != "OUTPUT_VARIABLE" && + argv[i] != "LINK_LIBRARIES"; ++i) { extraArgs++; @@ -85,6 +90,61 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv) } } + std::vector<cmTarget*> targets; + std::string libsToLink = " "; + bool useOldLinkLibs = true; + for (i = 3; i < argv.size(); ++i) + { + if (argv[i] == "LINK_LIBRARIES") + { + if ( argv.size() <= (i+1) ) + { + this->Makefile->IssueMessage(cmake::FATAL_ERROR, + "LINK_LIBRARIES specified but there is no content"); + return -1; + } + extraArgs++; + ++i; + useOldLinkLibs = false; + for ( ; i < argv.size() && argv[i] != "CMAKE_FLAGS" + && argv[i] != "COMPILE_DEFINITIONS" && argv[i] != "OUTPUT_VARIABLE"; + ++i) + { + extraArgs++; + libsToLink += argv[i] + " "; + cmTarget *tgt = this->Makefile->FindTargetToUse(argv[i].c_str()); + if (!tgt) + { + continue; + } + switch(tgt->GetType()) + { + case cmTarget::SHARED_LIBRARY: + case cmTarget::STATIC_LIBRARY: + case cmTarget::UNKNOWN_LIBRARY: + break; + case cmTarget::EXECUTABLE: + if (tgt->IsExecutableWithExports()) + { + break; + } + default: + this->Makefile->IssueMessage(cmake::FATAL_ERROR, + "Only libraries may be used as try_compile IMPORTED " + "LINK_LIBRARIES. Got " + std::string(tgt->GetName()) + " of " + "type " + tgt->GetTargetTypeName(tgt->GetType()) + "."); + return -1; + } + if (!tgt->IsImported()) + { + continue; + } + targets.push_back(tgt); + } + break; + } + } + // look for COPY_FILE std::string copyFile; for (i = 3; i < argv.size(); ++i) @@ -247,6 +307,32 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv) fprintf(fout, ")\n"); } + /* Use a random file name to avoid rapid creation and deletion + of the same executable name (some filesystems fail on that). */ + sprintf(targetNameBuf, "cmTryCompileExec%u", + cmSystemTools::RandomSeed()); + targetName = targetNameBuf; + + if (!targets.empty()) + { + std::string fname = "/" + std::string(targetName) + "Targets.cmake"; + cmExportTryCompileFileGenerator tcfg; + tcfg.SetExportFile((this->BinaryDirectory + fname).c_str()); + tcfg.SetExports(targets); + tcfg.SetConfig(this->Makefile->GetDefinition( + "CMAKE_TRY_COMPILE_CONFIGURATION")); + + if(!tcfg.GenerateImportFile()) + { + this->Makefile->IssueMessage(cmake::FATAL_ERROR, + "could not write export file."); + return -1; + } + fprintf(fout, + "\ninclude(\"${CMAKE_CURRENT_LIST_DIR}/%s\")\n\n", + fname.c_str()); + } + /* for the TRY_COMPILEs we want to be able to specify the architecture. So the user can set CMAKE_OSX_ARCHITECTURE to i386;ppc and then set CMAKE_TRY_COMPILE_OSX_ARCHITECTURE first to i386 and then to ppc to @@ -286,18 +372,22 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv) fprintf(fout, "SET(CMAKE_POSITION_INDEPENDENT_CODE \"ON\")\n"); } - /* Use a random file name to avoid rapid creation and deletion - of the same executable name (some filesystems fail on that). */ - sprintf(targetNameBuf, "cmTryCompileExec%u", - cmSystemTools::RandomSeed()); - targetName = targetNameBuf; - /* 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 \"%s\")\n", targetName, source.c_str()); - fprintf(fout, "TARGET_LINK_LIBRARIES(%s ${LINK_LIBRARIES})\n",targetName); + if (useOldLinkLibs) + { + fprintf(fout, + "TARGET_LINK_LIBRARIES(%s ${LINK_LIBRARIES})\n",targetName); + } + else + { + fprintf(fout, "TARGET_LINK_LIBRARIES(%s %s)\n", + targetName, + libsToLink.c_str()); + } fclose(fout); projectName = "CMAKE_TRY_COMPILE"; // if the source is not in CMakeTmp diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index e55f168..7fd0380 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -679,6 +679,9 @@ cmExportFileGenerator case cmTarget::MODULE_LIBRARY: os << "add_library(" << targetName << " MODULE IMPORTED)\n"; break; + case cmTarget::UNKNOWN_LIBRARY: + os << "add_library(" << targetName << " UNKNOWN IMPORTED)\n"; + break; default: // should never happen break; } diff --git a/Source/cmExportTryCompileFileGenerator.cxx b/Source/cmExportTryCompileFileGenerator.cxx new file mode 100644 index 0000000..75f2651 --- /dev/null +++ b/Source/cmExportTryCompileFileGenerator.cxx @@ -0,0 +1,114 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2013 Stephen Kelly <steveire@gmail.com> + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmExportTryCompileFileGenerator.h" + +#include "cmGeneratedFileStream.h" +#include "cmGeneratorExpressionDAGChecker.h" + +//---------------------------------------------------------------------------- +bool cmExportTryCompileFileGenerator::GenerateMainFile(std::ostream& os) +{ + std::set<cmTarget*> emitted; + std::set<cmTarget*> emittedDeps; + while(!this->Exports.empty()) + { + cmTarget* te = this->Exports.back(); + this->Exports.pop_back(); + if (emitted.insert(te).second) + { + emittedDeps.insert(te); + this->GenerateImportTargetCode(os, te); + + ImportPropertyMap properties; + + this->FindTargets("INTERFACE_INCLUDE_DIRECTORIES", te, emittedDeps); + this->FindTargets("INTERFACE_COMPILE_DEFINITIONS", te, emittedDeps); + + this->PopulateProperties(te, properties, emittedDeps); + + this->GenerateInterfaceProperties(te, os, properties); + } + } + return true; +} + +std::string cmExportTryCompileFileGenerator::FindTargets(const char *propName, + cmTarget *tgt, + std::set<cmTarget*> &emitted) +{ + const char *prop = tgt->GetProperty(propName); + if(!prop) + { + return std::string(); + } + + cmListFileBacktrace lfbt; + cmGeneratorExpression ge(lfbt); + + cmGeneratorExpressionDAGChecker dagChecker(lfbt, + tgt->GetName(), + propName, 0, 0); + + cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(prop); + + cmTarget dummyHead; + dummyHead.SetType(cmTarget::EXECUTABLE, "try_compile_dummy_exe"); + dummyHead.SetMakefile(tgt->GetMakefile()); + + std::string result = cge->Evaluate(tgt->GetMakefile(), this->Config, + false, &dummyHead, tgt, &dagChecker); + + const std::set<cmTarget*> &allTargets = cge->GetAllTargetsSeen(); + for(std::set<cmTarget*>::const_iterator li = allTargets.begin(); + li != allTargets.end(); ++li) + { + if(emitted.insert(*li).second) + { + this->Exports.push_back(*li); + } + } + return result; +} + +//---------------------------------------------------------------------------- +void +cmExportTryCompileFileGenerator::PopulateProperties(cmTarget* target, + ImportPropertyMap& properties, + std::set<cmTarget*> &emitted) +{ + cmPropertyMap props = target->GetProperties(); + for(cmPropertyMap::const_iterator i = props.begin(); i != props.end(); ++i) + { + properties[i->first] = i->second.GetValue(); + + if(i->first.find("IMPORTED_LINK_INTERFACE_LIBRARIES") == 0) + { + const std::string libs = i->second.GetValue(); + + std::string evalResult = this->FindTargets(i->first.c_str(), + target, emitted); + + std::vector<std::string> depends; + cmSystemTools::ExpandListArgument(evalResult, depends); + for(std::vector<std::string>::const_iterator li = depends.begin(); + li != depends.end(); ++li) + { + cmTarget *tgt = target->GetMakefile()->FindTargetToUse(li->c_str()); + if(tgt && emitted.insert(tgt).second) + { + this->Exports.push_back(tgt); + } + } + } + } +} diff --git a/Source/cmExportTryCompileFileGenerator.h b/Source/cmExportTryCompileFileGenerator.h new file mode 100644 index 0000000..ed393ab --- /dev/null +++ b/Source/cmExportTryCompileFileGenerator.h @@ -0,0 +1,55 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2013 Stephen Kelly <steveire@gmail.com> + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#ifndef cmExportInstallFileGenerator_h +#define cmExportInstallFileGenerator_h + +#include "cmExportFileGenerator.h" + +class cmInstallExportGenerator; +class cmInstallTargetGenerator; + +class cmExportTryCompileFileGenerator: public cmExportFileGenerator +{ +public: + /** Set the list of targets to export. */ + void SetExports(const std::vector<cmTarget*> &exports) + { this->Exports = exports; } + void SetConfig(const char *config) { this->Config = config; } +protected: + + // Implement virtual methods from the superclass. + virtual bool GenerateMainFile(std::ostream& os); + + virtual void GenerateImportTargetsConfig(std::ostream&, + const char*, + std::string const&, + std::vector<std::string>&) {} + virtual void HandleMissingTarget(std::string&, + std::vector<std::string>&, + cmMakefile*, + cmTarget*, + cmTarget*) {} + + void PopulateProperties(cmTarget* target, + ImportPropertyMap& properties, + std::set<cmTarget*> &emitted); + +private: + std::string FindTargets(const char *prop, cmTarget *tgt, + std::set<cmTarget*> &emitted); + + + std::vector<cmTarget*> Exports; + const char *Config; +}; + +#endif diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx index 5d162fe..51ebddb 100644 --- a/Source/cmGeneratorExpression.cxx +++ b/Source/cmGeneratorExpression.cxx @@ -114,7 +114,8 @@ const char *cmCompiledGeneratorExpression::Evaluate( this->HadContextSensitiveCondition = context.HadContextSensitiveCondition; } - this->Targets = context.Targets; + this->DependTargets = context.DependTargets; + this->AllTargetsSeen = context.AllTargets; // TODO: Return a std::string from here instead? return this->Output.c_str(); } diff --git a/Source/cmGeneratorExpression.h b/Source/cmGeneratorExpression.h index 489b052..e223034 100644 --- a/Source/cmGeneratorExpression.h +++ b/Source/cmGeneratorExpression.h @@ -88,11 +88,14 @@ public: /** Get set of targets found during evaluations. */ std::set<cmTarget*> const& GetTargets() const - { return this->Targets; } + { return this->DependTargets; } std::set<cmStdString> const& GetSeenTargetProperties() const { return this->SeenTargetProperties; } + std::set<cmTarget*> const& GetAllTargetsSeen() const + { return this->AllTargetsSeen; } + ~cmCompiledGeneratorExpression(); std::string GetInput() const @@ -123,7 +126,8 @@ private: const std::string Input; bool NeedsParsing; - mutable std::set<cmTarget*> Targets; + mutable std::set<cmTarget*> DependTargets; + mutable std::set<cmTarget*> AllTargetsSeen; mutable std::set<cmStdString> SeenTargetProperties; mutable std::string Output; mutable bool HadContextSensitiveCondition; diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx index cd6a40b..97ba524 100644 --- a/Source/cmGeneratorExpressionEvaluator.cxx +++ b/Source/cmGeneratorExpressionEvaluator.cxx @@ -392,6 +392,7 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode reportError(context, content->GetOriginalExpression(), e.str()); return std::string(); } + context->AllTargets.insert(target); } if (target == context->HeadTarget) @@ -852,7 +853,8 @@ struct TargetFilesystemArtifact : public cmGeneratorExpressionNode "Target \"" + name + "\" is not an executable or library."); return std::string(); } - context->Targets.insert(target); + context->DependTargets.insert(target); + context->AllTargets.insert(target); std::string result = TargetFilesystemArtifactResultCreator<linker, soname>::Create( diff --git a/Source/cmGeneratorExpressionEvaluator.h b/Source/cmGeneratorExpressionEvaluator.h index 37d5c86..ce7ad69 100644 --- a/Source/cmGeneratorExpressionEvaluator.h +++ b/Source/cmGeneratorExpressionEvaluator.h @@ -23,7 +23,8 @@ class cmTarget; struct cmGeneratorExpressionContext { cmListFileBacktrace Backtrace; - std::set<cmTarget*> Targets; + std::set<cmTarget*> DependTargets; + std::set<cmTarget*> AllTargets; std::set<cmStdString> SeenTargetProperties; cmMakefile *Makefile; const char *Config; diff --git a/Source/cmTryCompileCommand.h b/Source/cmTryCompileCommand.h index 68ec666..6caa130 100644 --- a/Source/cmTryCompileCommand.h +++ b/Source/cmTryCompileCommand.h @@ -67,6 +67,7 @@ public: " try_compile(RESULT_VAR <bindir> <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. " @@ -90,7 +91,12 @@ public: "Some extra flags that can be included are, " "INCLUDE_DIRECTORIES, LINK_DIRECTORIES, and LINK_LIBRARIES. " "COMPILE_DEFINITIONS are -Ddefinition that will be passed to the " - "compile line. " + "compile line.\n" + "The srcfile signature also accepts a LINK_LIBRARIES argument which " + "may contain a list of libraries or IMPORTED targets which will be " + "linked to in the generated project. If LINK_LIBRARIES is specified " + "as a parameter to try_compile, then any LINK_LIBRARIES passed as " + "CMAKE_FLAGS will be ignored.\n" "try_compile creates a CMakeList.txt " "file on the fly that looks like this:\n" " add_definitions( <expanded COMPILE_DEFINITIONS from calling " |