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)
|
||||
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_C_CREATE_SHARED_LIBRARY_FORBIDDEN_FLAGS -w)
|
||||
|
|
|
@ -171,6 +171,14 @@ cmComputeLinkDepends::Compute()
|
|||
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.
|
||||
this->InferDependencies();
|
||||
|
||||
|
@ -197,6 +205,20 @@ cmComputeLinkDepends::Compute()
|
|||
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)
|
||||
{
|
||||
|
@ -209,14 +231,7 @@ int cmComputeLinkDepends::AddLinkEntry(std::string const& item)
|
|||
}
|
||||
|
||||
// Allocate a spot for the item entry.
|
||||
{
|
||||
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());
|
||||
}
|
||||
lei = this->AllocateLinkEntry(item);
|
||||
|
||||
// Initialize the item entry.
|
||||
int index = lei->second;
|
||||
|
@ -263,18 +278,17 @@ void cmComputeLinkDepends::FollowLinkEntry(BFSEntry const& qe)
|
|||
if(entry.Target)
|
||||
{
|
||||
// Follow the target dependencies.
|
||||
if(entry.Target->IsImported())
|
||||
{
|
||||
// Imported targets provide their own link information.
|
||||
this->AddImportedLinkEntries(depender_index, entry.Target);
|
||||
}
|
||||
else if(cmTargetLinkInterface const* interface =
|
||||
if(cmTargetLinkInterface const* interface =
|
||||
entry.Target->GetLinkInterface(this->Config))
|
||||
{
|
||||
// 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.
|
||||
this->AddTargetLinkEntries(depender_index,
|
||||
|
@ -289,13 +303,60 @@ void cmComputeLinkDepends::FollowLinkEntry(BFSEntry const& qe)
|
|||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void cmComputeLinkDepends::AddImportedLinkEntries(int depender_index,
|
||||
cmTarget* target)
|
||||
void
|
||||
cmComputeLinkDepends
|
||||
::QueueSharedDependencies(int depender_index,
|
||||
std::vector<std::string> const& deps)
|
||||
{
|
||||
if(std::vector<std::string> const* libs =
|
||||
target->GetImportedLinkLibraries(this->Config))
|
||||
for(std::vector<std::string>::const_iterator li = deps.begin();
|
||||
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;
|
||||
cmTarget* Target;
|
||||
LinkEntry(): Item(), Target(0) {}
|
||||
LinkEntry(LinkEntry const& r): Item(r.Item), Target(r.Target) {}
|
||||
bool IsSharedDep;
|
||||
LinkEntry(): Item(), Target(0), IsSharedDep(false) {}
|
||||
LinkEntry(LinkEntry const& r):
|
||||
Item(r.Item), Target(r.Target), IsSharedDep(r.IsSharedDep) {}
|
||||
};
|
||||
|
||||
typedef std::vector<LinkEntry> EntryVector;
|
||||
|
@ -65,8 +67,9 @@ private:
|
|||
|
||||
typedef cmTarget::LinkLibraryVectorType LinkLibraryVectorType;
|
||||
|
||||
std::map<cmStdString, int>::iterator
|
||||
AllocateLinkEntry(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 AddTargetLinkEntries(int depender_index,
|
||||
LinkLibraryVectorType const& libs);
|
||||
|
@ -86,6 +89,19 @@ private:
|
|||
std::queue<BFSEntry> BFSQueue;
|
||||
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.
|
||||
struct DependSet: public std::set<int> {};
|
||||
struct DependSetList: public std::vector<DependSet> {};
|
||||
|
|
|
@ -234,6 +234,21 @@ cmComputeLinkInformation
|
|||
// Setup framework support.
|
||||
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.
|
||||
if(const char* implicitLinks =
|
||||
(this->Makefile->GetDefinition
|
||||
|
@ -335,7 +350,7 @@ bool cmComputeLinkInformation::Compute()
|
|||
lei = linkEntries.begin();
|
||||
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
|
||||
|
@ -358,8 +373,14 @@ bool cmComputeLinkInformation::Compute()
|
|||
|
||||
//----------------------------------------------------------------------------
|
||||
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.
|
||||
const char* config = this->Config;
|
||||
bool impexe = (tgt && tgt->IsExecutableWithExports());
|
||||
|
@ -370,12 +391,6 @@ void cmComputeLinkInformation::AddItem(std::string const& item,
|
|||
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 ||
|
||||
tgt->GetType() == cmTarget::SHARED_LIBRARY ||
|
||||
tgt->GetType() == cmTarget::MODULE_LIBRARY ||
|
||||
|
@ -401,6 +416,14 @@ void cmComputeLinkInformation::AddItem(std::string const& item,
|
|||
(this->UseImportLibrary &&
|
||||
(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.
|
||||
std::string lib = tgt->GetFullPath(config, implib);
|
||||
this->Depends.push_back(lib);
|
||||
|
@ -411,6 +434,7 @@ void cmComputeLinkInformation::AddItem(std::string const& item,
|
|||
// link.
|
||||
std::string fw = tgt->GetDirectory(config, implib);
|
||||
this->AddFrameworkItem(fw);
|
||||
this->SharedLibrariesLinked.insert(tgt);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -705,6 +729,12 @@ void cmComputeLinkInformation::AddTargetItem(std::string const& item,
|
|||
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.
|
||||
this->Items.push_back(Item(item, true));
|
||||
}
|
||||
|
@ -991,6 +1021,18 @@ void cmComputeLinkInformation::ComputeLinkerSearchDirectories()
|
|||
{
|
||||
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::set<cmTarget*> const& GetSharedLibrariesLinked();
|
||||
private:
|
||||
void AddItem(std::string const& item, cmTarget* tgt);
|
||||
void AddItem(std::string const& item, cmTarget* tgt, bool isSharedDep);
|
||||
|
||||
// Output information.
|
||||
ItemVector Items;
|
||||
|
@ -78,6 +78,14 @@ private:
|
|||
const char* Config;
|
||||
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.
|
||||
bool UseImportLibrary;
|
||||
const char* LoaderFlag;
|
||||
|
@ -88,6 +96,7 @@ private:
|
|||
std::string RuntimeSep;
|
||||
std::string RuntimeAlways;
|
||||
bool RuntimeUseChrpath;
|
||||
SharedDepMode SharedDependencyMode;
|
||||
|
||||
// Link type adjustment.
|
||||
void ComputeLinkTypeInfo();
|
||||
|
@ -134,6 +143,7 @@ private:
|
|||
void AddLinkerSearchDirectories(std::vector<std::string> const& dirs);
|
||||
std::set<cmStdString> DirectoriesEmmitted;
|
||||
std::set<cmStdString> ImplicitLinkDirs;
|
||||
std::vector<std::string> SharedDependencyDirectories;
|
||||
|
||||
// Linker search path compatibility mode.
|
||||
std::vector<std::string> OldLinkDirs;
|
||||
|
|
|
@ -1104,5 +1104,7 @@ void cmDocumentVariables::DefineVariables(cmake* cm)
|
|||
cmProperty::VARIABLE,0,0);
|
||||
cm->DefineProperty("CMAKE_SHARED_MODULE_RUNTIME_<LANG>_FLAG_SEP",
|
||||
cmProperty::VARIABLE,0,0);
|
||||
cm->DefineProperty("CMAKE_DEPENDENT_SHARED_LIBRARY_MODE",
|
||||
cmProperty::VARIABLE,0,0);
|
||||
|
||||
}
|
||||
|
|
|
@ -139,7 +139,12 @@ cmExportFileGenerator
|
|||
target->GetLinkInterface(config))
|
||||
{
|
||||
// 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 ||
|
||||
target->GetType() == cmTarget::SHARED_LIBRARY)
|
||||
|
@ -183,17 +188,26 @@ cmExportFileGenerator
|
|||
}
|
||||
|
||||
// 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
|
||||
cmExportFileGenerator
|
||||
::SetImportLinkProperties(std::string const& suffix,
|
||||
::SetImportLinkProperty(std::string const& suffix,
|
||||
cmTarget* target,
|
||||
const char* propName,
|
||||
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.
|
||||
cmMakefile* mf = target->GetMakefile();
|
||||
|
||||
|
@ -233,6 +247,9 @@ cmExportFileGenerator
|
|||
// known here. This is probably user-error.
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -244,7 +261,7 @@ cmExportFileGenerator
|
|||
}
|
||||
|
||||
// Store the property.
|
||||
std::string prop = "IMPORTED_LINK_LIBRARIES";
|
||||
std::string prop = propName;
|
||||
prop += suffix;
|
||||
properties[prop] = link_libs;
|
||||
}
|
||||
|
|
|
@ -70,8 +70,8 @@ protected:
|
|||
void SetImportLinkProperties(const char* config,
|
||||
std::string const& suffix, cmTarget* target,
|
||||
ImportPropertyMap& properties);
|
||||
void SetImportLinkProperties(std::string const& suffix,
|
||||
cmTarget* target,
|
||||
void SetImportLinkProperty(std::string const& suffix,
|
||||
cmTarget* target, const char* propName,
|
||||
std::vector<std::string> const& libs,
|
||||
ImportPropertyMap& properties);
|
||||
|
||||
|
|
|
@ -188,15 +188,38 @@ void cmTarget::DefineProperties(cmake *cm)
|
|||
"from which the target is imported.");
|
||||
|
||||
cm->DefineProperty
|
||||
("IMPORTED_LINK_LIBRARIES", cmProperty::TARGET,
|
||||
"Transitive link dependencies of an IMPORTED target.",
|
||||
"Lists dependencies that must be linked when an IMPORTED library "
|
||||
("IMPORTED_LINK_DEPENDENT_LIBRARIES", cmProperty::TARGET,
|
||||
"Dependent shared libraries of an imported shared 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. "
|
||||
"The libraries will be included on the link line for the target. "
|
||||
"Ignored for non-imported targets.");
|
||||
|
||||
cm->DefineProperty
|
||||
("IMPORTED_LINK_LIBRARIES_<CONFIG>", cmProperty::TARGET,
|
||||
"Per-configuration version of IMPORTED_LINK_LIBRARIES property.",
|
||||
("IMPORTED_LINK_INTERFACE_LIBRARIES_<CONFIG>", cmProperty::TARGET,
|
||||
"Per-configuration version of IMPORTED_LINK_INTERFACE_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 "
|
||||
|
@ -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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
std::vector<std::string> const*
|
||||
cmTarget::GetImportedLinkLibraries(const char* config)
|
||||
{
|
||||
if(cmTarget::ImportInfo const* info = this->GetImportInfo(config))
|
||||
// Get the link dependencies.
|
||||
{
|
||||
return &info->LinkLibraries;
|
||||
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
|
||||
else if(const char* libs =
|
||||
this->GetProperty("IMPORTED_LINK_DEPENDENT_LIBRARIES"))
|
||||
{
|
||||
return 0;
|
||||
cmSystemTools::ExpandListArgument(libs, info.LinkInterface.SharedDeps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
cmTargetLinkInterface const* cmTarget::GetLinkInterface(const char* config)
|
||||
{
|
||||
// Link interfaces are supported only for non-imported shared
|
||||
// libraries and executables that export symbols. Imported targets
|
||||
// provide their own link information.
|
||||
if(this->IsImported() ||
|
||||
(this->GetType() != cmTarget::SHARED_LIBRARY &&
|
||||
// Imported targets have their own link interface.
|
||||
if(this->IsImported())
|
||||
{
|
||||
if(cmTarget::ImportInfo const* info = this->GetImportInfo(config))
|
||||
{
|
||||
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()))
|
||||
{
|
||||
return 0;
|
||||
|
@ -3139,13 +3175,77 @@ cmTargetLinkInterface* cmTarget::ComputeLinkInterface(const char* config)
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Return the interface libraries even if the list is empty.
|
||||
if(cmTargetLinkInterface* interface = new cmTargetLinkInterface)
|
||||
// Allocate the interface.
|
||||
cmTargetLinkInterface* interface = new cmTargetLinkInterface;
|
||||
if(!interface)
|
||||
{
|
||||
cmSystemTools::ExpandListArgument(libs, *interface);
|
||||
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();
|
||||
};
|
||||
|
||||
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:
|
||||
|
@ -218,11 +222,6 @@ public:
|
|||
|
||||
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
|
||||
libraries from which something that links to this target may
|
||||
also receive symbols. Returns 0 if the user has not specified
|
||||
|
@ -487,7 +486,7 @@ private:
|
|||
std::string Location;
|
||||
std::string SOName;
|
||||
std::string ImportLibrary;
|
||||
std::vector<std::string> LinkLibraries;
|
||||
cmTargetLinkInterface LinkInterface;
|
||||
};
|
||||
typedef std::map<cmStdString, ImportInfo> ImportInfoMapType;
|
||||
ImportInfoMapType ImportInfoMap;
|
||||
|
|
|
@ -32,17 +32,11 @@ set_property(TARGET testLib4 PROPERTY FRAMEWORK 1)
|
|||
add_executable(testExe3 testExe3.c)
|
||||
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(
|
||||
TARGETS testExe1 testLib1 testLib2 testExe2 testLib3 testLib4 testExe3
|
||||
TARGETS
|
||||
testExe2libImp testLib3Imp
|
||||
testExe1 testLib1 testLib2 testExe2 testLib3 testLib4 testExe3
|
||||
testExe2lib
|
||||
EXPORT exp
|
||||
RUNTIME DESTINATION bin
|
||||
|
@ -55,6 +49,7 @@ install(EXPORT exp NAMESPACE exp_ DESTINATION lib/exp)
|
|||
|
||||
# Export from build tree.
|
||||
export(TARGETS testExe1 testLib1 testLib2 testLib3
|
||||
testExe2libImp testLib3Imp
|
||||
NAMESPACE bld_
|
||||
FILE ExportBuildTree.cmake
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue