Merge topic 'export-at-generate-time'

a4263c9 export(): Handle multiple dependent export sets.
66b290e export(): Process the export() command at generate time.
5fe5c32 export(): Set a Makefile on the cmExportBuildFileGenerator.
e383555 cmExportInstallFileGenerator: Fix comment to match reality.
This commit is contained in:
Brad King 2013-10-15 09:32:36 -04:00 committed by CMake Topic Stage
commit 06491955eb
13 changed files with 209 additions and 111 deletions

View File

@ -11,40 +11,38 @@
============================================================================*/ ============================================================================*/
#include "cmExportBuildFileGenerator.h" #include "cmExportBuildFileGenerator.h"
#include "cmExportCommand.h" #include "cmLocalGenerator.h"
#include "cmGlobalGenerator.h"
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
cmExportBuildFileGenerator::cmExportBuildFileGenerator() cmExportBuildFileGenerator::cmExportBuildFileGenerator()
{ {
this->ExportCommand = 0; this->Makefile = 0;
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os)
{ {
std::vector<cmTarget*> allTargets;
{ {
std::string expectedTargets; std::string expectedTargets;
std::string sep; std::string sep;
for(std::vector<cmTarget*>::const_iterator for(std::vector<std::string>::const_iterator
tei = this->Exports->begin(); tei = this->Targets.begin();
tei != this->Exports->end(); ++tei) tei != this->Targets.end(); ++tei)
{ {
expectedTargets += sep + this->Namespace + (*tei)->GetExportName(); cmTarget *te = this->Makefile->FindTargetToUse(tei->c_str());
expectedTargets += sep + this->Namespace + te->GetExportName();
sep = " "; sep = " ";
cmTarget* te = *tei;
if(this->ExportedTargets.insert(te).second) if(this->ExportedTargets.insert(te).second)
{ {
allTargets.push_back(te); this->Exports.push_back(te);
} }
else else
{
if(this->ExportCommand && this->ExportCommand->ErrorMessage.empty())
{ {
cmOStringStream e; cmOStringStream e;
e << "given target \"" << te->GetName() << "\" more than once."; e << "given target \"" << te->GetName() << "\" more than once.";
this->ExportCommand->ErrorMessage = e.str(); this->Makefile->GetCMakeInstance()
} ->IssueMessage(cmake::FATAL_ERROR, e.str().c_str(), this->Backtrace);
return false; return false;
} }
if (te->GetType() == cmTarget::INTERFACE_LIBRARY) if (te->GetType() == cmTarget::INTERFACE_LIBRARY)
@ -60,8 +58,8 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os)
// Create all the imported targets. // Create all the imported targets.
for(std::vector<cmTarget*>::const_iterator for(std::vector<cmTarget*>::const_iterator
tei = allTargets.begin(); tei = this->Exports.begin();
tei != allTargets.end(); ++tei) tei != this->Exports.end(); ++tei)
{ {
cmTarget* te = *tei; cmTarget* te = *tei;
this->GenerateImportTargetCode(os, te); this->GenerateImportTargetCode(os, te);
@ -116,8 +114,8 @@ cmExportBuildFileGenerator
std::vector<std::string> &missingTargets) std::vector<std::string> &missingTargets)
{ {
for(std::vector<cmTarget*>::const_iterator for(std::vector<cmTarget*>::const_iterator
tei = this->Exports->begin(); tei = this->Exports.begin();
tei != this->Exports->end(); ++tei) tei != this->Exports.end(); ++tei)
{ {
// Collect import properties for this target. // Collect import properties for this target.
cmTarget* target = *tei; cmTarget* target = *tei;
@ -198,40 +196,95 @@ cmExportBuildFileGenerator
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void void
cmExportBuildFileGenerator::HandleMissingTarget( cmExportBuildFileGenerator::HandleMissingTarget(
std::string& link_libs, std::vector<std::string>&, std::string& link_libs, std::vector<std::string>& missingTargets,
cmMakefile*, cmTarget* depender, cmTarget* dependee) cmMakefile* mf, cmTarget* depender, cmTarget* dependee)
{ {
// The target is not in the export. // The target is not in the export.
if(!this->AppendMode) if(!this->AppendMode)
{
const std::string name = dependee->GetName();
std::vector<std::string> namespaces = this->FindNamespaces(mf, name);
int targetOccurrences = (int)namespaces.size();
if (targetOccurrences == 1)
{
std::string missingTarget = namespaces[0];
missingTarget += dependee->GetExportName();
link_libs += missingTarget;
missingTargets.push_back(missingTarget);
return;
}
else
{ {
// We are not appending, so all exported targets should be // We are not appending, so all exported targets should be
// known here. This is probably user-error. // known here. This is probably user-error.
this->ComplainAboutMissingTarget(depender, dependee); this->ComplainAboutMissingTarget(depender, dependee, targetOccurrences);
}
} }
// Assume the target will be exported by another command. // Assume the target will be exported by another command.
// Append it with the export namespace. // Append it with the export namespace.
link_libs += this->Namespace; link_libs += this->Namespace;
link_libs += dependee->GetExportName(); link_libs += dependee->GetExportName();
// if generate time {}
}
//----------------------------------------------------------------------------
std::vector<std::string>
cmExportBuildFileGenerator
::FindNamespaces(cmMakefile* mf, const std::string& name)
{
std::vector<std::string> namespaces;
cmGlobalGenerator* gg = mf->GetLocalGenerator()->GetGlobalGenerator();
std::map<std::string, cmExportBuildFileGenerator*>& exportSets
= gg->GetBuildExportSets();
for(std::map<std::string, cmExportBuildFileGenerator*>::const_iterator
expIt = exportSets.begin(); expIt != exportSets.end(); ++expIt)
{
const cmExportBuildFileGenerator* exportSet = expIt->second;
std::vector<std::string> const& targets = exportSet->GetTargets();
if (std::find(targets.begin(), targets.end(), name) != targets.end())
{
namespaces.push_back(exportSet->GetNamespace());
}
}
return namespaces;
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void void
cmExportBuildFileGenerator cmExportBuildFileGenerator
::ComplainAboutMissingTarget(cmTarget* depender, ::ComplainAboutMissingTarget(cmTarget* depender,
cmTarget* dependee) cmTarget* dependee,
int occurrences)
{ {
if(!this->ExportCommand || !this->ExportCommand->ErrorMessage.empty()) if(cmSystemTools::GetErrorOccuredFlag())
{ {
return; return;
} }
cmOStringStream e; cmOStringStream e;
e << "called with target \"" << depender->GetName() e << "export called with target \"" << depender->GetName()
<< "\" which requires target \"" << dependee->GetName() << "\" which requires target \"" << dependee->GetName() << "\" ";
<< "\" that is not in the export list.\n" if (occurrences == 0)
<< "If the required target is not easy to reference in this call, " {
e << "that is not in the export set.\n";
}
else
{
e << "that is not in this export set, but " << occurrences
<< " times in others.\n";
}
e << "If the required target is not easy to reference in this call, "
<< "consider using the APPEND option with multiple separate calls."; << "consider using the APPEND option with multiple separate calls.";
this->ExportCommand->ErrorMessage = e.str();
this->Makefile->GetCMakeInstance()
->IssueMessage(cmake::FATAL_ERROR, e.str().c_str(), this->Backtrace);
} }
std::string std::string

View File

@ -13,8 +13,7 @@
#define cmExportBuildFileGenerator_h #define cmExportBuildFileGenerator_h
#include "cmExportFileGenerator.h" #include "cmExportFileGenerator.h"
#include "cmListFileCache.h"
class cmExportCommand;
/** \class cmExportBuildFileGenerator /** \class cmExportBuildFileGenerator
* \brief Generate a file exporting targets from a build tree. * \brief Generate a file exporting targets from a build tree.
@ -31,14 +30,22 @@ public:
cmExportBuildFileGenerator(); cmExportBuildFileGenerator();
/** Set the list of targets to export. */ /** Set the list of targets to export. */
void SetExports(std::vector<cmTarget*> const* exports) void SetTargets(std::vector<std::string> const& targets)
{ this->Exports = exports; } { this->Targets = targets; }
std::vector<std::string> const& GetTargets() const
{ return this->Targets; }
void AppendTargets(std::vector<std::string> const& targets)
{ this->Targets.insert(this->Targets.end(),
targets.begin(), targets.end()); }
/** Set whether to append generated code to the output file. */ /** Set whether to append generated code to the output file. */
void SetAppendMode(bool append) { this->AppendMode = append; } void SetAppendMode(bool append) { this->AppendMode = append; }
/** Set the command instance through which errors should be reported. */ void SetMakefile(cmMakefile *mf) {
void SetCommand(cmExportCommand* cmd) { this->ExportCommand = cmd; } this->Makefile = mf;
this->Makefile->GetBacktrace(this->Backtrace);
}
protected: protected:
// Implement virtual methods from the superclass. // Implement virtual methods from the superclass.
virtual bool GenerateMainFile(std::ostream& os); virtual bool GenerateMainFile(std::ostream& os);
@ -53,7 +60,8 @@ protected:
cmTarget* dependee); cmTarget* dependee);
void ComplainAboutMissingTarget(cmTarget* depender, void ComplainAboutMissingTarget(cmTarget* depender,
cmTarget* dependee); cmTarget* dependee,
int occurrences);
/** Fill in properties indicating built file locations. */ /** Fill in properties indicating built file locations. */
void SetImportLocationProperty(const char* config, void SetImportLocationProperty(const char* config,
@ -63,8 +71,13 @@ protected:
std::string InstallNameDir(cmTarget* target, const std::string& config); std::string InstallNameDir(cmTarget* target, const std::string& config);
std::vector<cmTarget*> const* Exports; std::vector<std::string>
cmExportCommand* ExportCommand; FindNamespaces(cmMakefile* mf, const std::string& name);
std::vector<std::string> Targets;
std::vector<cmTarget*> Exports;
cmMakefile* Makefile;
cmListFileBacktrace Backtrace;
}; };
#endif #endif

View File

@ -108,8 +108,6 @@ bool cmExportCommand
fname += this->Filename.GetString(); fname += this->Filename.GetString();
} }
// Collect the targets to be exported.
std::vector<cmTarget*> targets;
for(std::vector<std::string>::const_iterator for(std::vector<std::string>::const_iterator
currentTarget = this->Targets.GetVector().begin(); currentTarget = this->Targets.GetVector().begin();
currentTarget != this->Targets.GetVector().end(); currentTarget != this->Targets.GetVector().end();
@ -128,15 +126,7 @@ bool cmExportCommand
this->Makefile->GetLocalGenerator()-> this->Makefile->GetLocalGenerator()->
GetGlobalGenerator()->FindTarget(0, currentTarget->c_str())) GetGlobalGenerator()->FindTarget(0, currentTarget->c_str()))
{ {
if((target->GetType() == cmTarget::EXECUTABLE) || if(target->GetType() == cmTarget::OBJECT_LIBRARY)
(target->GetType() == cmTarget::STATIC_LIBRARY) ||
(target->GetType() == cmTarget::SHARED_LIBRARY) ||
(target->GetType() == cmTarget::MODULE_LIBRARY) ||
(target->GetType() == cmTarget::INTERFACE_LIBRARY))
{
targets.push_back(target);
}
else if(target->GetType() == cmTarget::OBJECT_LIBRARY)
{ {
cmOStringStream e; cmOStringStream e;
e << "given OBJECT library \"" << *currentTarget e << "given OBJECT library \"" << *currentTarget
@ -144,37 +134,28 @@ bool cmExportCommand
this->SetError(e.str().c_str()); this->SetError(e.str().c_str());
return false; return false;
} }
else
{
cmOStringStream e;
e << "given target \"" << *currentTarget
<< "\" which is not an executable or library.";
this->SetError(e.str().c_str());
return false;
} }
} }
else
cmGlobalGenerator *gg = this->Makefile->GetLocalGenerator()
->GetGlobalGenerator();
if (this->Append.IsEnabled())
{ {
cmOStringStream e; if (cmExportBuildFileGenerator *ebfg = gg->GetExportedTargetsFile(fname))
e << "given target \"" << *currentTarget {
<< "\" which is not built by this project."; ebfg->AppendTargets(this->Targets.GetVector());
this->SetError(e.str().c_str()); return true;
return false;
} }
} }
// Setup export file generation. // Setup export file generation.
cmExportBuildFileGenerator ebfg; cmExportBuildFileGenerator *ebfg = new cmExportBuildFileGenerator;
ebfg.SetExportFile(fname.c_str()); ebfg->SetExportFile(fname.c_str());
ebfg.SetNamespace(this->Namespace.GetCString()); ebfg->SetNamespace(this->Namespace.GetCString());
ebfg.SetAppendMode(this->Append.IsEnabled()); ebfg->SetAppendMode(this->Append.IsEnabled());
ebfg.SetExports(&targets); ebfg->SetTargets(this->Targets.GetVector());
ebfg.SetCommand(this); ebfg->SetMakefile(this->Makefile);
ebfg.SetExportOld(this->ExportOld.IsEnabled()); ebfg->SetExportOld(this->ExportOld.IsEnabled());
cmGlobalGenerator *gg = this->Makefile->GetLocalGenerator()
->GetGlobalGenerator();
gg->AddExportedTargetsFile(fname);
// Compute the set of configurations exported. // Compute the set of configurations exported.
std::vector<std::string> configurationTypes; std::vector<std::string> configurationTypes;
@ -185,27 +166,15 @@ bool cmExportCommand
ci = configurationTypes.begin(); ci = configurationTypes.begin();
ci != configurationTypes.end(); ++ci) ci != configurationTypes.end(); ++ci)
{ {
ebfg.AddConfiguration(ci->c_str()); ebfg->AddConfiguration(ci->c_str());
} }
} }
else else
{ {
ebfg.AddConfiguration(""); ebfg->AddConfiguration("");
} }
// Generate the import file. gg->AddBuildExportSet(ebfg);
if(!ebfg.GenerateImportFile() && this->ErrorMessage.empty())
{
this->SetError("could not write export file.");
return false;
}
// Report generated error message if any.
if(!this->ErrorMessage.empty())
{
this->SetError(this->ErrorMessage.c_str());
return false;
}
return true; return true;
} }

View File

@ -85,7 +85,9 @@ public:
"should never be installed. " "should never be installed. "
"See the install(EXPORT) command to export targets from an " "See the install(EXPORT) command to export targets from an "
"installation tree." "installation tree."
CM_LOCATION_UNDEFINED_BEHAVIOR("passing it to this command") "\n"
"The properties set on the generated IMPORTED targets will have the "
"same values as the final values of the input TARGETS."
"\n" "\n"
" export(PACKAGE <name>)\n" " export(PACKAGE <name>)\n"
"Store the current build directory in the CMake user package registry " "Store the current build directory in the CMake user package registry "

View File

@ -51,6 +51,12 @@ void cmExportFileGenerator::SetExportFile(const char* mainFile)
cmSystemTools::GetFilenameLastExtension(this->MainImportFile); cmSystemTools::GetFilenameLastExtension(this->MainImportFile);
} }
//----------------------------------------------------------------------------
const char* cmExportFileGenerator::GetMainExportFileName() const
{
return this->MainImportFile.c_str();
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
bool cmExportFileGenerator::GenerateImportFile() bool cmExportFileGenerator::GenerateImportFile()
{ {

View File

@ -33,9 +33,11 @@ public:
/** Set the full path to the export file to generate. */ /** Set the full path to the export file to generate. */
void SetExportFile(const char* mainFile); void SetExportFile(const char* mainFile);
const char *GetMainExportFileName() const;
/** Set the namespace in which to place exported target names. */ /** Set the namespace in which to place exported target names. */
void SetNamespace(const char* ns) { this->Namespace = ns; } void SetNamespace(const char* ns) { this->Namespace = ns; }
std::string GetNamespace() const { return this->Namespace; }
void SetExportOld(bool exportOld) { this->ExportOld = exportOld; } void SetExportOld(bool exportOld) { this->ExportOld = exportOld; }

View File

@ -432,8 +432,8 @@ cmExportInstallFileGenerator::HandleMissingTarget(
} }
else else
{ {
// We are not appending, so all exported targets should be // All exported targets should be known here and should be unique.
// known here. This is probably user-error. // This is probably user-error.
this->ComplainAboutMissingTarget(depender, dependee, targetOccurrences); this->ComplainAboutMissingTarget(depender, dependee, targetOccurrences);
} }
} }

View File

@ -27,6 +27,7 @@
#include "cmGeneratorTarget.h" #include "cmGeneratorTarget.h"
#include "cmGeneratorExpression.h" #include "cmGeneratorExpression.h"
#include "cmGeneratorExpressionEvaluationFile.h" #include "cmGeneratorExpressionEvaluationFile.h"
#include "cmExportBuildFileGenerator.h"
#include <cmsys/Directory.hxx> #include <cmsys/Directory.hxx>
@ -77,6 +78,12 @@ cmGlobalGenerator::~cmGlobalGenerator()
{ {
delete *li; delete *li;
} }
for(std::map<std::string, cmExportBuildFileGenerator*>::iterator
i = this->BuildExportSets.begin();
i != this->BuildExportSets.end(); ++i)
{
delete i->second;
}
this->LocalGenerators.clear(); this->LocalGenerators.clear();
if (this->ExtraGenerator) if (this->ExtraGenerator)
@ -183,6 +190,34 @@ void cmGlobalGenerator::ResolveLanguageCompiler(const std::string &lang,
doc.c_str(), cmCacheManager::FILEPATH); doc.c_str(), cmCacheManager::FILEPATH);
} }
void cmGlobalGenerator::AddBuildExportSet(cmExportBuildFileGenerator* gen)
{
this->BuildExportSets[gen->GetMainExportFileName()] = gen;
}
bool cmGlobalGenerator::GenerateImportFile(const std::string &file)
{
std::map<std::string, cmExportBuildFileGenerator*>::iterator it
= this->BuildExportSets.find(file);
if (it != this->BuildExportSets.end())
{
bool result = it->second->GenerateImportFile();
delete it->second;
it->second = 0;
this->BuildExportSets.erase(it);
return result;
}
return false;
}
bool
cmGlobalGenerator::IsExportedTargetsFile(const std::string &filename) const
{
const std::map<std::string, cmExportBuildFileGenerator*>::const_iterator it
= this->BuildExportSets.find(filename);
return it != this->BuildExportSets.end();
}
// Find the make program for the generator, required for try compiles // Find the make program for the generator, required for try compiles
void cmGlobalGenerator::FindMakeProgram(cmMakefile* mf) void cmGlobalGenerator::FindMakeProgram(cmMakefile* mf)
{ {
@ -966,6 +1001,14 @@ void cmGlobalGenerator::Configure()
} }
} }
cmExportBuildFileGenerator*
cmGlobalGenerator::GetExportedTargetsFile(const std::string &filename) const
{
std::map<std::string, cmExportBuildFileGenerator*>::const_iterator it
= this->BuildExportSets.find(filename);
return it == this->BuildExportSets.end() ? 0 : it->second;
}
bool cmGlobalGenerator::CheckALLOW_DUPLICATE_CUSTOM_TARGETS() bool cmGlobalGenerator::CheckALLOW_DUPLICATE_CUSTOM_TARGETS()
{ {
// If the property is not enabled then okay. // If the property is not enabled then okay.
@ -1091,6 +1134,19 @@ void cmGlobalGenerator::Generate()
} }
this->SetCurrentLocalGenerator(0); this->SetCurrentLocalGenerator(0);
for (std::map<std::string, cmExportBuildFileGenerator*>::iterator
it = this->BuildExportSets.begin(); it != this->BuildExportSets.end();
++it)
{
if (!it->second->GenerateImportFile()
&& !cmSystemTools::GetErrorOccuredFlag())
{
this->GetCMakeInstance()
->IssueMessage(cmake::FATAL_ERROR, "Could not write export file.",
cmListFileBacktrace());
return;
}
}
// Update rule hashes. // Update rule hashes.
this->CheckRuleHashes(); this->CheckRuleHashes();

View File

@ -31,6 +31,7 @@ class cmExternalMakefileProjectGenerator;
class cmTarget; class cmTarget;
class cmInstallTargetGenerator; class cmInstallTargetGenerator;
class cmInstallFilesGenerator; class cmInstallFilesGenerator;
class cmExportBuildFileGenerator;
/** \class cmGlobalGenerator /** \class cmGlobalGenerator
* \brief Responable for overseeing the generation process for the entire tree * \brief Responable for overseeing the generation process for the entire tree
@ -293,18 +294,13 @@ public:
void ProcessEvaluationFiles(); void ProcessEvaluationFiles();
void AddExportedTargetsFile(const std::string &filename) std::map<std::string, cmExportBuildFileGenerator*>& GetBuildExportSets()
{ {return this->BuildExportSets;}
this->ExportedTargetsFiles.insert(filename); void AddBuildExportSet(cmExportBuildFileGenerator*);
} bool IsExportedTargetsFile(const std::string &filename) const;
bool GenerateImportFile(const std::string &file);
bool IsExportedTargetsFile(const std::string &filename) const cmExportBuildFileGenerator*
{ GetExportedTargetsFile(const std::string &filename) const;
const std::set<std::string>::const_iterator it
= this->ExportedTargetsFiles.find(filename);
return it != this->ExportedTargetsFiles.end();
}
protected: protected:
typedef std::vector<cmLocalGenerator*> GeneratorVector; typedef std::vector<cmLocalGenerator*> GeneratorVector;
// for a project collect all its targets by following depend // for a project collect all its targets by following depend
@ -356,6 +352,7 @@ protected:
bool InstallTargetEnabled; bool InstallTargetEnabled;
// Sets of named target exports // Sets of named target exports
cmExportSetMap ExportSets; cmExportSetMap ExportSets;
std::map<std::string, cmExportBuildFileGenerator*> BuildExportSets;
// Manifest of all targets that will be built for each configuration. // Manifest of all targets that will be built for each configuration.
// This is computed just before local generators generate. // This is computed just before local generators generate.
@ -384,7 +381,6 @@ private:
std::map<cmStdString, cmStdString> ExtensionToLanguage; std::map<cmStdString, cmStdString> ExtensionToLanguage;
std::map<cmStdString, int> LanguageToLinkerPreference; std::map<cmStdString, int> LanguageToLinkerPreference;
std::map<cmStdString, cmStdString> LanguageToOriginalSharedLibFlags; std::map<cmStdString, cmStdString> LanguageToOriginalSharedLibFlags;
std::set<std::string> ExportedTargetsFiles;
// Record hashes for rules and outputs. // Record hashes for rules and outputs.
struct RuleHash { char Data[32]; }; struct RuleHash { char Data[32]; };

View File

@ -127,6 +127,7 @@ bool cmIncludeCommand
return false; return false;
} }
} }
gg->GenerateImportFile(fname_abs);
} }
std::string fullFilePath; std::string fullFilePath;

View File

@ -1,4 +1,4 @@
CMake Error at CMP0022-export.cmake:11 \(export\): CMake Error in CMakeLists.txt:
Target "cmp0022NEW" has policy CMP0022 enabled, but also has old-style Target "cmp0022NEW" has policy CMP0022 enabled, but also has old-style
LINK_INTERFACE_LIBRARIES properties populated, but it was exported without LINK_INTERFACE_LIBRARIES properties populated, but it was exported without
the EXPORT_LINK_INTERFACE_LIBRARIES to export the old-style properties the EXPORT_LINK_INTERFACE_LIBRARIES to export the old-style properties

View File

@ -1,6 +1,4 @@
CMake Error: CMake can not determine linker language for target: NoLanguage CMake Error: CMake can not determine linker language for target: NoLanguage
CMake Error at NoLanguage.cmake:2 \(export\): CMake Error in CMakeLists.txt:
Exporting the target "NoLanguage" is not allowed since its linker language Exporting the target "NoLanguage" is not allowed since its linker language
cannot be determined cannot be determined
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,2 @@
enum some_compilers { need_more_than_nothing };