ENH: Support linking to shared libs with dependent libs
- Split IMPORTED_LINK_LIBRARIES into two parts: IMPORTED_LINK_INTERFACE_LIBRARIES IMPORTED_LINK_DEPENDENT_LIBRARIES - Add CMAKE_DEPENDENT_SHARED_LIBRARY_MODE to select behavior - Set mode to LINK for Darwin (fixes universal binary problem) - Update ExportImport test to account for changes
This commit is contained in:
parent
52e75800b4
commit
2cff26fa52
|
@ -103,6 +103,12 @@ IF(XCODE)
|
||||||
SET(CMAKE_INCLUDE_SYSTEM_FLAG_CXX)
|
SET(CMAKE_INCLUDE_SYSTEM_FLAG_CXX)
|
||||||
ENDIF(XCODE)
|
ENDIF(XCODE)
|
||||||
|
|
||||||
|
# Need to list dependent shared libraries on link line. When building
|
||||||
|
# with -isysroot (for universal binaries), the linker always looks for
|
||||||
|
# dependent libraries under the sysroot. Listing them on the link
|
||||||
|
# line works around the problem.
|
||||||
|
SET(CMAKE_DEPENDENT_SHARED_LIBRARY_MODE "LINK")
|
||||||
|
|
||||||
SET(CMAKE_MacOSX_Content_COMPILE_OBJECT "\"${CMAKE_COMMAND}\" -E copy_if_different <SOURCE> <OBJECT>")
|
SET(CMAKE_MacOSX_Content_COMPILE_OBJECT "\"${CMAKE_COMMAND}\" -E copy_if_different <SOURCE> <OBJECT>")
|
||||||
|
|
||||||
SET(CMAKE_C_CREATE_SHARED_LIBRARY_FORBIDDEN_FLAGS -w)
|
SET(CMAKE_C_CREATE_SHARED_LIBRARY_FORBIDDEN_FLAGS -w)
|
||||||
|
|
|
@ -171,6 +171,14 @@ cmComputeLinkDepends::Compute()
|
||||||
this->FollowLinkEntry(qe);
|
this->FollowLinkEntry(qe);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Complete the search of shared library dependencies.
|
||||||
|
while(!this->SharedDepQueue.empty())
|
||||||
|
{
|
||||||
|
// Handle the next entry.
|
||||||
|
this->HandleSharedDependency(this->SharedDepQueue.front());
|
||||||
|
this->SharedDepQueue.pop();
|
||||||
|
}
|
||||||
|
|
||||||
// Infer dependencies of targets for which they were not known.
|
// Infer dependencies of targets for which they were not known.
|
||||||
this->InferDependencies();
|
this->InferDependencies();
|
||||||
|
|
||||||
|
@ -197,6 +205,20 @@ cmComputeLinkDepends::Compute()
|
||||||
return this->FinalLinkEntries;
|
return this->FinalLinkEntries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
std::map<cmStdString, int>::iterator
|
||||||
|
cmComputeLinkDepends::AllocateLinkEntry(std::string const& item)
|
||||||
|
{
|
||||||
|
std::map<cmStdString, int>::value_type
|
||||||
|
index_entry(item, static_cast<int>(this->EntryList.size()));
|
||||||
|
std::map<cmStdString, int>::iterator
|
||||||
|
lei = this->LinkEntryIndex.insert(index_entry).first;
|
||||||
|
this->EntryList.push_back(LinkEntry());
|
||||||
|
this->InferredDependSets.push_back(0);
|
||||||
|
this->EntryConstraintGraph.push_back(EntryConstraintSet());
|
||||||
|
return lei;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
int cmComputeLinkDepends::AddLinkEntry(std::string const& item)
|
int cmComputeLinkDepends::AddLinkEntry(std::string const& item)
|
||||||
{
|
{
|
||||||
|
@ -209,14 +231,7 @@ int cmComputeLinkDepends::AddLinkEntry(std::string const& item)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate a spot for the item entry.
|
// Allocate a spot for the item entry.
|
||||||
{
|
lei = this->AllocateLinkEntry(item);
|
||||||
std::map<cmStdString, int>::value_type
|
|
||||||
index_entry(item, static_cast<int>(this->EntryList.size()));
|
|
||||||
lei = this->LinkEntryIndex.insert(index_entry).first;
|
|
||||||
this->EntryList.push_back(LinkEntry());
|
|
||||||
this->InferredDependSets.push_back(0);
|
|
||||||
this->EntryConstraintGraph.push_back(EntryConstraintSet());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the item entry.
|
// Initialize the item entry.
|
||||||
int index = lei->second;
|
int index = lei->second;
|
||||||
|
@ -263,18 +278,17 @@ void cmComputeLinkDepends::FollowLinkEntry(BFSEntry const& qe)
|
||||||
if(entry.Target)
|
if(entry.Target)
|
||||||
{
|
{
|
||||||
// Follow the target dependencies.
|
// Follow the target dependencies.
|
||||||
if(entry.Target->IsImported())
|
if(cmTargetLinkInterface const* interface =
|
||||||
{
|
entry.Target->GetLinkInterface(this->Config))
|
||||||
// Imported targets provide their own link information.
|
|
||||||
this->AddImportedLinkEntries(depender_index, entry.Target);
|
|
||||||
}
|
|
||||||
else if(cmTargetLinkInterface const* interface =
|
|
||||||
entry.Target->GetLinkInterface(this->Config))
|
|
||||||
{
|
{
|
||||||
// This target provides its own link interface information.
|
// This target provides its own link interface information.
|
||||||
this->AddLinkEntries(depender_index, *interface);
|
this->AddLinkEntries(depender_index, interface->Libraries);
|
||||||
|
|
||||||
|
// Handle dependent shared libraries.
|
||||||
|
this->QueueSharedDependencies(depender_index, interface->SharedDeps);
|
||||||
}
|
}
|
||||||
else if(entry.Target->GetType() != cmTarget::EXECUTABLE)
|
else if(!entry.Target->IsImported() &&
|
||||||
|
entry.Target->GetType() != cmTarget::EXECUTABLE)
|
||||||
{
|
{
|
||||||
// Use the target's link implementation as the interface.
|
// Use the target's link implementation as the interface.
|
||||||
this->AddTargetLinkEntries(depender_index,
|
this->AddTargetLinkEntries(depender_index,
|
||||||
|
@ -289,13 +303,60 @@ void cmComputeLinkDepends::FollowLinkEntry(BFSEntry const& qe)
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void cmComputeLinkDepends::AddImportedLinkEntries(int depender_index,
|
void
|
||||||
cmTarget* target)
|
cmComputeLinkDepends
|
||||||
|
::QueueSharedDependencies(int depender_index,
|
||||||
|
std::vector<std::string> const& deps)
|
||||||
{
|
{
|
||||||
if(std::vector<std::string> const* libs =
|
for(std::vector<std::string>::const_iterator li = deps.begin();
|
||||||
target->GetImportedLinkLibraries(this->Config))
|
li != deps.end(); ++li)
|
||||||
{
|
{
|
||||||
this->AddLinkEntries(depender_index, *libs);
|
SharedDepEntry qe;
|
||||||
|
qe.Item = *li;
|
||||||
|
qe.DependerIndex = depender_index;
|
||||||
|
this->SharedDepQueue.push(qe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void cmComputeLinkDepends::HandleSharedDependency(SharedDepEntry const& dep)
|
||||||
|
{
|
||||||
|
// Check if the target already has an entry.
|
||||||
|
std::map<cmStdString, int>::iterator lei =
|
||||||
|
this->LinkEntryIndex.find(dep.Item);
|
||||||
|
if(lei == this->LinkEntryIndex.end())
|
||||||
|
{
|
||||||
|
// Allocate a spot for the item entry.
|
||||||
|
lei = this->AllocateLinkEntry(dep.Item);
|
||||||
|
|
||||||
|
// Initialize the item entry.
|
||||||
|
LinkEntry& entry = this->EntryList[lei->second];
|
||||||
|
entry.Item = dep.Item;
|
||||||
|
entry.Target = this->Makefile->FindTargetToUse(dep.Item.c_str());
|
||||||
|
|
||||||
|
// This item was added specifically because it is a dependent
|
||||||
|
// shared library. It may get special treatment
|
||||||
|
// in cmComputeLinkInformation.
|
||||||
|
entry.IsSharedDep = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the link entry for this target.
|
||||||
|
int index = lei->second;
|
||||||
|
LinkEntry& entry = this->EntryList[index];
|
||||||
|
|
||||||
|
// This shared library dependency must be preceded by the item that
|
||||||
|
// listed it.
|
||||||
|
this->EntryConstraintGraph[index].insert(dep.DependerIndex);
|
||||||
|
|
||||||
|
// Target items may have their own dependencies.
|
||||||
|
if(entry.Target)
|
||||||
|
{
|
||||||
|
if(cmTargetLinkInterface const* interface =
|
||||||
|
entry.Target->GetLinkInterface(this->Config))
|
||||||
|
{
|
||||||
|
// We use just the shared dependencies, not the interface.
|
||||||
|
this->QueueSharedDependencies(index, interface->SharedDeps);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,8 +41,10 @@ public:
|
||||||
{
|
{
|
||||||
std::string Item;
|
std::string Item;
|
||||||
cmTarget* Target;
|
cmTarget* Target;
|
||||||
LinkEntry(): Item(), Target(0) {}
|
bool IsSharedDep;
|
||||||
LinkEntry(LinkEntry const& r): Item(r.Item), Target(r.Target) {}
|
LinkEntry(): Item(), Target(0), IsSharedDep(false) {}
|
||||||
|
LinkEntry(LinkEntry const& r):
|
||||||
|
Item(r.Item), Target(r.Target), IsSharedDep(r.IsSharedDep) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<LinkEntry> EntryVector;
|
typedef std::vector<LinkEntry> EntryVector;
|
||||||
|
@ -65,8 +67,9 @@ private:
|
||||||
|
|
||||||
typedef cmTarget::LinkLibraryVectorType LinkLibraryVectorType;
|
typedef cmTarget::LinkLibraryVectorType LinkLibraryVectorType;
|
||||||
|
|
||||||
|
std::map<cmStdString, int>::iterator
|
||||||
|
AllocateLinkEntry(std::string const& item);
|
||||||
int AddLinkEntry(std::string const& item);
|
int AddLinkEntry(std::string const& item);
|
||||||
void AddImportedLinkEntries(int depender_index, cmTarget* target);
|
|
||||||
void AddVarLinkEntries(int depender_index, const char* value);
|
void AddVarLinkEntries(int depender_index, const char* value);
|
||||||
void AddTargetLinkEntries(int depender_index,
|
void AddTargetLinkEntries(int depender_index,
|
||||||
LinkLibraryVectorType const& libs);
|
LinkLibraryVectorType const& libs);
|
||||||
|
@ -86,6 +89,19 @@ private:
|
||||||
std::queue<BFSEntry> BFSQueue;
|
std::queue<BFSEntry> BFSQueue;
|
||||||
void FollowLinkEntry(BFSEntry const&);
|
void FollowLinkEntry(BFSEntry const&);
|
||||||
|
|
||||||
|
// Shared libraries that are included only because they are
|
||||||
|
// dependencies of other shared libraries, not because they are part
|
||||||
|
// of the interface.
|
||||||
|
struct SharedDepEntry
|
||||||
|
{
|
||||||
|
std::string Item;
|
||||||
|
int DependerIndex;
|
||||||
|
};
|
||||||
|
std::queue<SharedDepEntry> SharedDepQueue;
|
||||||
|
void QueueSharedDependencies(int depender_index,
|
||||||
|
std::vector<std::string> const& deps);
|
||||||
|
void HandleSharedDependency(SharedDepEntry const& dep);
|
||||||
|
|
||||||
// Dependency inferral for each link item.
|
// Dependency inferral for each link item.
|
||||||
struct DependSet: public std::set<int> {};
|
struct DependSet: public std::set<int> {};
|
||||||
struct DependSetList: public std::vector<DependSet> {};
|
struct DependSetList: public std::vector<DependSet> {};
|
||||||
|
|
|
@ -234,6 +234,21 @@ cmComputeLinkInformation
|
||||||
// Setup framework support.
|
// Setup framework support.
|
||||||
this->ComputeFrameworkInfo();
|
this->ComputeFrameworkInfo();
|
||||||
|
|
||||||
|
// Choose a mode for dealing with shared library dependencies.
|
||||||
|
this->SharedDependencyMode = SharedDepModeNone;
|
||||||
|
if(const char* mode =
|
||||||
|
this->Makefile->GetDefinition("CMAKE_DEPENDENT_SHARED_LIBRARY_MODE"))
|
||||||
|
{
|
||||||
|
if(strcmp(mode, "LINK") == 0)
|
||||||
|
{
|
||||||
|
this->SharedDependencyMode = SharedDepModeLink;
|
||||||
|
}
|
||||||
|
else if(strcmp(mode, "DIR") == 0)
|
||||||
|
{
|
||||||
|
this->SharedDependencyMode = SharedDepModeDir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Get the implicit link directories for this platform.
|
// Get the implicit link directories for this platform.
|
||||||
if(const char* implicitLinks =
|
if(const char* implicitLinks =
|
||||||
(this->Makefile->GetDefinition
|
(this->Makefile->GetDefinition
|
||||||
|
@ -335,7 +350,7 @@ bool cmComputeLinkInformation::Compute()
|
||||||
lei = linkEntries.begin();
|
lei = linkEntries.begin();
|
||||||
lei != linkEntries.end(); ++lei)
|
lei != linkEntries.end(); ++lei)
|
||||||
{
|
{
|
||||||
this->AddItem(lei->Item, lei->Target);
|
this->AddItem(lei->Item, lei->Target, lei->IsSharedDep);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore the target link type so the correct system runtime
|
// Restore the target link type so the correct system runtime
|
||||||
|
@ -358,8 +373,14 @@ bool cmComputeLinkInformation::Compute()
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void cmComputeLinkInformation::AddItem(std::string const& item,
|
void cmComputeLinkInformation::AddItem(std::string const& item,
|
||||||
cmTarget* tgt)
|
cmTarget* tgt, bool isSharedDep)
|
||||||
{
|
{
|
||||||
|
// If dropping shared library dependencies, ignore them.
|
||||||
|
if(isSharedDep && this->SharedDependencyMode == SharedDepModeNone)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Compute the proper name to use to link this library.
|
// Compute the proper name to use to link this library.
|
||||||
const char* config = this->Config;
|
const char* config = this->Config;
|
||||||
bool impexe = (tgt && tgt->IsExecutableWithExports());
|
bool impexe = (tgt && tgt->IsExecutableWithExports());
|
||||||
|
@ -370,12 +391,6 @@ void cmComputeLinkInformation::AddItem(std::string const& item,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep track of shared libraries linked.
|
|
||||||
if(tgt && tgt->GetType() == cmTarget::SHARED_LIBRARY)
|
|
||||||
{
|
|
||||||
this->SharedLibrariesLinked.insert(tgt);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(tgt && (tgt->GetType() == cmTarget::STATIC_LIBRARY ||
|
if(tgt && (tgt->GetType() == cmTarget::STATIC_LIBRARY ||
|
||||||
tgt->GetType() == cmTarget::SHARED_LIBRARY ||
|
tgt->GetType() == cmTarget::SHARED_LIBRARY ||
|
||||||
tgt->GetType() == cmTarget::MODULE_LIBRARY ||
|
tgt->GetType() == cmTarget::MODULE_LIBRARY ||
|
||||||
|
@ -401,6 +416,14 @@ void cmComputeLinkInformation::AddItem(std::string const& item,
|
||||||
(this->UseImportLibrary &&
|
(this->UseImportLibrary &&
|
||||||
(impexe || tgt->GetType() == cmTarget::SHARED_LIBRARY));
|
(impexe || tgt->GetType() == cmTarget::SHARED_LIBRARY));
|
||||||
|
|
||||||
|
// Handle shared dependencies in directory mode.
|
||||||
|
if(isSharedDep && this->SharedDependencyMode == SharedDepModeDir)
|
||||||
|
{
|
||||||
|
std::string dir = tgt->GetDirectory(config, implib);
|
||||||
|
this->SharedDependencyDirectories.push_back(dir);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Pass the full path to the target file.
|
// Pass the full path to the target file.
|
||||||
std::string lib = tgt->GetFullPath(config, implib);
|
std::string lib = tgt->GetFullPath(config, implib);
|
||||||
this->Depends.push_back(lib);
|
this->Depends.push_back(lib);
|
||||||
|
@ -411,6 +434,7 @@ void cmComputeLinkInformation::AddItem(std::string const& item,
|
||||||
// link.
|
// link.
|
||||||
std::string fw = tgt->GetDirectory(config, implib);
|
std::string fw = tgt->GetDirectory(config, implib);
|
||||||
this->AddFrameworkItem(fw);
|
this->AddFrameworkItem(fw);
|
||||||
|
this->SharedLibrariesLinked.insert(tgt);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -705,6 +729,12 @@ void cmComputeLinkInformation::AddTargetItem(std::string const& item,
|
||||||
this->Items.push_back(Item(this->LibLinkFileFlag, false));
|
this->Items.push_back(Item(this->LibLinkFileFlag, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keep track of shared library targets linked.
|
||||||
|
if(target->GetType() == cmTarget::SHARED_LIBRARY)
|
||||||
|
{
|
||||||
|
this->SharedLibrariesLinked.insert(target);
|
||||||
|
}
|
||||||
|
|
||||||
// Now add the full path to the library.
|
// Now add the full path to the library.
|
||||||
this->Items.push_back(Item(item, true));
|
this->Items.push_back(Item(item, true));
|
||||||
}
|
}
|
||||||
|
@ -991,6 +1021,18 @@ void cmComputeLinkInformation::ComputeLinkerSearchDirectories()
|
||||||
{
|
{
|
||||||
this->AddLinkerSearchDirectories(this->OldLinkDirs);
|
this->AddLinkerSearchDirectories(this->OldLinkDirs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Help the linker find dependent shared libraries.
|
||||||
|
if(this->SharedDependencyMode == SharedDepModeDir)
|
||||||
|
{
|
||||||
|
// TODO: These directories should probably be added to the runtime
|
||||||
|
// path ordering analysis. However they are a bit different.
|
||||||
|
// They should be placed both on the -L path and in the rpath.
|
||||||
|
// The link-with-runtime-path feature above should be replaced by
|
||||||
|
// this.
|
||||||
|
this->AddLinkerSearchDirectories(this->SharedDependencyDirectories);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
|
@ -58,7 +58,7 @@ public:
|
||||||
std::string GetChrpathTool();
|
std::string GetChrpathTool();
|
||||||
std::set<cmTarget*> const& GetSharedLibrariesLinked();
|
std::set<cmTarget*> const& GetSharedLibrariesLinked();
|
||||||
private:
|
private:
|
||||||
void AddItem(std::string const& item, cmTarget* tgt);
|
void AddItem(std::string const& item, cmTarget* tgt, bool isSharedDep);
|
||||||
|
|
||||||
// Output information.
|
// Output information.
|
||||||
ItemVector Items;
|
ItemVector Items;
|
||||||
|
@ -78,6 +78,14 @@ private:
|
||||||
const char* Config;
|
const char* Config;
|
||||||
const char* LinkLanguage;
|
const char* LinkLanguage;
|
||||||
|
|
||||||
|
// Modes for dealing with dependent shared libraries.
|
||||||
|
enum SharedDepMode
|
||||||
|
{
|
||||||
|
SharedDepModeNone, // Drop
|
||||||
|
SharedDepModeDir, // Use in runtime information
|
||||||
|
SharedDepModeLink // List file on link line
|
||||||
|
};
|
||||||
|
|
||||||
// System info.
|
// System info.
|
||||||
bool UseImportLibrary;
|
bool UseImportLibrary;
|
||||||
const char* LoaderFlag;
|
const char* LoaderFlag;
|
||||||
|
@ -88,6 +96,7 @@ private:
|
||||||
std::string RuntimeSep;
|
std::string RuntimeSep;
|
||||||
std::string RuntimeAlways;
|
std::string RuntimeAlways;
|
||||||
bool RuntimeUseChrpath;
|
bool RuntimeUseChrpath;
|
||||||
|
SharedDepMode SharedDependencyMode;
|
||||||
|
|
||||||
// Link type adjustment.
|
// Link type adjustment.
|
||||||
void ComputeLinkTypeInfo();
|
void ComputeLinkTypeInfo();
|
||||||
|
@ -134,6 +143,7 @@ private:
|
||||||
void AddLinkerSearchDirectories(std::vector<std::string> const& dirs);
|
void AddLinkerSearchDirectories(std::vector<std::string> const& dirs);
|
||||||
std::set<cmStdString> DirectoriesEmmitted;
|
std::set<cmStdString> DirectoriesEmmitted;
|
||||||
std::set<cmStdString> ImplicitLinkDirs;
|
std::set<cmStdString> ImplicitLinkDirs;
|
||||||
|
std::vector<std::string> SharedDependencyDirectories;
|
||||||
|
|
||||||
// Linker search path compatibility mode.
|
// Linker search path compatibility mode.
|
||||||
std::vector<std::string> OldLinkDirs;
|
std::vector<std::string> OldLinkDirs;
|
||||||
|
|
|
@ -1104,5 +1104,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm)
|
||||||
cmProperty::VARIABLE,0,0);
|
cmProperty::VARIABLE,0,0);
|
||||||
cm->DefineProperty("CMAKE_SHARED_MODULE_RUNTIME_<LANG>_FLAG_SEP",
|
cm->DefineProperty("CMAKE_SHARED_MODULE_RUNTIME_<LANG>_FLAG_SEP",
|
||||||
cmProperty::VARIABLE,0,0);
|
cmProperty::VARIABLE,0,0);
|
||||||
|
cm->DefineProperty("CMAKE_DEPENDENT_SHARED_LIBRARY_MODE",
|
||||||
|
cmProperty::VARIABLE,0,0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,7 +139,12 @@ cmExportFileGenerator
|
||||||
target->GetLinkInterface(config))
|
target->GetLinkInterface(config))
|
||||||
{
|
{
|
||||||
// This target provides a link interface, so use it.
|
// This target provides a link interface, so use it.
|
||||||
this->SetImportLinkProperties(suffix, target, *interface, properties);
|
this->SetImportLinkProperty(suffix, target,
|
||||||
|
"IMPORTED_LINK_INTERFACE_LIBRARIES",
|
||||||
|
interface->Libraries, properties);
|
||||||
|
this->SetImportLinkProperty(suffix, target,
|
||||||
|
"IMPORTED_LINK_DEPENDENT_LIBRARIES",
|
||||||
|
interface->SharedDeps, properties);
|
||||||
}
|
}
|
||||||
else if(target->GetType() == cmTarget::STATIC_LIBRARY ||
|
else if(target->GetType() == cmTarget::STATIC_LIBRARY ||
|
||||||
target->GetType() == cmTarget::SHARED_LIBRARY)
|
target->GetType() == cmTarget::SHARED_LIBRARY)
|
||||||
|
@ -183,17 +188,26 @@ cmExportFileGenerator
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the entries in the property.
|
// Store the entries in the property.
|
||||||
this->SetImportLinkProperties(suffix, target, actual_libs, properties);
|
this->SetImportLinkProperty(suffix, target,
|
||||||
|
"IMPORTED_LINK_INTERFACE_LIBRARIES",
|
||||||
|
actual_libs, properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void
|
void
|
||||||
cmExportFileGenerator
|
cmExportFileGenerator
|
||||||
::SetImportLinkProperties(std::string const& suffix,
|
::SetImportLinkProperty(std::string const& suffix,
|
||||||
cmTarget* target,
|
cmTarget* target,
|
||||||
std::vector<std::string> const& libs,
|
const char* propName,
|
||||||
ImportPropertyMap& properties)
|
std::vector<std::string> const& libs,
|
||||||
|
ImportPropertyMap& properties)
|
||||||
{
|
{
|
||||||
|
// Skip the property if there are no libraries.
|
||||||
|
if(libs.empty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Get the makefile in which to lookup target information.
|
// Get the makefile in which to lookup target information.
|
||||||
cmMakefile* mf = target->GetMakefile();
|
cmMakefile* mf = target->GetMakefile();
|
||||||
|
|
||||||
|
@ -233,6 +247,9 @@ cmExportFileGenerator
|
||||||
// known here. This is probably user-error.
|
// known here. This is probably user-error.
|
||||||
this->ComplainAboutMissingTarget(target, li->c_str());
|
this->ComplainAboutMissingTarget(target, li->c_str());
|
||||||
}
|
}
|
||||||
|
// Assume the target will be exported by another command.
|
||||||
|
// Append it with the export namespace.
|
||||||
|
link_libs += this->Namespace;
|
||||||
link_libs += *li;
|
link_libs += *li;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -244,7 +261,7 @@ cmExportFileGenerator
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the property.
|
// Store the property.
|
||||||
std::string prop = "IMPORTED_LINK_LIBRARIES";
|
std::string prop = propName;
|
||||||
prop += suffix;
|
prop += suffix;
|
||||||
properties[prop] = link_libs;
|
properties[prop] = link_libs;
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,10 +70,10 @@ protected:
|
||||||
void SetImportLinkProperties(const char* config,
|
void SetImportLinkProperties(const char* config,
|
||||||
std::string const& suffix, cmTarget* target,
|
std::string const& suffix, cmTarget* target,
|
||||||
ImportPropertyMap& properties);
|
ImportPropertyMap& properties);
|
||||||
void SetImportLinkProperties(std::string const& suffix,
|
void SetImportLinkProperty(std::string const& suffix,
|
||||||
cmTarget* target,
|
cmTarget* target, const char* propName,
|
||||||
std::vector<std::string> const& libs,
|
std::vector<std::string> const& libs,
|
||||||
ImportPropertyMap& properties);
|
ImportPropertyMap& properties);
|
||||||
|
|
||||||
/** Each subclass knows how to generate its kind of export file. */
|
/** Each subclass knows how to generate its kind of export file. */
|
||||||
virtual bool GenerateMainFile(std::ostream& os) = 0;
|
virtual bool GenerateMainFile(std::ostream& os) = 0;
|
||||||
|
|
|
@ -188,15 +188,38 @@ void cmTarget::DefineProperties(cmake *cm)
|
||||||
"from which the target is imported.");
|
"from which the target is imported.");
|
||||||
|
|
||||||
cm->DefineProperty
|
cm->DefineProperty
|
||||||
("IMPORTED_LINK_LIBRARIES", cmProperty::TARGET,
|
("IMPORTED_LINK_DEPENDENT_LIBRARIES", cmProperty::TARGET,
|
||||||
"Transitive link dependencies of an IMPORTED target.",
|
"Dependent shared libraries of an imported shared library.",
|
||||||
"Lists dependencies that must be linked when an IMPORTED library "
|
"Shared libraries may be linked to other shared libraries as part "
|
||||||
|
"of their implementation. On some platforms the linker searches "
|
||||||
|
"for the dependent libraries of shared libraries they are including "
|
||||||
|
"in the link. CMake gives the paths to these libraries to the linker "
|
||||||
|
"by listing them on the link line explicitly. This property lists "
|
||||||
|
"the dependent shared libraries of an imported library. The list "
|
||||||
|
"should be disjoint from the list of interface libraries in the "
|
||||||
|
"IMPORTED_LINK_INTERFACE_LIBRARIES property. On platforms requiring "
|
||||||
|
"dependent shared libraries to be found at link time CMake uses this "
|
||||||
|
"list to add the dependent libraries to the link command line.");
|
||||||
|
|
||||||
|
cm->DefineProperty
|
||||||
|
("IMPORTED_LINK_DEPENDENT_LIBRARIES_<CONFIG>", cmProperty::TARGET,
|
||||||
|
"Per-configuration version of IMPORTED_LINK_DEPENDENT_LIBRARIES.",
|
||||||
|
"This property is used when loading settings for the <CONFIG> "
|
||||||
|
"configuration of an imported target. "
|
||||||
|
"Configuration names correspond to those provided by the project "
|
||||||
|
"from which the target is imported.");
|
||||||
|
|
||||||
|
cm->DefineProperty
|
||||||
|
("IMPORTED_LINK_INTERFACE_LIBRARIES", cmProperty::TARGET,
|
||||||
|
"Transitive link interface of an IMPORTED target.",
|
||||||
|
"Lists libraries whose interface is included when an IMPORTED library "
|
||||||
"target is linked to another target. "
|
"target is linked to another target. "
|
||||||
|
"The libraries will be included on the link line for the target. "
|
||||||
"Ignored for non-imported targets.");
|
"Ignored for non-imported targets.");
|
||||||
|
|
||||||
cm->DefineProperty
|
cm->DefineProperty
|
||||||
("IMPORTED_LINK_LIBRARIES_<CONFIG>", cmProperty::TARGET,
|
("IMPORTED_LINK_INTERFACE_LIBRARIES_<CONFIG>", cmProperty::TARGET,
|
||||||
"Per-configuration version of IMPORTED_LINK_LIBRARIES property.",
|
"Per-configuration version of IMPORTED_LINK_INTERFACE_LIBRARIES.",
|
||||||
"This property is used when loading settings for the <CONFIG> "
|
"This property is used when loading settings for the <CONFIG> "
|
||||||
"configuration of an imported target. "
|
"configuration of an imported target. "
|
||||||
"Configuration names correspond to those provided by the project "
|
"Configuration names correspond to those provided by the project "
|
||||||
|
@ -3045,43 +3068,56 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the link dependencies.
|
// Get the link interface.
|
||||||
{
|
{
|
||||||
std::string linkProp = "IMPORTED_LINK_LIBRARIES";
|
std::string linkProp = "IMPORTED_LINK_INTERFACE_LIBRARIES";
|
||||||
linkProp += suffix;
|
linkProp += suffix;
|
||||||
if(const char* config_libs = this->GetProperty(linkProp.c_str()))
|
if(const char* config_libs = this->GetProperty(linkProp.c_str()))
|
||||||
{
|
{
|
||||||
cmSystemTools::ExpandListArgument(config_libs, info.LinkLibraries);
|
cmSystemTools::ExpandListArgument(config_libs,
|
||||||
|
info.LinkInterface.Libraries);
|
||||||
}
|
}
|
||||||
else if(const char* libs = this->GetProperty("IMPORTED_LINK_LIBRARIES"))
|
else if(const char* libs =
|
||||||
|
this->GetProperty("IMPORTED_LINK_INTERFACE_LIBRARIES"))
|
||||||
{
|
{
|
||||||
cmSystemTools::ExpandListArgument(libs, info.LinkLibraries);
|
cmSystemTools::ExpandListArgument(libs,
|
||||||
|
info.LinkInterface.Libraries);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the link dependencies.
|
||||||
|
{
|
||||||
|
std::string linkProp = "IMPORTED_LINK_DEPENDENT_LIBRARIES";
|
||||||
|
linkProp += suffix;
|
||||||
|
if(const char* config_libs = this->GetProperty(linkProp.c_str()))
|
||||||
|
{
|
||||||
|
cmSystemTools::ExpandListArgument(config_libs,
|
||||||
|
info.LinkInterface.SharedDeps);
|
||||||
|
}
|
||||||
|
else if(const char* libs =
|
||||||
|
this->GetProperty("IMPORTED_LINK_DEPENDENT_LIBRARIES"))
|
||||||
|
{
|
||||||
|
cmSystemTools::ExpandListArgument(libs, info.LinkInterface.SharedDeps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
std::vector<std::string> const*
|
|
||||||
cmTarget::GetImportedLinkLibraries(const char* config)
|
|
||||||
{
|
|
||||||
if(cmTarget::ImportInfo const* info = this->GetImportInfo(config))
|
|
||||||
{
|
|
||||||
return &info->LinkLibraries;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
cmTargetLinkInterface const* cmTarget::GetLinkInterface(const char* config)
|
cmTargetLinkInterface const* cmTarget::GetLinkInterface(const char* config)
|
||||||
{
|
{
|
||||||
// Link interfaces are supported only for non-imported shared
|
// Imported targets have their own link interface.
|
||||||
// libraries and executables that export symbols. Imported targets
|
if(this->IsImported())
|
||||||
// provide their own link information.
|
{
|
||||||
if(this->IsImported() ||
|
if(cmTarget::ImportInfo const* info = this->GetImportInfo(config))
|
||||||
(this->GetType() != cmTarget::SHARED_LIBRARY &&
|
{
|
||||||
|
return &info->LinkInterface;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Link interfaces are supported only for shared libraries and
|
||||||
|
// executables that export symbols.
|
||||||
|
if((this->GetType() != cmTarget::SHARED_LIBRARY &&
|
||||||
!this->IsExecutableWithExports()))
|
!this->IsExecutableWithExports()))
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -3139,13 +3175,77 @@ cmTargetLinkInterface* cmTarget::ComputeLinkInterface(const char* config)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the interface libraries even if the list is empty.
|
// Allocate the interface.
|
||||||
if(cmTargetLinkInterface* interface = new cmTargetLinkInterface)
|
cmTargetLinkInterface* interface = new cmTargetLinkInterface;
|
||||||
|
if(!interface)
|
||||||
{
|
{
|
||||||
cmSystemTools::ExpandListArgument(libs, *interface);
|
return 0;
|
||||||
return interface;
|
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
// Expand the list of libraries in the interface.
|
||||||
|
cmSystemTools::ExpandListArgument(libs, interface->Libraries);
|
||||||
|
|
||||||
|
// Now we need to construct a list of shared library dependencies
|
||||||
|
// not included in the interface.
|
||||||
|
if(this->GetType() == cmTarget::SHARED_LIBRARY)
|
||||||
|
{
|
||||||
|
// Use a set to keep track of what libraries have been emitted to
|
||||||
|
// either list.
|
||||||
|
std::set<cmStdString> emitted;
|
||||||
|
for(std::vector<std::string>::const_iterator
|
||||||
|
li = interface->Libraries.begin();
|
||||||
|
li != interface->Libraries.end(); ++li)
|
||||||
|
{
|
||||||
|
emitted.insert(*li);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute which library configuration to link.
|
||||||
|
cmTarget::LinkLibraryType linkType = cmTarget::OPTIMIZED;
|
||||||
|
if(config && cmSystemTools::UpperCase(config) == "DEBUG")
|
||||||
|
{
|
||||||
|
linkType = cmTarget::DEBUG;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct the list of libs linked for this configuration.
|
||||||
|
cmTarget::LinkLibraryVectorType const& libs =
|
||||||
|
this->GetOriginalLinkLibraries();
|
||||||
|
for(cmTarget::LinkLibraryVectorType::const_iterator li = libs.begin();
|
||||||
|
li != libs.end(); ++li)
|
||||||
|
{
|
||||||
|
// Skip entries that will resolve to the target itself, are empty,
|
||||||
|
// or are not meant for this configuration.
|
||||||
|
if(li->first == this->GetName() || li->first.empty() ||
|
||||||
|
!(li->second == cmTarget::GENERAL || li->second == linkType))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip entries that have already been emitted into either list.
|
||||||
|
if(!emitted.insert(li->first).second)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add this entry if it is a shared library.
|
||||||
|
if(cmTarget* tgt = this->Makefile->FindTargetToUse(li->first.c_str()))
|
||||||
|
{
|
||||||
|
if(tgt->GetType() == cmTarget::SHARED_LIBRARY)
|
||||||
|
{
|
||||||
|
interface->SharedDeps.push_back(li->first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO: Recognize shared library file names. Perhaps this
|
||||||
|
// should be moved to cmComputeLinkInformation, but that creates
|
||||||
|
// a chicken-and-egg problem since this list is needed for its
|
||||||
|
// construction.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the completed interface.
|
||||||
|
return interface;
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
|
@ -35,9 +35,13 @@ struct cmTargetLinkInformationMap:
|
||||||
~cmTargetLinkInformationMap();
|
~cmTargetLinkInformationMap();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cmTargetLinkInterface: public std::vector<std::string>
|
struct cmTargetLinkInterface
|
||||||
{
|
{
|
||||||
typedef std::vector<std::string> derived;
|
// Libraries listed in the interface.
|
||||||
|
std::vector<std::string> Libraries;
|
||||||
|
|
||||||
|
// Shared library dependencies needed for linking on some platforms.
|
||||||
|
std::vector<std::string> SharedDeps;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cmTargetLinkInterfaceMap:
|
struct cmTargetLinkInterfaceMap:
|
||||||
|
@ -218,11 +222,6 @@ public:
|
||||||
|
|
||||||
bool IsImported() const {return this->IsImportedTarget;}
|
bool IsImported() const {return this->IsImportedTarget;}
|
||||||
|
|
||||||
/** Get link libraries for the given configuration of an imported
|
|
||||||
target. */
|
|
||||||
std::vector<std::string> const*
|
|
||||||
GetImportedLinkLibraries(const char* config);
|
|
||||||
|
|
||||||
/** Get the library interface dependencies. This is the set of
|
/** Get the library interface dependencies. This is the set of
|
||||||
libraries from which something that links to this target may
|
libraries from which something that links to this target may
|
||||||
also receive symbols. Returns 0 if the user has not specified
|
also receive symbols. Returns 0 if the user has not specified
|
||||||
|
@ -487,7 +486,7 @@ private:
|
||||||
std::string Location;
|
std::string Location;
|
||||||
std::string SOName;
|
std::string SOName;
|
||||||
std::string ImportLibrary;
|
std::string ImportLibrary;
|
||||||
std::vector<std::string> LinkLibraries;
|
cmTargetLinkInterface LinkInterface;
|
||||||
};
|
};
|
||||||
typedef std::map<cmStdString, ImportInfo> ImportInfoMapType;
|
typedef std::map<cmStdString, ImportInfo> ImportInfoMapType;
|
||||||
ImportInfoMapType ImportInfoMap;
|
ImportInfoMapType ImportInfoMap;
|
||||||
|
|
|
@ -32,18 +32,12 @@ set_property(TARGET testLib4 PROPERTY FRAMEWORK 1)
|
||||||
add_executable(testExe3 testExe3.c)
|
add_executable(testExe3 testExe3.c)
|
||||||
set_property(TARGET testExe3 PROPERTY MACOSX_BUNDLE 1)
|
set_property(TARGET testExe3 PROPERTY MACOSX_BUNDLE 1)
|
||||||
|
|
||||||
# Install helper targets that are not part of the interface.
|
|
||||||
install(
|
|
||||||
TARGETS testExe2libImp testLib3Imp
|
|
||||||
RUNTIME DESTINATION bin
|
|
||||||
LIBRARY DESTINATION lib
|
|
||||||
ARCHIVE DESTINATION lib
|
|
||||||
)
|
|
||||||
|
|
||||||
# Install and export from install tree.
|
# Install and export from install tree.
|
||||||
install(
|
install(
|
||||||
TARGETS testExe1 testLib1 testLib2 testExe2 testLib3 testLib4 testExe3
|
TARGETS
|
||||||
testExe2lib
|
testExe2libImp testLib3Imp
|
||||||
|
testExe1 testLib1 testLib2 testExe2 testLib3 testLib4 testExe3
|
||||||
|
testExe2lib
|
||||||
EXPORT exp
|
EXPORT exp
|
||||||
RUNTIME DESTINATION bin
|
RUNTIME DESTINATION bin
|
||||||
LIBRARY DESTINATION lib
|
LIBRARY DESTINATION lib
|
||||||
|
@ -55,6 +49,7 @@ install(EXPORT exp NAMESPACE exp_ DESTINATION lib/exp)
|
||||||
|
|
||||||
# Export from build tree.
|
# Export from build tree.
|
||||||
export(TARGETS testExe1 testLib1 testLib2 testLib3
|
export(TARGETS testExe1 testLib1 testLib2 testLib3
|
||||||
|
testExe2libImp testLib3Imp
|
||||||
NAMESPACE bld_
|
NAMESPACE bld_
|
||||||
FILE ExportBuildTree.cmake
|
FILE ExportBuildTree.cmake
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue