summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2008-01-22 14:13:04 (GMT)
committerBrad King <brad.king@kitware.com>2008-01-22 14:13:04 (GMT)
commit96fd5909d9dd1ffe740230ce652d574cd01c62d5 (patch)
treee83b3ce2d5066660256a69cacb6caa7d2d95c416 /Source
parent0df9e6904cd2416336a85d6d7972ce84dcbab417 (diff)
downloadCMake-96fd5909d9dd1ffe740230ce652d574cd01c62d5.zip
CMake-96fd5909d9dd1ffe740230ce652d574cd01c62d5.tar.gz
CMake-96fd5909d9dd1ffe740230ce652d574cd01c62d5.tar.bz2
ENH: Implement linking with paths to library files instead of -L and -l separation. See bug #3832
- This is purely an implementation improvement. No interface has changed. - Create cmComputeLinkInformation class - Move and re-implement logic from: cmLocalGenerator::ComputeLinkInformation cmOrderLinkDirectories - Link libraries to targets with their full path (if it is known) - Dirs specified with link_directories command still added with -L - Make link type specific to library names without paths (name libfoo.a without path becomes -Wl,-Bstatic -lfoo) - Make directory ordering specific to a runtime path computation feature (look for conflicting SONAMEs instead of library names) - Implement proper rpath support on HP-UX and AIX.
Diffstat (limited to 'Source')
-rw-r--r--Source/CMakeLists.txt3
-rw-r--r--Source/cmComputeLinkInformation.cxx1157
-rw-r--r--Source/cmComputeLinkInformation.h165
-rw-r--r--Source/cmDocumentVariables.cxx6
-rw-r--r--Source/cmGlobalGenerator.cxx43
-rw-r--r--Source/cmGlobalGenerator.h21
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx88
-rw-r--r--Source/cmLocalGenerator.cxx478
-rw-r--r--Source/cmLocalGenerator.h9
-rw-r--r--Source/cmLocalVisualStudio6Generator.cxx27
-rw-r--r--Source/cmLocalVisualStudio7Generator.cxx75
-rw-r--r--Source/cmLocalVisualStudio7Generator.h7
-rw-r--r--Source/cmOrderLinkDirectories.cxx710
-rw-r--r--Source/cmOrderLinkDirectories.h192
-rw-r--r--Source/cmTarget.cxx131
-rw-r--r--Source/cmTarget.h6
16 files changed, 1697 insertions, 1421 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index e821f91..aacdfcb 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -87,6 +87,8 @@ SET(SRCS
cmCommandArgumentLexer.cxx
cmCommandArgumentParser.cxx
cmCommandArgumentParserHelper.cxx
+ cmComputeLinkInformation.cxx
+ cmComputeLinkInformation.h
cmCustomCommand.cxx
cmCustomCommand.h
cmDepends.cxx
@@ -151,7 +153,6 @@ SET(SRCS
cmMakefileExecutableTargetGenerator.cxx
cmMakefileLibraryTargetGenerator.cxx
cmMakefileUtilityTargetGenerator.cxx
- cmOrderLinkDirectories.cxx
cmProperty.cxx
cmProperty.h
cmPropertyDefinition.cxx
diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx
new file mode 100644
index 0000000..50f69a2
--- /dev/null
+++ b/Source/cmComputeLinkInformation.cxx
@@ -0,0 +1,1157 @@
+/*=========================================================================
+
+ Program: CMake - Cross-Platform Makefile Generator
+ Module: $RCSfile$
+ Language: C++
+ Date: $Date$
+ Version: $Revision$
+
+ Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
+ See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE. See the above copyright notices for more information.
+
+=========================================================================*/
+#include "cmComputeLinkInformation.h"
+
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmTarget.h"
+
+#include <algorithm>
+
+#include <ctype.h>
+
+/*
+Notes about linking on various platforms:
+
+------------------------------------------------------------------------------
+
+Linux, FreeBSD, Mac OS X, IRIX, Sun, Windows:
+
+Linking to libraries using the full path works fine.
+
+------------------------------------------------------------------------------
+
+On AIX, more work is needed.
+
+ The "-bnoipath" option is needed. From "man ld":
+
+ Note: If you specify a shared object, or an archive file
+ containing a shared object, with an absolute or relative path
+ name, instead of with the -lName flag, the path name is
+ included in the import file ID string in the loader section of
+ the output file. You can override this behavior with the
+ -bnoipath option.
+
+ noipath
+
+ For shared objects listed on the command-line, rather than
+ specified with the -l flag, use a null path component when
+ listing the shared object in the loader section of the
+ output file. A null path component is always used for
+ shared objects specified with the -l flag. This option
+ does not affect the specification of a path component by
+ using a line beginning with #! in an import file. The
+ default is the ipath option.
+
+ This prevents the full path specified on the compile line from being
+ compiled directly into the binary.
+
+ By default the linker places -L paths in the embedded runtime path.
+ In order to implement CMake's RPATH interface correctly, we need the
+ -blibpath:Path option. From "man ld":
+
+ libpath:Path
+
+ Uses Path as the library path when writing the loader section
+ of the output file. Path is neither checked for validity nor
+ used when searching for libraries specified by the -l flag.
+ Path overrides any library paths generated when the -L flag is
+ used.
+
+ If you do not specify any -L flags, or if you specify the
+ nolibpath option, the default library path information is
+ written in the loader section of the output file. The default
+ library path information is the value of the LIBPATH
+ environment variable if it is defined, and /usr/lib:/lib,
+ otherwise.
+
+ We can pass -Wl,-blibpath:/usr/lib:/lib always to avoid the -L stuff
+ and not break when the user sets LIBPATH. Then if we want to add an
+ rpath we insert it into the option before /usr/lib.
+
+------------------------------------------------------------------------------
+
+On HP-UX, more work is needed. There are differences between
+versions.
+
+ld: 92453-07 linker linker ld B.10.33 990520
+
+ Linking with a full path works okay for static and shared libraries.
+ The linker seems to always put the full path to where the library
+ was found in the binary whether using a full path or -lfoo syntax.
+ Transitive link dependencies work just fine due to the full paths.
+
+ It has the "-l:libfoo.sl" option. The +nodefaultrpath is accepted
+ but not documented and does not seem to do anything. There is no
+ +forceload option.
+
+ld: 92453-07 linker ld HP Itanium(R) B.12.41 IPF/IPF
+
+ Linking with a full path works okay for static libraries.
+
+ Linking with a full path works okay for shared libraries. However
+ dependent (transitive) libraries of those linked directly must be
+ either found with an rpath stored in the direct dependencies or
+ found in -L paths as if they were specified with "-l:libfoo.sl"
+ (really "-l:<soname>"). The search matches that of the dynamic
+ loader but only with -L paths. In other words, if we have an
+ executable that links to shared library bar which links to shared
+ library foo, the link line for the exe must contain
+
+ /dir/with/bar/libbar.sl -L/dir/with/foo
+
+ It does not matter whether the exe wants to link to foo directly or
+ whether /dir/with/foo/libfoo.sl is listed. The -L path must still
+ be present. It should match the runtime path computed for the
+ executable taking all directly and transitively linked libraries
+ into account.
+
+ The "+nodefaultrpath" option should be used to avoid getting -L
+ paths in the rpath unless we add our own rpath with +b. This means
+ that skip-build-rpath should use this option.
+
+ See documentation in "man ld", "man dld.so", and
+ http://docs.hp.com/en/B2355-90968/creatingandusinglibraries.htm
+
+ +[no]defaultrpath
+ +defaultrpath is the default. Include any paths that are
+ specified with -L in the embedded path, unless you specify the
+ +b option. If you use +b, only the path list specified by +b is
+ in the embedded path.
+
+ The +nodefaultrpath option removes all library paths that were
+ specified with the -L option from the embedded path. The linker
+ searches the library paths specified by the -L option at link
+ time. At run time, the only library paths searched are those
+ specified by the environment variables LD_LIBRARY_PATH and
+ SHLIB_PATH, library paths specified by the +b linker option, and
+ finally the default library paths.
+
+ +rpathfirst
+ This option will cause the paths specified in RPATH (embedded
+ path) to be used before the paths specified in LD_LIBRARY_PATH
+ or SHLIB_PATH, in searching for shared libraries. This changes
+ the default search order of LD_LIBRARY_PATH, SHLIB_PATH, and
+ RPATH (embedded path).
+*/
+
+//----------------------------------------------------------------------------
+cmComputeLinkInformation
+::cmComputeLinkInformation(cmTarget* target, const char* config)
+{
+ // Store context information.
+ this->Target = target;
+ this->Makefile = this->Target->GetMakefile();
+ this->LocalGenerator = this->Makefile->GetLocalGenerator();
+ this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator();
+
+ // The configuration being linked.
+ this->Config = config;
+
+ // Get the language used for linking this target.
+ this->LinkLanguage =
+ this->Target->GetLinkerLanguage(this->GlobalGenerator);
+
+ // Check whether we should use an import library for linking a target.
+ this->UseImportLibrary =
+ this->Makefile->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")?true:false;
+
+ // On platforms without import libraries there may be a special flag
+ // to use when creating a plugin (module) that obtains symbols from
+ // the program that will load it.
+ this->LoaderFlag = 0;
+ if(!this->UseImportLibrary &&
+ this->Target->GetType() == cmTarget::MODULE_LIBRARY)
+ {
+ std::string loader_flag_var = "CMAKE_SHARED_MODULE_LOADER_";
+ loader_flag_var += this->LinkLanguage;
+ loader_flag_var += "_FLAG";
+ this->LoaderFlag = this->Makefile->GetDefinition(loader_flag_var.c_str());
+ }
+
+ // Get options needed to link libraries.
+ this->LibLinkFlag =
+ this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_FLAG");
+ this->LibLinkSuffix =
+ this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_SUFFIX");
+
+ // Get link type information.
+ this->ComputeLinkTypeInfo();
+
+ // Setup the link item parser.
+ this->ComputeItemParserInfo();
+
+ // Setup framework support.
+ this->ComputeFrameworkInfo();
+
+ // Initial state.
+ this->RuntimeSearchPathComputed = false;
+}
+
+//----------------------------------------------------------------------------
+cmComputeLinkInformation::ItemVector const&
+cmComputeLinkInformation::GetItems()
+{
+ return this->Items;
+}
+
+//----------------------------------------------------------------------------
+std::vector<std::string> const& cmComputeLinkInformation::GetDirectories()
+{
+ return this->Directories;
+}
+
+//----------------------------------------------------------------------------
+std::vector<std::string> const& cmComputeLinkInformation::GetDepends()
+{
+ return this->Depends;
+}
+
+//----------------------------------------------------------------------------
+std::vector<std::string> const& cmComputeLinkInformation::GetFrameworkPaths()
+{
+ return this->FrameworkPaths;
+}
+
+//----------------------------------------------------------------------------
+bool cmComputeLinkInformation::Compute()
+{
+ // Skip targets that do not link.
+ if(!(this->Target->GetType() == cmTarget::EXECUTABLE ||
+ this->Target->GetType() == cmTarget::SHARED_LIBRARY ||
+ this->Target->GetType() == cmTarget::MODULE_LIBRARY ||
+ this->Target->GetType() == cmTarget::STATIC_LIBRARY))
+ {
+ return false;
+ }
+
+ // We require a link language for the target.
+ if(!this->LinkLanguage)
+ {
+ cmSystemTools::
+ Error("CMake can not determine linker language for target:",
+ this->Target->GetName());
+ return false;
+ }
+
+ // Compute which library configuration to link.
+ cmTarget::LinkLibraryType linkType = cmTarget::OPTIMIZED;
+ if(this->Config && cmSystemTools::UpperCase(this->Config) == "DEBUG")
+ {
+ linkType = cmTarget::DEBUG;
+ }
+
+ // Get the list of libraries against which this target wants to link.
+ {
+ const cmTarget::LinkLibraryVectorType& libs =
+ this->Target->GetLinkLibraries();
+ for(cmTarget::LinkLibraryVectorType::const_iterator li = libs.begin();
+ li != libs.end(); ++li)
+ {
+ // Link to a library if it is not the same target and is meant for
+ // this configuration type.
+ if((this->Target->GetType() == cmTarget::EXECUTABLE ||
+ li->first != this->Target->GetName()) &&
+ (li->second == cmTarget::GENERAL || li->second == linkType))
+ {
+ this->AddItem(li->first);
+ }
+ }
+ }
+
+ // Restore the target link type so the correct system runtime
+ // libraries are found.
+ this->SetCurrentLinkType(this->StartLinkType);
+
+ // Compute the linker search path.
+ this->ComputeLinkerSearchDirectories();
+
+ return true;
+}
+
+//----------------------------------------------------------------------------
+void cmComputeLinkInformation::AddItem(std::string const& item)
+{
+ // Compute the proper name to use to link this library.
+ // TODO: Change third argument to support imported libraries.
+ cmTarget* tgt = this->GlobalGenerator->FindTarget(0, item.c_str(), false);
+ const char* config = this->Config;
+ bool implib = this->UseImportLibrary;
+ bool impexe = (tgt &&
+ tgt->GetType() == cmTarget::EXECUTABLE &&
+ tgt->GetPropertyAsBool("ENABLE_EXPORTS"));
+ if(impexe && !implib && !this->LoaderFlag)
+ {
+ // Skip linking to executables on platforms with no import
+ // libraries or loader flags.
+ return;
+ }
+
+ if(tgt && (tgt->GetType() == cmTarget::STATIC_LIBRARY ||
+ tgt->GetType() == cmTarget::SHARED_LIBRARY ||
+ tgt->GetType() == cmTarget::MODULE_LIBRARY ||
+ impexe))
+ {
+ // This is a CMake target. Ask the target for its real name.
+ if(impexe && this->LoaderFlag)
+ {
+ // This link item is an executable that may provide symbols
+ // used by this target. A special flag is needed on this
+ // platform. Add it now.
+ std::string linkItem;
+ linkItem = this->LoaderFlag;
+ std::string exe = tgt->GetFullPath(config, implib);
+ linkItem += exe;
+ this->Items.push_back(Item(linkItem, true));
+ this->Depends.push_back(exe);
+ }
+ else
+ {
+ // Pass the full path to the target file.
+ std::string lib = tgt->GetFullPath(config, implib);
+ this->Depends.push_back(lib);
+#ifdef __APPLE__
+ if(tgt->GetType() == cmTarget::SHARED_LIBRARY &&
+ tgt->GetPropertyAsBool("FRAMEWORK"))
+ {
+ // Frameworks on OS X need only the framework directory to
+ // link.
+ std::string fw = tgt->GetDirectory(config, implib);
+ this->AddFrameworkItem(fw);
+ }
+ else
+#endif
+ {
+ this->Items.push_back(Item(lib, true));
+ this->AddLibraryRuntimeInfo(lib, tgt);
+ }
+ }
+ }
+ else
+ {
+ // This is not a CMake target. Use the name given.
+ if(cmSystemTools::FileIsFullPath(item.c_str()))
+ {
+ if(cmSystemTools::FileIsDirectory(item.c_str()))
+ {
+ // This is a directory.
+ this->AddDirectoryItem(item);
+ }
+ else
+ {
+ // Use the full path given to the library file.
+ this->Items.push_back(Item(item, true));
+ this->Depends.push_back(item);
+ this->AddLibraryRuntimeInfo(item);
+ }
+ }
+ else
+ {
+ // This is a library or option specified by the user.
+ this->AddUserItem(item);
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmComputeLinkInformation::ComputeLinkTypeInfo()
+{
+ // First assume we cannot do link type stuff.
+ this->LinkTypeEnabled = false;
+
+ // Lookup link type selection flags.
+ const char* static_link_type_flag = 0;
+ const char* shared_link_type_flag = 0;
+ const char* target_type_str = 0;
+ switch(this->Target->GetType())
+ {
+ case cmTarget::EXECUTABLE: target_type_str = "EXE"; break;
+ case cmTarget::SHARED_LIBRARY: target_type_str = "SHARED_LIBRARY"; break;
+ case cmTarget::MODULE_LIBRARY: target_type_str = "SHARED_MODULE"; break;
+ default: break;
+ }
+ if(target_type_str)
+ {
+ std::string static_link_type_flag_var = "CMAKE_";
+ static_link_type_flag_var += target_type_str;
+ static_link_type_flag_var += "_LINK_STATIC_";
+ static_link_type_flag_var += this->LinkLanguage;
+ static_link_type_flag_var += "_FLAGS";
+ static_link_type_flag =
+ this->Makefile->GetDefinition(static_link_type_flag_var.c_str());
+
+ std::string shared_link_type_flag_var = "CMAKE_";
+ shared_link_type_flag_var += target_type_str;
+ shared_link_type_flag_var += "_LINK_DYNAMIC_";
+ shared_link_type_flag_var += this->LinkLanguage;
+ shared_link_type_flag_var += "_FLAGS";
+ shared_link_type_flag =
+ this->Makefile->GetDefinition(shared_link_type_flag_var.c_str());
+ }
+
+ // We can support link type switching only if all needed flags are
+ // known.
+ if(static_link_type_flag && *static_link_type_flag &&
+ shared_link_type_flag && *shared_link_type_flag)
+ {
+ this->LinkTypeEnabled = true;
+ this->StaticLinkTypeFlag = static_link_type_flag;
+ this->SharedLinkTypeFlag = shared_link_type_flag;
+ }
+
+ // TODO: Lookup the starting link type from the target (is it being
+ // linked statically?).
+ this->StartLinkType = LinkShared;
+ this->CurrentLinkType = this->StartLinkType;
+}
+
+//----------------------------------------------------------------------------
+void cmComputeLinkInformation::ComputeItemParserInfo()
+{
+ // Get possible library name prefixes.
+ cmMakefile* mf = this->Makefile;
+ this->AddLinkPrefix(mf->GetDefinition("CMAKE_STATIC_LIBRARY_PREFIX"));
+ this->AddLinkPrefix(mf->GetDefinition("CMAKE_SHARED_LIBRARY_PREFIX"));
+
+ // Import library names should be matched and treated as shared
+ // libraries for the purposes of linking.
+ this->AddLinkExtension(mf->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX"),
+ LinkShared);
+ this->AddLinkExtension(mf->GetDefinition("CMAKE_STATIC_LIBRARY_SUFFIX"),
+ LinkStatic);
+ this->AddLinkExtension(mf->GetDefinition("CMAKE_SHARED_LIBRARY_SUFFIX"),
+ LinkShared);
+ this->AddLinkExtension(mf->GetDefinition("CMAKE_LINK_LIBRARY_SUFFIX"),
+ LinkUnknown);
+ if(const char* linkSuffixes =
+ mf->GetDefinition("CMAKE_EXTRA_LINK_EXTENSIONS"))
+ {
+ std::vector<std::string> linkSuffixVec;
+ cmSystemTools::ExpandListArgument(linkSuffixes, linkSuffixVec);
+ for(std::vector<std::string>::iterator i = linkSuffixVec.begin();
+ i != linkSuffixVec.end(); ++i)
+ {
+ this->AddLinkExtension(i->c_str(), LinkUnknown);
+ }
+ }
+
+ // Compute a regex to match link extensions.
+ std::string libext = this->CreateExtensionRegex(this->LinkExtensions);
+
+ // Create regex to remove any library extension.
+ std::string reg("(.*)");
+ reg += libext;
+ this->RemoveLibraryExtension.compile(reg.c_str());
+
+ // Create a regex to match a library name. Match index 1 will be
+ // the prefix if it exists and empty otherwise. Match index 2 will
+ // be the library name. Match index 3 will be the library
+ // extension.
+ reg = "^(";
+ for(std::set<cmStdString>::iterator p = this->LinkPrefixes.begin();
+ p != this->LinkPrefixes.end(); ++p)
+ {
+ reg += *p;
+ reg += "|";
+ }
+ reg += ")";
+ reg += "([^/]*)";
+
+ // Create a regex to match any library name.
+ std::string reg_any = reg;
+ reg_any += libext;
+#ifdef CM_COMPUTE_LINK_INFO_DEBUG
+ fprintf(stderr, "any regex [%s]\n", reg_any.c_str());
+#endif
+ this->ExtractAnyLibraryName.compile(reg_any.c_str());
+
+ // Create a regex to match static library names.
+ if(!this->StaticLinkExtensions.empty())
+ {
+ std::string reg_static = reg;
+ reg_static += this->CreateExtensionRegex(this->StaticLinkExtensions);
+#ifdef CM_COMPUTE_LINK_INFO_DEBUG
+ fprintf(stderr, "static regex [%s]\n", reg_static.c_str());
+#endif
+ this->ExtractStaticLibraryName.compile(reg_static.c_str());
+ }
+
+ // Create a regex to match shared library names.
+ if(!this->SharedLinkExtensions.empty())
+ {
+ std::string reg_shared = reg;
+ reg_shared += this->CreateExtensionRegex(this->SharedLinkExtensions);
+#ifdef CM_COMPUTE_LINK_INFO_DEBUG
+ fprintf(stderr, "shared regex [%s]\n", reg_shared.c_str());
+#endif
+ this->ExtractSharedLibraryName.compile(reg_shared.c_str());
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmComputeLinkInformation::AddLinkPrefix(const char* p)
+{
+ if(p)
+ {
+ this->LinkPrefixes.insert(p);
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmComputeLinkInformation::AddLinkExtension(const char* e, LinkType type)
+{
+ if(e && *e)
+ {
+ if(type == LinkStatic)
+ {
+ this->StaticLinkExtensions.push_back(e);
+ }
+ if(type == LinkShared)
+ {
+ this->SharedLinkExtensions.push_back(e);
+ }
+ this->LinkExtensions.push_back(e);
+ }
+}
+
+//----------------------------------------------------------------------------
+std::string
+cmComputeLinkInformation
+::CreateExtensionRegex(std::vector<std::string> const& exts)
+{
+ // Build a list of extension choices.
+ std::string libext = "(";
+ const char* sep = "";
+ for(std::vector<std::string>::const_iterator i = exts.begin();
+ i != exts.end(); ++i)
+ {
+ // Separate this choice from the previous one.
+ libext += sep;
+ sep = "|";
+
+ // Store this extension choice with the "." escaped.
+ libext += "\\";
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ libext += this->NoCaseExpression(i->c_str());
+#else
+ libext += *i;
+#endif
+ }
+
+ // Finish the list.
+ libext += ").*";
+ return libext;
+}
+
+//----------------------------------------------------------------------------
+std::string cmComputeLinkInformation::NoCaseExpression(const char* str)
+{
+ std::string ret;
+ const char* s = str;
+ while(*s)
+ {
+ if(*s == '.')
+ {
+ ret += *s;
+ }
+ else
+ {
+ ret += "[";
+ ret += tolower(*s);
+ ret += toupper(*s);
+ ret += "]";
+ }
+ s++;
+ }
+ return ret;
+}
+
+//-------------------------------------------------------------------
+void cmComputeLinkInformation::SetCurrentLinkType(LinkType lt)
+{
+ // If we are changing the current link type add the flag to tell the
+ // linker about it.
+ if(this->CurrentLinkType != lt)
+ {
+ this->CurrentLinkType = lt;
+
+ if(this->LinkTypeEnabled)
+ {
+ switch(this->CurrentLinkType)
+ {
+ case LinkStatic:
+ this->Items.push_back(Item(this->StaticLinkTypeFlag, false));
+ break;
+ case LinkShared:
+ this->Items.push_back(Item(this->SharedLinkTypeFlag, false));
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmComputeLinkInformation::AddUserItem(std::string const& item)
+{
+ // This is called to handle a link item that does not match a CMake
+ // target and is not a full path. We check here if it looks like a
+ // library file name to automatically request the proper link type
+ // from the linker. For example:
+ //
+ // foo ==> -lfoo
+ // libfoo.a ==> -Wl,-Bstatic -lfoo
+ std::string lib;
+
+ // Parse out the prefix, base, and suffix components of the
+ // library name. If the name matches that of a shared or static
+ // library then set the link type accordingly.
+ //
+ // Search for shared library names first because some platforms
+ // have shared libraries with names that match the static library
+ // pattern. For example cygwin and msys use the convention
+ // libfoo.dll.a for import libraries and libfoo.a for static
+ // libraries. On AIX a library with the name libfoo.a can be
+ // shared!
+ if(this->ExtractSharedLibraryName.find(item))
+ {
+ // This matches a shared library file name.
+#ifdef CM_COMPUTE_LINK_INFO_DEBUG
+ fprintf(stderr, "shared regex matched [%s] [%s] [%s]\n",
+ this->ExtractSharedLibraryName.match(1).c_str(),
+ this->ExtractSharedLibraryName.match(2).c_str(),
+ this->ExtractSharedLibraryName.match(3).c_str());
+#endif
+ // Set the link type to shared.
+ this->SetCurrentLinkType(LinkShared);
+
+ // Use just the library name so the linker will search.
+ lib = this->ExtractSharedLibraryName.match(2);
+ }
+ else if(this->ExtractStaticLibraryName.find(item))
+ {
+ // This matches a static library file name.
+#ifdef CM_COMPUTE_LINK_INFO_DEBUG
+ fprintf(stderr, "static regex matched [%s] [%s] [%s]\n",
+ this->ExtractStaticLibraryName.match(1).c_str(),
+ this->ExtractStaticLibraryName.match(2).c_str(),
+ this->ExtractStaticLibraryName.match(3).c_str());
+#endif
+ // Set the link type to static.
+ this->SetCurrentLinkType(LinkStatic);
+
+ // Use just the library name so the linker will search.
+ lib = this->ExtractStaticLibraryName.match(2);
+ }
+ else if(this->ExtractAnyLibraryName.find(item))
+ {
+ // This matches a library file name.
+#ifdef CM_COMPUTE_LINK_INFO_DEBUG
+ fprintf(stderr, "any regex matched [%s] [%s] [%s]\n",
+ this->ExtractAnyLibraryName.match(1).c_str(),
+ this->ExtractAnyLibraryName.match(2).c_str(),
+ this->ExtractAnyLibraryName.match(3).c_str());
+#endif
+ // Restore the target link type since this item does not specify
+ // one.
+ this->SetCurrentLinkType(this->StartLinkType);
+
+ // Use just the library name so the linker will search.
+ lib = this->ExtractAnyLibraryName.match(2);
+ }
+ else if(item[0] == '-' || item[0] == '$' || item[0] == '`')
+ {
+ // This is a linker option provided by the user. Restore the
+ // target link type since this item does not specify one.
+ this->SetCurrentLinkType(this->StartLinkType);
+
+ // Use the item verbatim.
+ this->Items.push_back(Item(item, false));
+ return;
+ }
+ else
+ {
+ // This is a name specified by the user. We must ask the linker
+ // to search for a library with this name. Restore the target
+ // link type since this item does not specify one.
+ this->SetCurrentLinkType(this->StartLinkType);
+ lib = item;
+ }
+
+ // Create an option to ask the linker to search for the library.
+ std::string out = this->LibLinkFlag;
+ out += lib;
+ out += this->LibLinkSuffix;
+ this->Items.push_back(Item(out, false));
+
+ // Here we could try to find the library the linker will find and
+ // add a runtime information entry for it. It would probably not be
+ // reliable and we want to encourage use of full paths for library
+ // specification.
+}
+
+//----------------------------------------------------------------------------
+void cmComputeLinkInformation::AddFrameworkItem(std::string const& item)
+{
+ // Try to separate the framework name and path.
+ if(!this->SplitFramework.find(item.c_str()))
+ {
+ cmOStringStream e;
+ e << "Could not parse framework path \"" << item << "\" "
+ << "linked by target " << this->Target->GetName() << ".";
+ cmSystemTools::Error(e.str().c_str());
+ return;
+ }
+
+ // Add the directory portion to the framework search path.
+ this->AddFrameworkPath(this->SplitFramework.match(1));
+
+ // Add the item using the -framework option.
+ std::string fw = "-framework ";
+ fw += this->SplitFramework.match(2);
+ this->Items.push_back(Item(fw, false));
+}
+
+//----------------------------------------------------------------------------
+void cmComputeLinkInformation::AddDirectoryItem(std::string const& item)
+{
+#ifdef __APPLE__
+ if(cmSystemTools::IsPathToFramework(item.c_str()))
+ {
+ this->AddFrameworkItem(item);
+ }
+ else
+#endif
+ {
+ this->DropDirectoryItem(item);
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmComputeLinkInformation::DropDirectoryItem(std::string const& item)
+{
+ // A full path to a directory was found as a link item. Warn the
+ // user.
+ cmOStringStream e;
+ e << "WARNING: Target \"" << this->Target->GetName()
+ << "\" requests linking to directory \"" << item << "\". "
+ << "Targets may link only to libraries. "
+ << "CMake is dropping the item.";
+ cmSystemTools::Message(e.str().c_str());
+}
+
+//----------------------------------------------------------------------------
+void cmComputeLinkInformation::ComputeFrameworkInfo()
+{
+ // Avoid adding system framework paths. See "man ld" on OS X.
+ this->FrameworkPathsEmmitted.insert("/Library/Frameworks");
+ this->FrameworkPathsEmmitted.insert("/Network/Library/Frameworks");
+ this->FrameworkPathsEmmitted.insert("/System/Library/Frameworks");
+
+ // Regular expression to extract a framework path and name.
+ this->SplitFramework.compile("(.*)/(.*)\\.framework$");
+}
+
+//----------------------------------------------------------------------------
+void cmComputeLinkInformation::AddFrameworkPath(std::string const& p)
+{
+ if(this->FrameworkPathsEmmitted.insert(p).second)
+ {
+ this->FrameworkPaths.push_back(p);
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmComputeLinkInformation::ComputeLinkerSearchDirectories()
+{
+ // Some search paths should never be emitted.
+ this->DirectoriesEmmitted.insert("");
+ if(const char* implicitLinks =
+ (this->Makefile->GetDefinition
+ ("CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES")))
+ {
+ std::vector<std::string> implicitLinkVec;
+ cmSystemTools::ExpandListArgument(implicitLinks, implicitLinkVec);
+ for(std::vector<std::string>::const_iterator
+ i = implicitLinkVec.begin();
+ i != implicitLinkVec.end(); ++i)
+ {
+ this->DirectoriesEmmitted.insert(*i);
+ }
+ }
+
+ // Check if we need to include the runtime search path at link time.
+ std::string var = "CMAKE_SHARED_LIBRARY_LINK_";
+ var += this->LinkLanguage;
+ var += "_WITH_RUNTIME_PATH";
+ if(this->Makefile->IsOn(var.c_str()))
+ {
+ // This platform requires the runtime library path for shared
+ // libraries to be specified at link time as -L paths. It needs
+ // them so that transitive dependencies of the libraries linked
+ // may be found by the linker.
+ this->AddLinkerSearchDirectories(this->GetRuntimeSearchPath());
+ }
+
+ // Get the search path entries requested by the user.
+ this->AddLinkerSearchDirectories(this->Target->GetLinkDirectories());
+}
+
+//----------------------------------------------------------------------------
+void
+cmComputeLinkInformation
+::AddLinkerSearchDirectories(std::vector<std::string> const& dirs)
+{
+ for(std::vector<std::string>::const_iterator i = dirs.begin();
+ i != dirs.end(); ++i)
+ {
+ if(this->DirectoriesEmmitted.insert(*i).second)
+ {
+ this->Directories.push_back(*i);
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+std::vector<std::string> const&
+cmComputeLinkInformation::GetRuntimeSearchPath()
+{
+ if(!this->RuntimeSearchPathComputed)
+ {
+ this->RuntimeSearchPathComputed = true;
+ this->CollectRuntimeDirectories();
+ this->FindConflictingLibraries();
+ this->OrderRuntimeSearchPath();
+ }
+ return this->RuntimeSearchPath;
+}
+
+//============================================================================
+// Directory ordering computation.
+// - Useful to compute a safe runtime library path order
+// - Need runtime path for supporting INSTALL_RPATH_USE_LINK_PATH
+// - Need runtime path at link time to pickup transitive link dependencies
+// for shared libraries (in future when we do not always add them).
+
+//----------------------------------------------------------------------------
+void
+cmComputeLinkInformation::AddLibraryRuntimeInfo(std::string const& fullPath,
+ cmTarget* target)
+{
+ // Skip targets that are not shared libraries (modules cannot be linked).
+ if(target->GetType() != cmTarget::SHARED_LIBRARY)
+ {
+ return;
+ }
+
+ // Try to get the soname of the library. Only files with this name
+ // could possibly conflict.
+ std::string soName;
+ const char* soname = 0;
+ if(!target->IsImported())
+ {
+ std::string name;
+ std::string realName;
+ std::string impName;
+ std::string pdbName;
+ target->GetLibraryNames(name, soName, realName, impName, pdbName,
+ this->Config);
+ soname = soName.c_str();
+ }
+
+ // Add the library runtime entry.
+ this->AddLibraryRuntimeInfo(fullPath, soname);
+}
+
+//----------------------------------------------------------------------------
+void
+cmComputeLinkInformation::AddLibraryRuntimeInfo(std::string const& fullPath,
+ const char* soname)
+{
+ // Get the name of the library from the file name.
+ std::string file = cmSystemTools::GetFilenameName(fullPath);
+ if(!this->ExtractSharedLibraryName.find(file.c_str()))
+ {
+ // This is not the name of a shared library.
+ return;
+ }
+
+ // Add the runtime information at most once.
+ if(this->LibraryRuntimeInfoEmmitted.insert(fullPath).second)
+ {
+ // Construct the runtime information entry for this library.
+ LibraryRuntimeEntry entry;
+ entry.FileName = cmSystemTools::GetFilenameName(fullPath);
+ entry.SOName = soname? soname : "";
+ entry.Directory = cmSystemTools::GetFilenamePath(fullPath);
+ this->LibraryRuntimeInfo.push_back(entry);
+ }
+ else
+ {
+ // This can happen if the same library is linked multiple times.
+ // In that case the runtime information check need be done only
+ // once anyway. For shared libs we could add a check in AddItem
+ // to not repeat them.
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmComputeLinkInformation::CollectRuntimeDirectories()
+{
+ // Get all directories that should be in the runtime search path.
+
+ // Add directories containing libraries linked with full path.
+ for(std::vector<LibraryRuntimeEntry>::iterator
+ ei = this->LibraryRuntimeInfo.begin();
+ ei != this->LibraryRuntimeInfo.end(); ++ei)
+ {
+ ei->DirectoryIndex = this->AddRuntimeDirectory(ei->Directory);
+ }
+
+ // Add link directories specified for the target.
+ std::vector<std::string> const& dirs = this->GetDirectories();
+ for(std::vector<std::string>::const_iterator di = dirs.begin();
+ di != dirs.end(); ++di)
+ {
+ this->AddRuntimeDirectory(*di);
+ }
+}
+
+//----------------------------------------------------------------------------
+int cmComputeLinkInformation::AddRuntimeDirectory(std::string const& dir)
+{
+ // Add the runtime directory with a unique index.
+ std::map<cmStdString, int>::iterator i =
+ this->RuntimeDirectoryIndex.find(dir);
+ if(i == this->RuntimeDirectoryIndex.end())
+ {
+ std::map<cmStdString, int>::value_type
+ entry(dir, static_cast<int>(this->RuntimeDirectories.size()));
+ i = this->RuntimeDirectoryIndex.insert(entry).first;
+ this->RuntimeDirectories.push_back(dir);
+ }
+
+ return i->second;
+}
+
+//----------------------------------------------------------------------------
+struct cmCLIRuntimeConflictCompare
+{
+ typedef std::pair<int, int> RuntimeConflictPair;
+
+ // The conflict pair is unique based on just the directory
+ // (first). The second element is only used for displaying
+ // information about why the entry is present.
+ bool operator()(RuntimeConflictPair const& l,
+ RuntimeConflictPair const& r)
+ {
+ return l.first == r.first;
+ }
+};
+
+//----------------------------------------------------------------------------
+void cmComputeLinkInformation::FindConflictingLibraries()
+{
+ // Allocate the conflict graph.
+ this->RuntimeConflictGraph.resize(this->RuntimeDirectories.size());
+ this->RuntimeDirectoryVisited.resize(this->RuntimeDirectories.size(), 0);
+
+ // Find all runtime directories providing each library.
+ for(unsigned int lri = 0; lri < this->LibraryRuntimeInfo.size(); ++lri)
+ {
+ this->FindDirectoriesForLib(lri);
+ }
+
+ // Clean up the conflict graph representation.
+ for(std::vector<RuntimeConflictList>::iterator
+ i = this->RuntimeConflictGraph.begin();
+ i != this->RuntimeConflictGraph.end(); ++i)
+ {
+ // Sort the outgoing edges for each graph node so that the
+ // original order will be preserved as much as possible.
+ std::sort(i->begin(), i->end());
+
+ // Make the edge list unique so cycle detection will be reliable.
+ RuntimeConflictList::iterator last =
+ std::unique(i->begin(), i->end(), cmCLIRuntimeConflictCompare());
+ i->erase(last, i->end());
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmComputeLinkInformation::FindDirectoriesForLib(unsigned int lri)
+{
+ // Search through the runtime directories to find those providing
+ // this library.
+ LibraryRuntimeEntry& re = this->LibraryRuntimeInfo[lri];
+ for(unsigned int i = 0; i < this->RuntimeDirectories.size(); ++i)
+ {
+ // Skip the directory that is supposed to provide the library.
+ if(this->RuntimeDirectories[i] == re.Directory)
+ {
+ continue;
+ }
+
+ // Determine which type of check to do.
+ if(!re.SOName.empty())
+ {
+ // We have the library soname. Check if it will be found.
+ std::string file = this->RuntimeDirectories[i];
+ file += "/";
+ file += re.SOName;
+ std::set<cmStdString> const& files =
+ (this->GlobalGenerator
+ ->GetDirectoryContent(this->RuntimeDirectories[i], false));
+ if(files.find(re.SOName) != files.end() ||
+ cmSystemTools::FileExists(file.c_str(), true))
+ {
+ // The library will be found in this directory but this is not
+ // the directory named for it. Add an entry to make sure the
+ // desired directory comes before this one.
+ RuntimeConflictPair p(re.DirectoryIndex, lri);
+ this->RuntimeConflictGraph[i].push_back(p);
+ }
+ }
+ else
+ {
+ // We do not have the soname. Look for files in the directory
+ // that may conflict.
+ std::set<cmStdString> const& files =
+ (this->GlobalGenerator
+ ->GetDirectoryContent(this->RuntimeDirectories[i], true));
+
+ // Get the extension which should appear in the soname.
+ std::string ext =
+ cmSystemTools::GetFilenameLastExtension(re.FileName);
+
+ // Get the set of files that might conflict.
+ std::string base =
+ cmSystemTools::GetFilenameWithoutLastExtension(re.FileName);
+ std::set<cmStdString>::const_iterator first = files.lower_bound(base);
+ ++base[base.size()-1];
+ std::set<cmStdString>::const_iterator last = files.upper_bound(base);
+ bool found = false;
+ for(std::set<cmStdString>::const_iterator fi = first;
+ !found && fi != last; ++fi)
+ {
+ // This file name starts with the name of the library file.
+ // If the name also contains the extension then this is
+ // possibly an soname of the library.
+ if(fi->find(ext, base.size()) != fi->npos)
+ {
+ found = true;
+ }
+ }
+
+ if(found)
+ {
+ // The library may be found in this directory but this is not
+ // the directory named for it. Add an entry to make sure the
+ // desired directory comes before this one.
+ RuntimeConflictPair p(re.DirectoryIndex, lri);
+ this->RuntimeConflictGraph[i].push_back(p);
+ }
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmComputeLinkInformation::OrderRuntimeSearchPath()
+{
+ // Allow a cycle to be diagnosed once.
+ this->CycleDiagnosed = false;
+
+ // Iterate through the directories in the original order.
+ for(unsigned int i=0; i < this->RuntimeDirectories.size(); ++i)
+ {
+ this->VisitRuntimeDirectory(i, true);
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmComputeLinkInformation::VisitRuntimeDirectory(unsigned int i,
+ bool top)
+{
+ // Skip nodes already visited.
+ if(this->RuntimeDirectoryVisited[i])
+ {
+ if(!top)
+ {
+ // We have reached a previously visited node but were not called
+ // to start a new section of the graph. There is a cycle.
+ this->DiagnoseCycle();
+ }
+ return;
+ }
+
+ // We are not visiting this node so mark it.
+ this->RuntimeDirectoryVisited[i] = 1;
+
+ // Visit the neighbors of the node first.
+ RuntimeConflictList const& clist = this->RuntimeConflictGraph[i];
+ for(RuntimeConflictList::const_iterator j = clist.begin();
+ j != clist.end(); ++j)
+ {
+ this->VisitRuntimeDirectory(j->first, false);
+ }
+
+ // Now that all directories required to come before this one have
+ // been emmitted, emit this directory.
+ this->RuntimeSearchPath.push_back(this->RuntimeDirectories[i]);
+}
+
+//----------------------------------------------------------------------------
+void cmComputeLinkInformation::DiagnoseCycle()
+{
+ // Report the cycle at most once.
+ if(this->CycleDiagnosed)
+ {
+ return;
+ }
+ this->CycleDiagnosed = true;
+
+ // Construct the message.
+ cmOStringStream e;
+ e << "WARNING: Cannot generate a safe runtime path for target "
+ << this->Target->GetName()
+ << " because there is a cycle in the constraint graph:\n";
+
+ // Clean up the conflict graph representation.
+ for(unsigned int i=0; i < this->RuntimeConflictGraph.size(); ++i)
+ {
+ RuntimeConflictList const& clist = this->RuntimeConflictGraph[i];
+ e << "dir " << i << " is [" << this->RuntimeDirectories[i] << "]\n";
+ for(RuntimeConflictList::const_iterator j = clist.begin();
+ j != clist.end(); ++j)
+ {
+ e << " dir " << j->first << " must precede it due to [";
+ LibraryRuntimeEntry const& re = this->LibraryRuntimeInfo[j->second];
+ if(re.SOName.empty())
+ {
+ e << re.FileName;
+ }
+ else
+ {
+ e << re.SOName;
+ }
+ e << "]\n";
+ }
+ }
+ cmSystemTools::Message(e.str().c_str());
+}
diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h
new file mode 100644
index 0000000..d8a1374
--- /dev/null
+++ b/Source/cmComputeLinkInformation.h
@@ -0,0 +1,165 @@
+/*=========================================================================
+
+ Program: CMake - Cross-Platform Makefile Generator
+ Module: $RCSfile$
+ Language: C++
+ Date: $Date$
+ Version: $Revision$
+
+ Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
+ See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE. See the above copyright notices for more information.
+
+=========================================================================*/
+#ifndef cmComputeLinkInformation_h
+#define cmComputeLinkInformation_h
+
+#include "cmStandardIncludes.h"
+
+#include <cmsys/RegularExpression.hxx>
+
+class cmGlobalGenerator;
+class cmLocalGenerator;
+class cmMakefile;
+class cmTarget;
+
+/** \class cmComputeLinkInformation
+ * \brief Compute link information for a target in one configuration.
+ */
+class cmComputeLinkInformation
+{
+public:
+ cmComputeLinkInformation(cmTarget* target, const char* config);
+ bool Compute();
+
+ struct Item
+ {
+ Item(): Value(), IsPath(true) {}
+ Item(Item const& item): Value(item.Value), IsPath(item.IsPath) {}
+ Item(std::string const& v, bool p): Value(v), IsPath(p) {}
+ std::string Value;
+ bool IsPath;
+ };
+ typedef std::vector<Item> ItemVector;
+ ItemVector const& GetItems();
+ std::vector<std::string> const& GetDirectories();
+ std::vector<std::string> const& GetDepends();
+ std::vector<std::string> const& GetFrameworkPaths();
+ const char* GetLinkLanguage() const { return this->LinkLanguage; }
+ std::vector<std::string> const& GetRuntimeSearchPath();
+private:
+ void AddItem(std::string const& item);
+
+ // Output information.
+ ItemVector Items;
+ std::vector<std::string> Directories;
+ std::vector<std::string> Depends;
+ std::vector<std::string> FrameworkPaths;
+ std::vector<std::string> RuntimeSearchPath;
+
+ // Context information.
+ cmTarget* Target;
+ cmMakefile* Makefile;
+ cmLocalGenerator* LocalGenerator;
+ cmGlobalGenerator* GlobalGenerator;
+
+ // Configuration information.
+ const char* Config;
+ const char* LinkLanguage;
+
+ // System info.
+ bool UseImportLibrary;
+ const char* LoaderFlag;
+ std::string LibLinkFlag;
+ std::string LibLinkSuffix;
+
+ // Link type adjustment.
+ void ComputeLinkTypeInfo();
+ enum LinkType { LinkUnknown, LinkStatic, LinkShared };
+ LinkType StartLinkType;
+ LinkType CurrentLinkType;
+ std::string StaticLinkTypeFlag;
+ std::string SharedLinkTypeFlag;
+ bool LinkTypeEnabled;
+ void SetCurrentLinkType(LinkType lt);
+
+ // Link item parsing.
+ void ComputeItemParserInfo();
+ std::vector<std::string> StaticLinkExtensions;
+ std::vector<std::string> SharedLinkExtensions;
+ std::vector<std::string> LinkExtensions;
+ std::set<cmStdString> LinkPrefixes;
+ cmsys::RegularExpression RemoveLibraryExtension;
+ cmsys::RegularExpression ExtractStaticLibraryName;
+ cmsys::RegularExpression ExtractSharedLibraryName;
+ cmsys::RegularExpression ExtractAnyLibraryName;
+ void AddLinkPrefix(const char* p);
+ void AddLinkExtension(const char* e, LinkType type);
+ std::string CreateExtensionRegex(std::vector<std::string> const& exts);
+ std::string NoCaseExpression(const char* str);
+
+ // Handling of link items that are not targets or full file paths.
+ void AddUserItem(std::string const& item);
+ void AddDirectoryItem(std::string const& item);
+ void AddFrameworkItem(std::string const& item);
+ void DropDirectoryItem(std::string const& item);
+
+ // Framework info.
+ void ComputeFrameworkInfo();
+ void AddFrameworkPath(std::string const& p);
+ std::set<cmStdString> FrameworkPathsEmmitted;
+ cmsys::RegularExpression SplitFramework;
+
+ // Linker search path computation.
+ void ComputeLinkerSearchDirectories();
+ void AddLinkerSearchDirectories(std::vector<std::string> const& dirs);
+ std::set<cmStdString> DirectoriesEmmitted;
+
+ // Runtime path computation.
+ struct LibraryRuntimeEntry
+ {
+ // The file name of the library.
+ std::string FileName;
+
+ // The soname of the shared library if it is known.
+ std::string SOName;
+
+ // The directory in which the library is supposed to be found.
+ std::string Directory;
+
+ // The index assigned to the directory.
+ int DirectoryIndex;
+ };
+ bool RuntimeSearchPathComputed;
+ std::vector<LibraryRuntimeEntry> LibraryRuntimeInfo;
+ std::set<cmStdString> LibraryRuntimeInfoEmmitted;
+ std::vector<std::string> RuntimeDirectories;
+ std::map<cmStdString, int> RuntimeDirectoryIndex;
+ std::vector<char> RuntimeDirectoryVisited;
+ void AddLibraryRuntimeInfo(std::string const& fullPath, cmTarget* target);
+ void AddLibraryRuntimeInfo(std::string const& fullPath,
+ const char* soname = 0);
+ void CollectRuntimeDirectories();
+ int AddRuntimeDirectory(std::string const& dir);
+ void FindConflictingLibraries();
+ void FindDirectoriesForLib(unsigned int lri);
+ void OrderRuntimeSearchPath();
+ void VisitRuntimeDirectory(unsigned int i, bool top);
+ void DiagnoseCycle();
+ bool CycleDiagnosed;
+
+ // Adjacency-list representation of runtime path ordering graph.
+ // This maps from directory to those that must come *before* it.
+ // Each entry that must come before is a pair. The first element is
+ // the index of the directory that must come first. The second
+ // element is the index of the runtime library that added the
+ // constraint.
+ typedef std::pair<int, int> RuntimeConflictPair;
+ struct RuntimeConflictList: public std::vector<RuntimeConflictPair> {};
+ std::vector<RuntimeConflictList> RuntimeConflictGraph;
+};
+
+#endif
diff --git a/Source/cmDocumentVariables.cxx b/Source/cmDocumentVariables.cxx
index 9fd48d9..d744145 100644
--- a/Source/cmDocumentVariables.cxx
+++ b/Source/cmDocumentVariables.cxx
@@ -1035,6 +1035,12 @@ void cmDocumentVariables::DefineVariables(cmake* cm)
cmProperty::VARIABLE,0,0);
cm->DefineProperty("CMAKE_SHARED_LIBRARY_RUNTIME_<LANG>_FLAG_SEP",
cmProperty::VARIABLE,0,0);
+ cm->DefineProperty("CMAKE_EXECUTABLE_RUNTIME_<LANG>_FLAG",
+ cmProperty::VARIABLE,0,0);
+ cm->DefineProperty("CMAKE_EXECUTABLE_RUNTIME_<LANG>_FLAG_SEP",
+ cmProperty::VARIABLE,0,0);
+ cm->DefineProperty("CMAKE_PLATFORM_REQUIRED_RUNTIME_PATH",
+ cmProperty::VARIABLE,0,0);
cm->DefineProperty("CMAKE_SHARED_MODULE_CREATE_<LANG>_FLAGS",
cmProperty::VARIABLE,0,0);
cm->DefineProperty("CMAKE_SHARED_MODULE_<LANG>_FLAGS",
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index 8f8325e..448d457 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -27,6 +27,8 @@
#include "cmVersion.h"
#include "cmInstallExportGenerator.h"
+#include <cmsys/Directory.hxx>
+
#include <stdlib.h> // required for atof
#include <assert.h>
@@ -784,7 +786,7 @@ void cmGlobalGenerator::Generate()
// Compute the manifest of main targets generated.
for (i = 0; i < this->LocalGenerators.size(); ++i)
{
- this->LocalGenerators[i]->GenerateTargetManifest(this->TargetManifest);
+ this->LocalGenerators[i]->GenerateTargetManifest();
}
// Create a map from local generator to the complete set of targets
@@ -1880,3 +1882,42 @@ cmGlobalGenerator
this->FilesReplacedDuringGenerate.end(),
std::back_inserter(filenames));
}
+
+//----------------------------------------------------------------------------
+void cmGlobalGenerator::AddToManifest(const char* config,
+ std::string const& f)
+{
+ // Add to the main manifest for this configuration.
+ this->TargetManifest[config].insert(f);
+
+ // Add to the content listing for the file's directory.
+ std::string dir = cmSystemTools::GetFilenamePath(f);
+ std::string file = cmSystemTools::GetFilenameName(f);
+ this->DirectoryContentMap[dir].insert(file);
+}
+
+//----------------------------------------------------------------------------
+std::set<cmStdString> const&
+cmGlobalGenerator::GetDirectoryContent(std::string const& dir, bool needDisk)
+{
+ DirectoryContent& dc = this->DirectoryContentMap[dir];
+ if(needDisk && !dc.LoadedFromDisk)
+ {
+ // Load the directory content from disk.
+ cmsys::Directory d;
+ if(d.Load(dir.c_str()))
+ {
+ unsigned long n = d.GetNumberOfFiles();
+ for(unsigned long i = 0; i < n; ++i)
+ {
+ const char* f = d.GetFile(i);
+ if(strcmp(f, ".") != 0 && strcmp(f, "..") != 0)
+ {
+ dc.insert(f);
+ }
+ }
+ }
+ dc.LoadedFromDisk = true;
+ }
+ return dc;
+}
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index edb2019..dfbf1ad 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -150,6 +150,9 @@ public:
///! Get the export target set with the given name
const std::vector<cmTargetExport*>* GetExportSet(const char* name) const;
+ /** Add a file to the manifest of generated targets for a configuration. */
+ void AddToManifest(const char* config, std::string const& f);
+
void EnableInstallTarget();
int TryCompileTimeout;
@@ -209,6 +212,13 @@ public:
configuration. This is valid during generation only. */
cmTargetManifest const& GetTargetManifest() { return this->TargetManifest; }
+ /** Get the content of a directory on disk including the target
+ files to be generated. This may be called only during the
+ generation step. It is intended for use only by
+ cmComputeLinkInformation. */
+ std::set<cmStdString> const& GetDirectoryContent(std::string const& dir,
+ bool needDisk);
+
void AddTarget(cmTargets::value_type &v);
virtual const char* GetAllTargetName() { return "ALL_BUILD"; }
@@ -304,6 +314,17 @@ private:
std::vector<cmTarget const*>& steps);
typedef std::map<cmTarget const*, TargetDependSet> TargetDependMap;
TargetDependMap TargetDependencies;
+
+ // Cache directory content and target files to be built.
+ struct DirectoryContent: public std::set<cmStdString>
+ {
+ typedef std::set<cmStdString> derived;
+ bool LoadedFromDisk;
+ DirectoryContent(): LoadedFromDisk(false) {}
+ DirectoryContent(DirectoryContent const& dc):
+ derived(dc), LoadedFromDisk(dc.LoadedFromDisk) {}
+ };
+ std::map<cmStdString, DirectoryContent> DirectoryContentMap;
};
#endif
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index 89c9377..cc7e7f8 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -22,6 +22,7 @@ PURPOSE. See the above copyright notices for more information.
#include "cmXCode21Object.h"
#include "cmake.h"
#include "cmGeneratedFileStream.h"
+#include "cmComputeLinkInformation.h"
#include "cmSourceFile.h"
//----------------------------------------------------------------------------
@@ -2107,23 +2108,27 @@ void cmGlobalXCodeGenerator
}
// Compute the link library and directory information.
- std::vector<cmStdString> libNames;
- std::vector<cmStdString> libDirs;
- std::vector<cmStdString> fullPathLibs;
- this->CurrentLocalGenerator->ComputeLinkInformation(*cmtarget, configName,
- libNames, libDirs,
- &fullPathLibs);
+ cmComputeLinkInformation cli(cmtarget, configName);
+ if(!cli.Compute())
+ {
+ continue;
+ }
// Add dependencies directly on library files.
- for(std::vector<cmStdString>::iterator j = fullPathLibs.begin();
- j != fullPathLibs.end(); ++j)
+ {
+ std::vector<std::string> const& libDeps = cli.GetDepends();
+ for(std::vector<std::string>::const_iterator j = libDeps.begin();
+ j != libDeps.end(); ++j)
{
target->AddDependLibrary(configName, j->c_str());
}
+ }
- std::string linkDirs;
// add the library search paths
- for(std::vector<cmStdString>::const_iterator libDir = libDirs.begin();
+ {
+ std::vector<std::string> const& libDirs = cli.GetDirectories();
+ std::string linkDirs;
+ for(std::vector<std::string>::const_iterator libDir = libDirs.begin();
libDir != libDirs.end(); ++libDir)
{
if(libDir->size() && *libDir != "/usr/lib")
@@ -2141,45 +2146,50 @@ void cmGlobalXCodeGenerator
}
this->AppendBuildSettingAttribute(target, "LIBRARY_SEARCH_PATHS",
linkDirs.c_str(), configName);
+ }
+
+ // add the framework search paths
+ {
+ const char* sep = "";
+ std::string fdirs;
+ std::vector<std::string> const& fwDirs = cli.GetFrameworkPaths();
+ for(std::vector<std::string>::const_iterator fdi = fwDirs.begin();
+ fdi != fwDirs.end(); ++fdi)
+ {
+ fdirs += sep;
+ sep = " ";
+ fdirs += this->XCodeEscapePath(fdi->c_str());
+ }
+ if(!fdirs.empty())
+ {
+ this->AppendBuildSettingAttribute(target, "FRAMEWORK_SEARCH_PATHS",
+ fdirs.c_str(), configName);
+ }
+ }
+
// now add the link libraries
if(cmtarget->GetType() != cmTarget::STATIC_LIBRARY)
{
- std::string fdirs;
- std::set<cmStdString> emitted;
- emitted.insert("/System/Library/Frameworks");
- for(std::vector<cmStdString>::iterator lib = libNames.begin();
- lib != libNames.end(); ++lib)
+ std::string linkLibs;
+ const char* sep = "";
+ typedef cmComputeLinkInformation::ItemVector ItemVector;
+ ItemVector const& libNames = cli.GetItems();
+ for(ItemVector::const_iterator li = libNames.begin();
+ li != libNames.end(); ++li)
{
- std::string& libString = *lib;
- // check to see if this is a -F framework path and extract it if it is
- // -F framework stuff should be in the FRAMEWORK_SEARCH_PATHS and not
- // OTHER_LDFLAGS
- if(libString.size() > 2 && libString[0] == '-'
- && libString[1] == 'F')
+ linkLibs += sep;
+ sep = " ";
+ if(li->IsPath)
{
- std::string path = libString.substr(2);
- // remove escaped spaces from the path
- cmSystemTools::ReplaceString(path, "\\ ", " ");
- if(emitted.insert(path).second)
- {
- if(fdirs.size())
- {
- fdirs += " ";
- }
- fdirs += this->XCodeEscapePath(path.c_str());
- }
+ linkLibs += this->XCodeEscapePath(li->Value.c_str());
}
else
{
- this->AppendBuildSettingAttribute(target, "OTHER_LDFLAGS",
- lib->c_str(), configName);
+ linkLibs += li->Value;
}
}
- if(fdirs.size())
- {
- this->AppendBuildSettingAttribute(target, "FRAMEWORK_SEARCH_PATHS",
- fdirs.c_str(), configName);
- }
+ this->AppendBuildSettingAttribute(target, "OTHER_LDFLAGS",
+ linkLibs.c_str(), configName);
}
}
}
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index c2b14b2..60a6b72 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -16,6 +16,7 @@
=========================================================================*/
#include "cmLocalGenerator.h"
+#include "cmComputeLinkInformation.h"
#include "cmGeneratedFileStream.h"
#include "cmGlobalGenerator.h"
#include "cmInstallGenerator.h"
@@ -23,7 +24,6 @@
#include "cmInstallScriptGenerator.h"
#include "cmInstallTargetGenerator.h"
#include "cmMakefile.h"
-#include "cmOrderLinkDirectories.h"
#include "cmSourceFile.h"
#include "cmTest.h"
#include "cmake.h"
@@ -477,7 +477,7 @@ void cmLocalGenerator::GenerateInstallRules()
}
//----------------------------------------------------------------------------
-void cmLocalGenerator::GenerateTargetManifest(cmTargetManifest& manifest)
+void cmLocalGenerator::GenerateTargetManifest()
{
// Collect the set of configuration types.
std::vector<std::string> configNames;
@@ -500,34 +500,17 @@ void cmLocalGenerator::GenerateTargetManifest(cmTargetManifest& manifest)
for(cmTargets::iterator t = targets.begin(); t != targets.end(); ++t)
{
cmTarget& target = t->second;
- cmTarget::TargetType type = target.GetType();
- if(type == cmTarget::STATIC_LIBRARY ||
- type == cmTarget::SHARED_LIBRARY ||
- type == cmTarget::MODULE_LIBRARY ||
- type == cmTarget::EXECUTABLE)
+ if(configNames.empty())
{
- if(configNames.empty())
+ target.GenerateTargetManifest(0);
+ }
+ else
+ {
+ for(std::vector<std::string>::iterator ci = configNames.begin();
+ ci != configNames.end(); ++ci)
{
- manifest[""].insert(target.GetFullPath(0, false));
- if(type == cmTarget::SHARED_LIBRARY &&
- this->Makefile->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX"))
- {
- manifest[""].insert(target.GetFullPath(0, true));
- }
- }
- else
- {
- for(std::vector<std::string>::iterator ci = configNames.begin();
- ci != configNames.end(); ++ci)
- {
- const char* config = ci->c_str();
- manifest[config].insert(target.GetFullPath(config, false));
- if(type == cmTarget::SHARED_LIBRARY &&
- this->Makefile->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX"))
- {
- manifest[config].insert(target.GetFullPath(config, true));
- }
- }
+ const char* config = ci->c_str();
+ target.GenerateTargetManifest(config);
}
}
}
@@ -1478,50 +1461,53 @@ bool cmLocalGenerator::GetLinkerArgs(std::string& rpath,
// collect all the flags needed for linking libraries
linkLibs = "";
- // Try to emit each search path once
- std::set<cmStdString> emitted;
+ const char* config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE");
+
+ cmComputeLinkInformation cli(&tgt, config);
+ if(!cli.Compute())
+ {
+ return false;
+ }
+
+ const char* linkLanguage = cli.GetLinkLanguage();
+
// Embed runtime search paths if possible and if required.
- bool outputRuntime = true;
+ bool outputRuntime = !this->Makefile->IsOn("CMAKE_SKIP_RPATH");
+
+ // Lookup rpath specification flags.
std::string runtimeFlag;
std::string runtimeSep;
-
- const char* config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE");
- const char* linkLanguage =
- tgt.GetLinkerLanguage(this->GetGlobalGenerator());
- if(!linkLanguage)
+ if(tgt.GetType() != cmTarget::STATIC_LIBRARY)
{
- cmSystemTools::
- Error("CMake can not determine linker language for target:",
- tgt.GetName());
- return false;
+ std::string runTimeFlagVar = "CMAKE_";
+ if(tgt.GetType() == cmTarget::EXECUTABLE)
+ {
+ runTimeFlagVar += "EXECUTABLE";
+ }
+ else
+ {
+ runTimeFlagVar += "SHARED_LIBRARY";
+ }
+ runTimeFlagVar += "_RUNTIME_";
+ runTimeFlagVar += linkLanguage;
+ runTimeFlagVar += "_FLAG";
+ std::string runTimeFlagSepVar = runTimeFlagVar + "_SEP";
+ runtimeFlag = this->Makefile->GetSafeDefinition(runTimeFlagVar.c_str());
+ runtimeSep = this->Makefile->GetSafeDefinition(runTimeFlagSepVar.c_str());
}
- std::string runTimeFlagVar = "CMAKE_SHARED_LIBRARY_RUNTIME_";
- runTimeFlagVar += linkLanguage;
- runTimeFlagVar += "_FLAG";
- std::string runTimeFlagSepVar = runTimeFlagVar + "_SEP";
- runtimeFlag = this->Makefile->GetSafeDefinition(runTimeFlagVar.c_str());
- runtimeSep = this->Makefile->GetSafeDefinition(runTimeFlagSepVar.c_str());
-
// concatenate all paths or no?
- bool runtimeConcatenate = ( runtimeSep!="" );
- if(runtimeFlag == "" || this->Makefile->IsOn("CMAKE_SKIP_RPATH"))
+ bool runtimeConcatenate = !runtimeSep.empty();
+
+ const char* runtimeAlways =
+ this->Makefile->GetDefinition("CMAKE_PLATFORM_REQUIRED_RUNTIME_PATH");
+
+ // Turn off rpath support if no flag is available to specify it.
+ if(runtimeFlag.empty())
{
outputRuntime = false;
+ runtimeAlways = 0;
}
- // Some search paths should never be emitted
- emitted.insert("");
- if(const char* implicitLinks =
- (this->Makefile->GetDefinition
- ("CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES")))
- {
- std::vector<std::string> implicitLinkVec;
- cmSystemTools::ExpandListArgument(implicitLinks, implicitLinkVec);
- for(unsigned int k = 0; k < implicitLinkVec.size(); ++k)
- {
- emitted.insert(implicitLinkVec[k]);
- }
- }
std::string libPathFlag =
this->Makefile->GetRequiredDefinition("CMAKE_LIBRARY_PATH_FLAG");
std::string libPathTerminator =
@@ -1539,10 +1525,43 @@ bool cmLocalGenerator::GetLinkerArgs(std::string& rpath,
linkLibs += " ";
}
- // Compute the link library and directory information.
- std::vector<cmStdString> libNames;
- std::vector<cmStdString> libDirs;
- this->ComputeLinkInformation(tgt, config, libNames, libDirs);
+ // Append the framework search path flags.
+ std::vector<std::string> const& fwDirs = cli.GetFrameworkPaths();
+ for(std::vector<std::string>::const_iterator fdi = fwDirs.begin();
+ fdi != fwDirs.end(); ++fdi)
+ {
+ linkLibs += "-F";
+ linkLibs += this->Convert(fdi->c_str(), NONE, SHELL, false);
+ linkLibs += " ";
+ }
+
+ // Append the library search path flags.
+ std::vector<std::string> const& libDirs = cli.GetDirectories();
+ for(std::vector<std::string>::const_iterator libDir = libDirs.begin();
+ libDir != libDirs.end(); ++libDir)
+ {
+ std::string libpath = this->ConvertToOutputForExisting(libDir->c_str());
+ linkLibs += libPathFlag;
+ linkLibs += libpath;
+ linkLibs += libPathTerminator;
+ linkLibs += " ";
+ }
+
+ // Append the link items.
+ typedef cmComputeLinkInformation::ItemVector ItemVector;
+ ItemVector const& items = cli.GetItems();
+ for(ItemVector::const_iterator li = items.begin(); li != items.end(); ++li)
+ {
+ if(li->IsPath)
+ {
+ linkLibs += this->Convert(li->Value.c_str(), START_OUTPUT, SHELL);
+ }
+ else
+ {
+ linkLibs += li->Value;
+ }
+ linkLibs += " ";
+ }
// Select whether to generate an rpath for the install tree or the
// build tree.
@@ -1562,68 +1581,46 @@ bool cmLocalGenerator::GetLinkerArgs(std::string& rpath,
{
const char* install_rpath = tgt.GetProperty("INSTALL_RPATH");
cmSystemTools::ExpandListArgument(install_rpath, runtimeDirs);
- for(unsigned int i=0; i < runtimeDirs.size(); ++i)
- {
- runtimeDirs[i] =
- this->Convert(runtimeDirs[i].c_str(), FULL, SHELL, false);
- }
}
-
- // Append the library search path flags.
- for(std::vector<cmStdString>::const_iterator libDir = libDirs.begin();
- libDir != libDirs.end(); ++libDir)
+ if(use_build_rpath || use_link_rpath)
{
- std::string libpath = this->ConvertToOutputForExisting(libDir->c_str());
- if(emitted.insert(libpath).second)
+ std::vector<std::string> const& rdirs = cli.GetRuntimeSearchPath();
+ for(std::vector<std::string>::const_iterator ri = rdirs.begin();
+ ri != rdirs.end(); ++ri)
{
- std::string fullLibPath;
- if(!this->WindowsShell && this->UseRelativePaths)
+ // Put this directory in the rpath if using build-tree rpath
+ // support or if using the link path as an rpath.
+ if(use_build_rpath)
{
- fullLibPath = "\"`cd ";
+ runtimeDirs.push_back(*ri);
}
- fullLibPath += libpath;
- if(!this->WindowsShell && this->UseRelativePaths)
+ else if(use_link_rpath)
{
- fullLibPath += ";pwd`\"";
- }
- std::string::size_type pos = libDir->find(libPathFlag.c_str());
- if((pos == std::string::npos || pos > 0)
- && libDir->find("${") == std::string::npos)
- {
- linkLibs += libPathFlag;
- linkLibs += fullLibPath;
- linkLibs += libPathTerminator;
- linkLibs += " ";
-
- // Put this directory in the rpath if using build-tree rpath
- // support or if using the link path as an rpath.
- if(use_build_rpath)
- {
- runtimeDirs.push_back(fullLibPath);
- }
- else if(use_link_rpath)
+ // Do not add any path inside the source or build tree.
+ const char* topSourceDir = this->Makefile->GetHomeDirectory();
+ const char* topBinaryDir = this->Makefile->GetHomeOutputDirectory();
+ if(!cmSystemTools::ComparePath(ri->c_str(), topSourceDir) &&
+ !cmSystemTools::ComparePath(ri->c_str(), topBinaryDir) &&
+ !cmSystemTools::IsSubDirectory(ri->c_str(), topSourceDir) &&
+ !cmSystemTools::IsSubDirectory(ri->c_str(), topBinaryDir))
{
- // Do not add any path inside the source or build tree.
- const char* topSourceDir = this->Makefile->GetHomeDirectory();
- const char* topBinaryDir = this->Makefile->GetHomeOutputDirectory();
- if(!cmSystemTools::ComparePath(libDir->c_str(), topSourceDir) &&
- !cmSystemTools::ComparePath(libDir->c_str(), topBinaryDir) &&
- !cmSystemTools::IsSubDirectory(libDir->c_str(), topSourceDir) &&
- !cmSystemTools::IsSubDirectory(libDir->c_str(), topBinaryDir))
- {
- runtimeDirs.push_back(fullLibPath);
- }
+ runtimeDirs.push_back(*ri);
}
}
}
}
+ if(runtimeAlways)
+ {
+ // Add runtime paths required by the platform to always be
+ // present. This is done even when skipping rpath support.
+ cmSystemTools::ExpandListArgument(runtimeAlways, runtimeDirs);
+ }
- // Append the link libraries.
- for(std::vector<cmStdString>::iterator lib = libNames.begin();
- lib != libNames.end(); ++lib)
+ // Convert the runtime directory names for use in the build file.
+ for(std::vector<std::string>::iterator ri = runtimeDirs.begin();
+ ri != runtimeDirs.end(); ++ri)
{
- linkLibs += *lib;
- linkLibs += " ";
+ *ri = this->Convert(ri->c_str(), FULL, SHELL, false);
}
if(!runtimeDirs.empty())
@@ -1715,257 +1712,6 @@ void cmLocalGenerator::OutputLinkLibraries(std::ostream& fout,
}
//----------------------------------------------------------------------------
-void cmLocalGenerator
-::ComputeLinkInformation(cmTarget& target,
- const char* config,
- std::vector<cmStdString>& outLibs,
- std::vector<cmStdString>& outDirs,
- std::vector<cmStdString>* fullPathLibs)
-{
- // Compute which library configuration to link.
- cmTarget::LinkLibraryType linkType = cmTarget::OPTIMIZED;
- if(config && cmSystemTools::UpperCase(config) == "DEBUG")
- {
- linkType = cmTarget::DEBUG;
- }
-
- // Get the language used for linking.
- const char* linkLanguage =
- target.GetLinkerLanguage(this->GetGlobalGenerator());
-
- // Check whether we should use an import library for linking a target.
- bool implib =
- this->Makefile->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")?true:false;
-
- // On platforms without import libraries there may be a special flag
- // to use when creating a plugin (module) that obtains symbols from
- // the program that will load it.
- const char* loader_flag = 0;
- if(!implib && target.GetType() == cmTarget::MODULE_LIBRARY)
- {
- if(!linkLanguage)
- {
- cmSystemTools::
- Error("CMake can not determine linker language for target:",
- target.GetName());
- return;
- }
- std::string loader_flag_var = "CMAKE_SHARED_MODULE_LOADER_";
- loader_flag_var += linkLanguage;
- loader_flag_var += "_FLAG";
- loader_flag = this->Makefile->GetDefinition(loader_flag_var.c_str());
- }
-
- // Get the list of libraries against which this target wants to link.
- std::vector<std::string> linkLibraries;
- const cmTarget::LinkLibraryVectorType& inLibs = target.GetLinkLibraries();
- for(cmTarget::LinkLibraryVectorType::const_iterator j = inLibs.begin();
- j != inLibs.end(); ++j)
- {
- // For backwards compatibility variables may have been expanded
- // inside library names. Clean up the resulting name.
- std::string lib = j->first;
- std::string::size_type pos = lib.find_first_not_of(" \t\r\n");
- if(pos != lib.npos)
- {
- lib = lib.substr(pos, lib.npos);
- }
- pos = lib.find_last_not_of(" \t\r\n");
- if(pos != lib.npos)
- {
- lib = lib.substr(0, pos+1);
- }
- if(lib.empty())
- {
- continue;
- }
- // Link to a library if it is not the same target and is meant for
- // this configuration type.
- if((target.GetType() == cmTarget::EXECUTABLE ||
- lib != target.GetName()) &&
- (j->second == cmTarget::GENERAL || j->second == linkType))
- {
- // Compute the proper name to use to link this library.
- cmTarget* tgt = this->GlobalGenerator->FindTarget(0, lib.c_str(), false);
- bool impexe = (tgt &&
- tgt->GetType() == cmTarget::EXECUTABLE &&
- tgt->GetPropertyAsBool("ENABLE_EXPORTS"));
- if(impexe && !implib && !loader_flag)
- {
- // Skip linking to executables on platforms with no import
- // libraries or loader flags.
- continue;
- }
- else if(tgt && (tgt->GetType() == cmTarget::STATIC_LIBRARY ||
- tgt->GetType() == cmTarget::SHARED_LIBRARY ||
- tgt->GetType() == cmTarget::MODULE_LIBRARY ||
- impexe))
- {
- // This is a CMake target. Ask the target for its real name.
- std::string linkItem;
- if(impexe && loader_flag)
- {
- // This link item is an executable that may provide symbols
- // used by this target. A special flag is needed on this
- // platform. Add it now.
- std::string exe = tgt->GetFullPath(config, implib);
- linkItem += loader_flag;
- linkItem += this->Convert(exe.c_str(), NONE, SHELL, false);
- }
- else
- {
- // Pass the full path to the target file but purposely leave
- // off the per-configuration subdirectory. The link directory
- // ordering knows how to deal with this.
- linkItem += tgt->GetDirectory(0, implib);
- // on apple if the FRAMEWORK prop is set, then
- // do not add the target full name but just use the directory
- // name
-#ifdef __APPLE__
- if (!(tgt->GetType() == cmTarget::SHARED_LIBRARY &&
- tgt->GetPropertyAsBool("FRAMEWORK")))
-#endif
- {
- linkItem += "/";
- linkItem += tgt->GetFullName(config, implib);
- }
- }
- linkLibraries.push_back(linkItem);
- // For full path, use the true location.
- if(fullPathLibs)
- {
- fullPathLibs->push_back(tgt->GetFullPath(config, implib));
- }
- }
- else
- {
- // This is not a CMake target. Use the name given.
- linkLibraries.push_back(lib);
-
- // Add to the list of full paths if this library is one.
- if(fullPathLibs &&
- cmSystemTools::FileIsFullPath(lib.c_str()) &&
- !cmSystemTools::FileIsDirectory(lib.c_str()))
- {
- fullPathLibs->push_back(lib);
- }
- }
- }
- }
-
- // Get the list of directories the target wants to search for libraries.
- const std::vector<std::string>&
- linkDirectories = target.GetLinkDirectories();
-
- // Lookup link type selection flags.
- const char* static_link_type_flag = 0;
- const char* shared_link_type_flag = 0;
- const char* target_type_str = 0;
- switch(target.GetType())
- {
- case cmTarget::EXECUTABLE: target_type_str = "EXE"; break;
- case cmTarget::SHARED_LIBRARY: target_type_str = "SHARED_LIBRARY"; break;
- case cmTarget::MODULE_LIBRARY: target_type_str = "SHARED_MODULE"; break;
- default: break;
- }
- if(target_type_str)
- {
- if(!linkLanguage)
- {
- cmSystemTools::
- Error("CMake can not determine linker language for target:",
- target.GetName());
- return;
- }
- std::string static_link_type_flag_var = "CMAKE_";
- static_link_type_flag_var += target_type_str;
- static_link_type_flag_var += "_LINK_STATIC_";
- static_link_type_flag_var += linkLanguage;
- static_link_type_flag_var += "_FLAGS";
- static_link_type_flag =
- this->Makefile->GetDefinition(static_link_type_flag_var.c_str());
-
- std::string shared_link_type_flag_var = "CMAKE_";
- shared_link_type_flag_var += target_type_str;
- shared_link_type_flag_var += "_LINK_DYNAMIC_";
- shared_link_type_flag_var += linkLanguage;
- shared_link_type_flag_var += "_FLAGS";
- shared_link_type_flag =
- this->Makefile->GetDefinition(shared_link_type_flag_var.c_str());
- }
-
- // Compute the link directory order needed to link the libraries.
- cmOrderLinkDirectories orderLibs;
- orderLibs.SetLinkTypeInformation(cmOrderLinkDirectories::LinkShared,
- static_link_type_flag,
- shared_link_type_flag);
- orderLibs.AddLinkPrefix(
- this->Makefile->GetDefinition("CMAKE_STATIC_LIBRARY_PREFIX"));
- orderLibs.AddLinkPrefix(
- this->Makefile->GetDefinition("CMAKE_SHARED_LIBRARY_PREFIX"));
-
- // Import library names should be matched and treated as shared
- // libraries for the purposes of linking.
- orderLibs.AddLinkExtension(
- this->Makefile->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX"),
- cmOrderLinkDirectories::LinkShared);
- orderLibs.AddLinkExtension(
- this->Makefile->GetDefinition("CMAKE_STATIC_LIBRARY_SUFFIX"),
- cmOrderLinkDirectories::LinkStatic);
- orderLibs.AddLinkExtension(
- this->Makefile->GetDefinition("CMAKE_SHARED_LIBRARY_SUFFIX"),
- cmOrderLinkDirectories::LinkShared);
- orderLibs.AddLinkExtension(
- this->Makefile->GetDefinition("CMAKE_LINK_LIBRARY_SUFFIX"));
- if(const char* linkSuffixes =
- this->Makefile->GetDefinition("CMAKE_EXTRA_LINK_EXTENSIONS"))
- {
- std::vector<std::string> linkSuffixVec;
- cmSystemTools::ExpandListArgument(linkSuffixes, linkSuffixVec);
- for(std::vector<std::string>::iterator i = linkSuffixVec.begin();
- i != linkSuffixVec.end(); ++i)
- {
- orderLibs.AddLinkExtension(i->c_str());
- }
- }
- std::string configSubdir;
- cmGlobalGenerator* gg = this->GetGlobalGenerator();
- gg->AppendDirectoryForConfig("", config, "", configSubdir);
- orderLibs.SetLinkInformation(target.GetName(),
- linkLibraries,
- linkDirectories,
- gg->GetTargetManifest(),
- configSubdir.c_str());
- orderLibs.DetermineLibraryPathOrder();
- std::vector<cmStdString> orderedLibs;
- orderLibs.GetLinkerInformation(outDirs, orderedLibs);
-
- // Make sure libraries are linked with the proper syntax.
- std::string libLinkFlag =
- this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_FLAG");
- std::string libLinkSuffix =
- this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_SUFFIX");
- for(std::vector<cmStdString>::iterator l = orderedLibs.begin();
- l != orderedLibs.end(); ++l)
- {
- std::string lib = *l;
- if(lib[0] == '-' || lib[0] == '$' || lib[0] == '`')
- {
- // The library is linked with special syntax by the user.
- outLibs.push_back(lib);
- }
- else
- {
- // Generate the proper link syntax.
- lib = libLinkFlag;
- lib += *l;
- lib += libLinkSuffix;
- outLibs.push_back(lib);
- }
- }
-}
-
-//----------------------------------------------------------------------------
void cmLocalGenerator::AddLanguageFlags(std::string& flags,
const char* lang,
const char* config)
diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h
index 25bedfc..9a9be8c 100644
--- a/Source/cmLocalGenerator.h
+++ b/Source/cmLocalGenerator.h
@@ -75,7 +75,7 @@ public:
/**
* Generate a manifest of target files that will be built.
*/
- virtual void GenerateTargetManifest(cmTargetManifest&);
+ virtual void GenerateTargetManifest();
///! Get the makefile for this generator
cmMakefile *GetMakefile() {
@@ -174,13 +174,6 @@ public:
bool /*color*/)
{ return true; }
- /** Compute the list of link libraries and directories for the given
- target and configuration. */
- void ComputeLinkInformation(cmTarget& target, const char* config,
- std::vector<cmStdString>& outLibs,
- std::vector<cmStdString>& outDirs,
- std::vector<cmStdString>* fullPathLibs=0);
-
/** Get the include flags for the current makefile and language. */
void GetIncludeDirectories(std::vector<std::string>& dirs,
bool filter_system_dirs = true);
diff --git a/Source/cmLocalVisualStudio6Generator.cxx b/Source/cmLocalVisualStudio6Generator.cxx
index 2cfcf70..b462cd3 100644
--- a/Source/cmLocalVisualStudio6Generator.cxx
+++ b/Source/cmLocalVisualStudio6Generator.cxx
@@ -22,6 +22,8 @@
#include "cmCacheManager.h"
#include "cmake.h"
+#include "cmComputeLinkInformation.h"
+
#include <cmsys/RegularExpression.hxx>
cmLocalVisualStudio6Generator::cmLocalVisualStudio6Generator()
@@ -1569,12 +1571,17 @@ void cmLocalVisualStudio6Generator
std::string& options)
{
// Compute the link information for this configuration.
- std::vector<cmStdString> linkLibs;
- std::vector<cmStdString> linkDirs;
- this->ComputeLinkInformation(target, configName, linkLibs, linkDirs);
+ cmComputeLinkInformation cli(&target, configName);
+ if(!cli.Compute())
+ {
+ return;
+ }
+ typedef cmComputeLinkInformation::ItemVector ItemVector;
+ ItemVector const& linkLibs = cli.GetItems();
+ std::vector<std::string> const& linkDirs = cli.GetDirectories();
// Build the link options code.
- for(std::vector<cmStdString>::const_iterator d = linkDirs.begin();
+ for(std::vector<std::string>::const_iterator d = linkDirs.begin();
d != linkDirs.end(); ++d)
{
std::string dir = *d;
@@ -1592,11 +1599,19 @@ void cmLocalVisualStudio6Generator
options += "\n";
}
}
- for(std::vector<cmStdString>::const_iterator l = linkLibs.begin();
+ for(ItemVector::const_iterator l = linkLibs.begin();
l != linkLibs.end(); ++l)
{
options += "# ADD LINK32 ";
- options += this->ConvertToOptionallyRelativeOutputPath(l->c_str());
+ if(l->IsPath)
+ {
+ options +=
+ this->ConvertToOptionallyRelativeOutputPath(l->Value.c_str());
+ }
+ else
+ {
+ options += l->Value;
+ }
options += "\n";
}
diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx
index f9ebb85..b368f7c 100644
--- a/Source/cmLocalVisualStudio7Generator.cxx
+++ b/Source/cmLocalVisualStudio7Generator.cxx
@@ -24,12 +24,24 @@
#include "cmCacheManager.h"
#include "cmake.h"
+#include "cmComputeLinkInformation.h"
#include "cmGeneratedFileStream.h"
#include <cmsys/System.h>
#include <ctype.h> // for isspace
+class cmLocalVisualStudio7GeneratorInternals
+{
+public:
+ cmLocalVisualStudio7GeneratorInternals(cmLocalVisualStudio7Generator* e):
+ LocalGenerator(e) {}
+ typedef cmComputeLinkInformation::ItemVector ItemVector;
+ void OutputLibraries(std::ostream& fout, ItemVector const& libs);
+private:
+ cmLocalVisualStudio7Generator* LocalGenerator;
+};
+
extern cmVS7FlagTable cmLocalVisualStudio7GeneratorFlagTable[];
//----------------------------------------------------------------------------
@@ -38,10 +50,12 @@ cmLocalVisualStudio7Generator::cmLocalVisualStudio7Generator()
this->Version = 7;
this->PlatformName = "Win32";
this->ExtraFlagTable = 0;
+ this->Internal = new cmLocalVisualStudio7GeneratorInternals(this);
}
cmLocalVisualStudio7Generator::~cmLocalVisualStudio7Generator()
{
+ delete this->Internal;
}
void cmLocalVisualStudio7Generator::AddHelperCommands()
@@ -748,20 +762,12 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
targetNameImport, targetNamePDB, configName);
// Compute the link library and directory information.
- std::vector<cmStdString> linkLibs;
- std::vector<cmStdString> linkDirs;
- this->ComputeLinkInformation(target, configName, linkLibs, linkDirs);
-
- // Get the language to use for linking.
- const char* linkLanguage =
- target.GetLinkerLanguage(this->GetGlobalGenerator());
- if(!linkLanguage)
+ cmComputeLinkInformation cli(&target, configName);
+ if(!cli.Compute())
{
- cmSystemTools::Error
- ("CMake can not determine linker language for target:",
- target.GetName());
return;
}
+ const char* linkLanguage = cli.GetLinkLanguage();
// Compute the variable name to lookup standard libraries for this
// language.
@@ -777,7 +783,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
fout << "\t\t\t\tAdditionalDependencies=\"$(NOINHERIT) "
<< this->Makefile->GetSafeDefinition(standardLibsVar.c_str())
<< " ";
- this->OutputLibraries(fout, linkLibs);
+ this->Internal->OutputLibraries(fout, cli.GetItems());
fout << "\"\n";
temp = target.GetDirectory(configName);
temp += "/";
@@ -787,7 +793,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
this->WriteTargetVersionAttribute(fout, target);
linkOptions.OutputFlagMap(fout, "\t\t\t\t");
fout << "\t\t\t\tAdditionalLibraryDirectories=\"";
- this->OutputLibraryDirectories(fout, linkDirs);
+ this->OutputLibraryDirectories(fout, cli.GetDirectories());
fout << "\"\n";
this->OutputModuleDefinitionFile(fout, target);
temp = target.GetDirectory(configName);
@@ -825,20 +831,12 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
targetNameImport, targetNamePDB, configName);
// Compute the link library and directory information.
- std::vector<cmStdString> linkLibs;
- std::vector<cmStdString> linkDirs;
- this->ComputeLinkInformation(target, configName, linkLibs, linkDirs);
-
- // Get the language to use for linking.
- const char* linkLanguage =
- target.GetLinkerLanguage(this->GetGlobalGenerator());
- if(!linkLanguage)
+ cmComputeLinkInformation cli(&target, configName);
+ if(!cli.Compute())
{
- cmSystemTools::Error
- ("CMake can not determine linker language for target:",
- target.GetName());
return;
}
+ const char* linkLanguage = cli.GetLinkLanguage();
// Compute the variable name to lookup standard libraries for this
// language.
@@ -854,7 +852,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
fout << "\t\t\t\tAdditionalDependencies=\"$(NOINHERIT) "
<< this->Makefile->GetSafeDefinition(standardLibsVar.c_str())
<< " ";
- this->OutputLibraries(fout, linkLibs);
+ this->Internal->OutputLibraries(fout, cli.GetItems());
fout << "\"\n";
temp = target.GetDirectory(configName);
temp += "/";
@@ -864,7 +862,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
this->WriteTargetVersionAttribute(fout, target);
linkOptions.OutputFlagMap(fout, "\t\t\t\t");
fout << "\t\t\t\tAdditionalLibraryDirectories=\"";
- this->OutputLibraryDirectories(fout, linkDirs);
+ this->OutputLibraryDirectories(fout, cli.GetDirectories());
fout << "\"\n";
fout << "\t\t\t\tProgramDataBaseFile=\""
<< target.GetDirectory(configName) << "/" << targetNamePDB
@@ -936,14 +934,23 @@ void cmLocalVisualStudio7Generator
//----------------------------------------------------------------------------
void
-cmLocalVisualStudio7Generator
-::OutputLibraries(std::ostream& fout,
- std::vector<cmStdString> const& libs)
+cmLocalVisualStudio7GeneratorInternals
+::OutputLibraries(std::ostream& fout, ItemVector const& libs)
{
- for(std::vector<cmStdString>::const_iterator l = libs.begin();
- l != libs.end(); ++l)
+ cmLocalVisualStudio7Generator* lg = this->LocalGenerator;
+ for(ItemVector::const_iterator l = libs.begin(); l != libs.end(); ++l)
{
- fout << this->ConvertToXMLOutputPath(l->c_str()) << " ";
+ if(l->IsPath)
+ {
+ std::string rel = lg->Convert(l->Value.c_str(),
+ cmLocalGenerator::START_OUTPUT,
+ cmLocalGenerator::UNCHANGED);
+ fout << lg->ConvertToXMLOutputPath(rel.c_str()) << " ";
+ }
+ else
+ {
+ fout << l->Value << " ";
+ }
}
}
@@ -951,10 +958,10 @@ cmLocalVisualStudio7Generator
void
cmLocalVisualStudio7Generator
::OutputLibraryDirectories(std::ostream& fout,
- std::vector<cmStdString> const& dirs)
+ std::vector<std::string> const& dirs)
{
const char* comma = "";
- for(std::vector<cmStdString>::const_iterator d = dirs.begin();
+ for(std::vector<std::string>::const_iterator d = dirs.begin();
d != dirs.end(); ++d)
{
// Remove any trailing slash and skip empty paths.
diff --git a/Source/cmLocalVisualStudio7Generator.h b/Source/cmLocalVisualStudio7Generator.h
index 3687289..34af7f5 100644
--- a/Source/cmLocalVisualStudio7Generator.h
+++ b/Source/cmLocalVisualStudio7Generator.h
@@ -27,6 +27,7 @@ struct cmVS7FlagTable;
class cmLocalVisualStudio7GeneratorOptions;
class cmLocalVisualStudio7GeneratorFCInfo;
+class cmLocalVisualStudio7GeneratorInternals;
/** \class cmLocalVisualStudio7Generator
* \brief Write Visual Studio .NET project files.
@@ -96,10 +97,8 @@ private:
cmTarget &target, const char *libName);
void OutputBuildTool(std::ostream& fout, const char* configName,
cmTarget& t);
- void OutputLibraries(std::ostream& fout,
- std::vector<cmStdString> const& libs);
void OutputLibraryDirectories(std::ostream& fout,
- std::vector<cmStdString> const& dirs);
+ std::vector<std::string> const& dirs);
void OutputModuleDefinitionFile(std::ostream& fout, cmTarget &target);
void WriteProjectStart(std::ostream& fout, const char *libName,
cmTarget &tgt, std::vector<cmSourceGroup> &sgs);
@@ -120,11 +119,13 @@ private:
virtual std::string GetTargetDirectory(cmTarget const&) const;
friend class cmLocalVisualStudio7GeneratorFCInfo;
+ friend class cmLocalVisualStudio7GeneratorInternals;
cmVS7FlagTable const* ExtraFlagTable;
std::string ModuleDefinitionFile;
int Version;
std::string PlatformName; // Win32 or x64
+ cmLocalVisualStudio7GeneratorInternals* Internal;
};
// This is a table mapping XML tag IDE names to command line options
diff --git a/Source/cmOrderLinkDirectories.cxx b/Source/cmOrderLinkDirectories.cxx
deleted file mode 100644
index 57b7470..0000000
--- a/Source/cmOrderLinkDirectories.cxx
+++ /dev/null
@@ -1,710 +0,0 @@
-#include "cmOrderLinkDirectories.h"
-#include "cmSystemTools.h"
-#include "cmsys/RegularExpression.hxx"
-#include <ctype.h>
-
-//#define CM_ORDER_LINK_DIRECTORIES_DEBUG
-
-//-------------------------------------------------------------------
-cmOrderLinkDirectories::cmOrderLinkDirectories()
-{
- this->StartLinkType = LinkUnknown;
- this->LinkTypeEnabled = false;
- this->Debug = false;
-}
-
-//-------------------------------------------------------------------
-void
-cmOrderLinkDirectories
-::SetLinkTypeInformation(LinkType start_link_type,
- const char* static_link_type_flag,
- const char* shared_link_type_flag)
-{
- // We can support link type switching only if all needed flags are
- // known.
- this->StartLinkType = start_link_type;
- if(static_link_type_flag && *static_link_type_flag &&
- shared_link_type_flag && *shared_link_type_flag)
- {
- this->LinkTypeEnabled = true;
- this->StaticLinkTypeFlag = static_link_type_flag;
- this->SharedLinkTypeFlag = shared_link_type_flag;
- }
- else
- {
- this->LinkTypeEnabled = false;
- this->StaticLinkTypeFlag = "";
- this->SharedLinkTypeFlag = "";
- }
-}
-
-//-------------------------------------------------------------------
-void cmOrderLinkDirectories::SetCurrentLinkType(LinkType lt)
-{
- if(this->CurrentLinkType != lt)
- {
- this->CurrentLinkType = lt;
-
- if(this->LinkTypeEnabled)
- {
- switch(this->CurrentLinkType)
- {
- case LinkStatic:
- this->LinkItems.push_back(this->StaticLinkTypeFlag); break;
- case LinkShared:
- this->LinkItems.push_back(this->SharedLinkTypeFlag); break;
- default: break;
- }
- }
- }
-}
-
-//-------------------------------------------------------------------
-bool cmOrderLinkDirectories::LibraryInDirectory(const char* desiredLib,
- const char* dir,
- const char* libIn)
-{
- // first look for the library as given
- if(this->LibraryMayConflict(desiredLib, dir, libIn))
- {
- return true;
- }
- // next remove the extension (.a, .so ) and look for the library
- // under a different name as the linker can do either
- if(this->RemoveLibraryExtension.find(libIn))
- {
- cmStdString lib = this->RemoveLibraryExtension.match(1);
- cmStdString ext = this->RemoveLibraryExtension.match(2);
- for(std::vector<cmStdString>::iterator i = this->LinkExtensions.begin();
- i != this->LinkExtensions.end(); ++i)
- {
- if(ext != *i)
- {
- std::string fname = lib;
- lib += *i;
- if(this->LibraryMayConflict(desiredLib, dir, fname.c_str()))
- {
- return true;
- }
- }
- }
- }
- return false;
-}
-
-//-------------------------------------------------------------------
-void cmOrderLinkDirectories::FindLibrariesInSearchPaths()
-{
- for(std::set<cmStdString>::iterator dir = this->LinkPathSet.begin();
- dir != this->LinkPathSet.end(); ++dir)
- {
- for(std::map<cmStdString, Library>::iterator lib
- = this->FullPathLibraries.begin();
- lib != this->FullPathLibraries.end(); ++lib)
- {
- if(lib->second.Path != *dir)
- {
- if(this->LibraryInDirectory(lib->second.FullPath.c_str(),
- dir->c_str(), lib->second.File.c_str()))
- {
- this->LibraryToDirectories[lib->second.FullPath].push_back(*dir);
- }
- }
- }
- }
-}
-
-//-------------------------------------------------------------------
-void cmOrderLinkDirectories::FindIndividualLibraryOrders()
-{
- for(std::vector<Library>::iterator lib =
- this->MultiDirectoryLibraries.begin();
- lib != this->MultiDirectoryLibraries.end(); ++lib)
- {
- std::vector<cmStdString>& dirs =
- this->LibraryToDirectories[lib->FullPath];
- std::vector<std::pair<cmStdString, std::vector<cmStdString> >
- >::iterator i;
- for(i = this->DirectoryToAfterList.begin();
- i != this->DirectoryToAfterList.end(); ++i)
- {
- if(i->first == lib->Path)
- {
- break;
- }
- }
- if(i == this->DirectoryToAfterList.end())
- {
- std::cerr << "ERROR: should not happen\n";
- }
- else
- {
- for(std::vector<cmStdString>::iterator d = dirs.begin();
- d != dirs.end(); ++d)
- {
- i->second.push_back(*d);
- }
- }
- }
-}
-
-//-------------------------------------------------------------------
-std::string cmOrderLinkDirectories::NoCaseExpression(const char* str)
-{
- std::string ret;
- const char* s = str;
- while(*s)
- {
- if(*s == '.')
- {
- ret += *s;
- }
- else
- {
- ret += "[";
- ret += tolower(*s);
- ret += toupper(*s);
- ret += "]";
- }
- s++;
- }
- return ret;
-}
-
-//-------------------------------------------------------------------
-void cmOrderLinkDirectories::CreateRegularExpressions()
-{
- this->SplitFramework.compile("(.*)/(.*)\\.framework$");
-
- // Compute a regex to match link extensions.
- cmStdString libext = this->CreateExtensionRegex(this->LinkExtensions);
-
- // Create regex to remove any library extension.
- cmStdString reg("(.*)");
- reg += libext;
- this->RemoveLibraryExtension.compile(reg.c_str());
-
- // Create a regex to match a library name. Match index 1 will be
- // the prefix if it exists and empty otherwise. Match index 2 will
- // be the library name. Match index 3 will be the library
- // extension.
- reg = "^(";
- for(std::set<cmStdString>::iterator p = this->LinkPrefixes.begin();
- p != this->LinkPrefixes.end(); ++p)
- {
- reg += *p;
- reg += "|";
- }
- reg += ")";
- reg += "([^/]*)";
-
- // Create a regex to match any library name.
- cmStdString reg_any = reg;
- reg_any += libext;
-#ifdef CM_ORDER_LINK_DIRECTORIES_DEBUG
- fprintf(stderr, "any regex [%s]\n", reg_any.c_str());
-#endif
- this->ExtractAnyLibraryName.compile(reg_any.c_str());
-
- // Create a regex to match static library names.
- if(!this->StaticLinkExtensions.empty())
- {
- cmStdString reg_static = reg;
- reg_static += this->CreateExtensionRegex(this->StaticLinkExtensions);
-#ifdef CM_ORDER_LINK_DIRECTORIES_DEBUG
- fprintf(stderr, "static regex [%s]\n", reg_static.c_str());
-#endif
- this->ExtractStaticLibraryName.compile(reg_static.c_str());
- }
-
- // Create a regex to match shared library names.
- if(!this->SharedLinkExtensions.empty())
- {
- cmStdString reg_shared = reg;
- reg_shared += this->CreateExtensionRegex(this->SharedLinkExtensions);
-#ifdef CM_ORDER_LINK_DIRECTORIES_DEBUG
- fprintf(stderr, "shared regex [%s]\n", reg_shared.c_str());
-#endif
- this->ExtractSharedLibraryName.compile(reg_shared.c_str());
- }
-}
-
-//-------------------------------------------------------------------
-std::string
-cmOrderLinkDirectories::CreateExtensionRegex(
- std::vector<cmStdString> const& exts)
-{
- // Build a list of extension choices.
- cmStdString libext = "(";
- const char* sep = "";
- for(std::vector<cmStdString>::const_iterator i = exts.begin();
- i != exts.end(); ++i)
- {
- // Separate this choice from the previous one.
- libext += sep;
- sep = "|";
-
- // Store this extension choice with the "." escaped.
- libext += "\\";
-#if defined(_WIN32) && !defined(__CYGWIN__)
- libext += this->NoCaseExpression(i->c_str());
-#else
- libext += *i;
-#endif
- }
-
- // Finish the list.
- libext += ").*";
- return libext;
-}
-
-//-------------------------------------------------------------------
-void cmOrderLinkDirectories::PrepareLinkTargets()
-{
- std::vector<cmStdString> originalLinkItems = this->LinkItems;
- this->LinkItems.clear();
- this->CurrentLinkType = this->StartLinkType;
- for(std::vector<cmStdString>::iterator i = originalLinkItems.begin();
- i != originalLinkItems.end(); ++i)
- {
- // Parse out the prefix, base, and suffix components of the
- // library name. If the name matches that of a shared or static
- // library then set the link type accordingly.
- //
- // Search for shared library names first because some platforms
- // have shared libraries with names that match the static library
- // pattern. For example cygwin and msys use the convention
- // libfoo.dll.a for import libraries and libfoo.a for static
- // libraries. On AIX a library with the name libfoo.a can be
- // shared!
- if(this->ExtractSharedLibraryName.find(*i))
- {
-#ifdef CM_ORDER_LINK_DIRECTORIES_DEBUG
- fprintf(stderr, "shared regex matched [%s] [%s] [%s]\n",
- this->ExtractSharedLibraryName.match(1).c_str(),
- this->ExtractSharedLibraryName.match(2).c_str(),
- this->ExtractSharedLibraryName.match(3).c_str());
-#endif
- this->SetCurrentLinkType(LinkShared);
- this->LinkItems.push_back(this->ExtractSharedLibraryName.match(2));
- }
- else if(this->ExtractStaticLibraryName.find(*i))
- {
-#ifdef CM_ORDER_LINK_DIRECTORIES_DEBUG
- fprintf(stderr, "static regex matched [%s] [%s] [%s]\n",
- this->ExtractStaticLibraryName.match(1).c_str(),
- this->ExtractStaticLibraryName.match(2).c_str(),
- this->ExtractStaticLibraryName.match(3).c_str());
-#endif
- this->SetCurrentLinkType(LinkStatic);
- this->LinkItems.push_back(this->ExtractStaticLibraryName.match(2));
- }
- else if(this->ExtractAnyLibraryName.find(*i))
- {
-#ifdef CM_ORDER_LINK_DIRECTORIES_DEBUG
- fprintf(stderr, "any regex matched [%s] [%s] [%s]\n",
- this->ExtractAnyLibraryName.match(1).c_str(),
- this->ExtractAnyLibraryName.match(2).c_str(),
- this->ExtractAnyLibraryName.match(3).c_str());
-#endif
- this->SetCurrentLinkType(this->StartLinkType);
- this->LinkItems.push_back(this->ExtractAnyLibraryName.match(2));
- }
- else
- {
- this->SetCurrentLinkType(this->StartLinkType);
- this->LinkItems.push_back(*i);
- }
- }
-
- // Restore the original linking type so system runtime libraries are
- // linked properly.
- this->SetCurrentLinkType(this->StartLinkType);
-}
-
-//-------------------------------------------------------------------
-bool cmOrderLinkDirectories::FindPathNotInDirectoryToAfterList(
- cmStdString& path)
-{
- for(std::vector<std::pair<cmStdString, std::vector<cmStdString> >
- >::iterator i = this->DirectoryToAfterList.begin();
- i != this->DirectoryToAfterList.end(); ++i)
- {
- const cmStdString& p = i->first;
- bool found = false;
- for(std::vector<std::pair<cmStdString, std::vector<cmStdString> >
- >::iterator j = this->DirectoryToAfterList.begin();
- j != this->DirectoryToAfterList.end() && !found; ++j)
- {
- if(j != i)
- {
- found = (std::find(j->second.begin(), j->second.end(), p)
- != j->second.end());
- }
- }
- if(!found)
- {
- path = p;
- this->DirectoryToAfterList.erase(i);
- return true;
- }
- }
- path = "";
- return false;
-}
-
-
-//-------------------------------------------------------------------
-void cmOrderLinkDirectories::OrderPaths(std::vector<cmStdString>&
- orderedPaths)
-{
- cmStdString path;
- // This is a topological sort implementation
- // One at a time find paths that are not in any other paths after list
- // and put them into the orderedPaths vector in that order
- // FindPathNotInDirectoryToAfterList removes the path from the
- // this->DirectoryToAfterList once it is found
- while(this->FindPathNotInDirectoryToAfterList(path))
- {
- orderedPaths.push_back(path);
- }
- // at this point if there are still paths in this->DirectoryToAfterList
- // then there is a cycle and we are stuck
- if(this->DirectoryToAfterList.size())
- {
- for(std::vector<std::pair<cmStdString, std::vector<cmStdString> >
- >::iterator i = this->DirectoryToAfterList.begin();
- i != this->DirectoryToAfterList.end(); ++i)
- {
- this->ImpossibleDirectories.insert(i->first);
- // still put it in the path list in the order we find them
- orderedPaths.push_back(i->first);
- }
-
- }
-}
-
-//-------------------------------------------------------------------
-void cmOrderLinkDirectories::SetLinkInformation(
- const char* targetName,
- const std::vector<std::string>& linkLibraries,
- const std::vector<std::string>& linkDirectories,
- const cmTargetManifest& manifest,
- const char* configSubdir
- )
-{
- // Save the target name.
- this->TargetName = targetName;
-
- // Save the subdirectory used for linking in this configuration.
- this->ConfigSubdir = configSubdir? configSubdir : "";
-
- // Merge the link directory search path given into our path set.
- std::vector<cmStdString> empty;
- for(std::vector<std::string>::const_iterator p = linkDirectories.begin();
- p != linkDirectories.end(); ++p)
- {
- std::string dir = *p;
-#ifdef _WIN32
- // Avoid case problems for windows paths.
- if(dir.size() > 2 && dir[1] == ':')
- {
- if(dir[0] >= 'A' && dir[0] <= 'Z')
- {
- dir[0] += 'a' - 'A';
- }
- }
- dir = cmSystemTools::GetActualCaseForPath(dir.c_str());
-#endif
- if(this->DirectoryToAfterListEmitted.insert(dir).second)
- {
- std::pair<cmStdString, std::vector<cmStdString> > dp;
- dp.first = dir;
- this->DirectoryToAfterList.push_back(dp);
- this->LinkPathSet.insert(dir);
- }
- }
-
- // Append the link library list into our raw list.
- for(std::vector<std::string>::const_iterator l = linkLibraries.begin();
- l != linkLibraries.end(); ++l)
- {
- this->RawLinkItems.push_back(*l);
- }
-
- // Construct a set of files that will exist after building.
- for(cmTargetManifest::const_iterator i = manifest.begin();
- i != manifest.end(); ++i)
- {
- for(cmTargetSet::const_iterator j = i->second.begin();
- j != i->second.end(); ++j)
- {
- this->ManifestFiles.insert(*j);
- }
- }
-}
-
-//-------------------------------------------------------------------
-bool cmOrderLinkDirectories::DetermineLibraryPathOrder()
-{
- // set up all the regular expressions
- this->CreateRegularExpressions();
- std::vector<cmStdString> finalOrderPaths;
- // find all libs that are full paths
- Library aLib;
- cmStdString dir;
- cmStdString file;
- std::vector<cmStdString> empty;
- // do not add a -F for the system frameworks
- this->EmittedFrameworkPaths.insert("/System/Library/Frameworks");
- for(unsigned int i=0; i < this->RawLinkItems.size(); ++i)
- {
- bool framework = false;
-#ifdef CM_ORDER_LINK_DIRECTORIES_DEBUG
- fprintf(stderr, "Raw link item [%s]\n", this->RawLinkItems[i].c_str());
-#endif
- // if it is a full path to an item then separate it from the path
- // this only works with files and paths
- cmStdString& item = this->RawLinkItems[i];
-
- if(cmSystemTools::FileIsFullPath(item.c_str()))
- {
- if(cmSystemTools::IsPathToFramework(item.c_str()))
- {
- this->SplitFramework.find(item.c_str());
- cmStdString path = this->SplitFramework.match(1);
- // Add the -F path if we have not yet done so
- if(this->EmittedFrameworkPaths.insert(path).second)
- {
- std::string fpath = "-F";
- fpath += cmSystemTools::ConvertToOutputPath(path.c_str());
- this->LinkItems.push_back(fpath);
- }
- // now add the -framework option
- std::string frame = "-framework ";
- frame += this->SplitFramework.match(2);
- this->LinkItems.push_back(frame);
- framework = true;
- }
- if(cmSystemTools::FileIsDirectory(item.c_str()))
- {
- if(!framework)
- {
- // A full path to a directory was found as a link item
- // warn user
- std::string message =
- "Warning: Ignoring path found in link libraries for target: ";
- message += this->TargetName;
- message += ", path is: ";
- message += this->RawLinkItems[i];
- message +=
- ". Expected a library name or a full path to a library name.";
- cmSystemTools::Message(message.c_str());
- continue;
- }
- } // is it a directory
- if(!framework)
- {
- dir = cmSystemTools::GetFilenamePath(this->RawLinkItems[i]);
- file = cmSystemTools::GetFilenameName(this->RawLinkItems[i]);
-#ifdef _WIN32
- // Avoid case problems for windows paths.
- if(dir.size() > 2 && dir[1] == ':')
- {
- if(dir[0] >= 'A' && dir[0] <= 'Z')
- {
- dir[0] += 'a' - 'A';
- }
- }
- dir = cmSystemTools::GetActualCaseForPath(dir.c_str());
-#endif
- if(this->DirectoryToAfterListEmitted.insert(dir).second)
- {
- std::pair<cmStdString, std::vector<cmStdString> > dp;
- dp.first = dir;
- this->DirectoryToAfterList.push_back(dp);
- }
- this->LinkPathSet.insert(dir);
- aLib.FullPath = this->RawLinkItems[i];
- aLib.File = file;
- aLib.Path = dir;
- this->FullPathLibraries[aLib.FullPath] = aLib;
-#ifdef CM_ORDER_LINK_DIRECTORIES_DEBUG
- fprintf(stderr, "Storing item [%s]\n", file.c_str());
-#endif
- this->LinkItems.push_back(file);
- }
- }
- else
- {
- this->LinkItems.push_back(this->RawLinkItems[i]);
- }
- }
- this->FindLibrariesInSearchPaths();
- for(std::map<cmStdString, std::vector<cmStdString> >::iterator lib =
- this->LibraryToDirectories.begin();
- lib!= this->LibraryToDirectories.end();
- ++lib)
- {
- if(lib->second.size() > 0)
- {
- this->MultiDirectoryLibraries.push_back
- (this->FullPathLibraries[lib->first]);
- }
- else
- {
- this->SingleDirectoryLibraries.push_back
- (this->FullPathLibraries[lib->first]);
- }
- }
- this->FindIndividualLibraryOrders();
- this->SortedSearchPaths.clear();
- if(this->Debug)
- {
- this->PrintMap("this->LibraryToDirectories", this->LibraryToDirectories);
- this->PrintVector("this->DirectoryToAfterList",
- this->DirectoryToAfterList);
- }
- this->OrderPaths(this->SortedSearchPaths);
- // now turn libfoo.a into foo and foo.a into foo
- // This will prepare the link items for -litem
- this->PrepareLinkTargets();
- if(this->ImpossibleDirectories.size())
- {
- cmSystemTools::Message(this->GetWarnings().c_str());
- return false;
- }
- return true;
-}
-
-std::string cmOrderLinkDirectories::GetWarnings()
-{
- std::string warning =
- "It is impossible to order the linker search path in such a way "
- "that libraries specified as full paths will be picked by the "
- "linker.\nDirectories and libraries involved are:\n";
-
- for(std::set<cmStdString>::iterator i = this->ImpossibleDirectories.begin();
- i != this->ImpossibleDirectories.end(); ++i)
- {
- warning += "Directory: ";
- warning += *i;
- warning += " contains:\n";
- std::map<cmStdString, std::vector<cmStdString> >::iterator j;
- for(j = this->LibraryToDirectories.begin();
- j != this->LibraryToDirectories.end(); ++j)
- {
- if(std::find(j->second.begin(), j->second.end(), *i)
- != j->second.end())
- {
- warning += "Library: ";
- warning += j->first;
- warning += "\n";
- }
- }
- warning += "\n";
- }
- warning += "\n";
- return warning;
-}
-
-//-------------------------------------------------------------------
-void
-cmOrderLinkDirectories::PrintMap(const char* name,
- std::map<cmStdString, std::vector<cmStdString> >& m)
-{
- std::cout << name << "\n";
- for(std::map<cmStdString, std::vector<cmStdString> >::iterator i =
- m.begin(); i != m.end();
- ++i)
- {
- std::cout << i->first << ": ";
- for(std::vector<cmStdString>::iterator l = i->second.begin();
- l != i->second.end(); ++l)
- {
- std::cout << *l << " ";
- }
- std::cout << "\n";
- }
-}
-//-------------------------------------------------------------------
-void
-cmOrderLinkDirectories::PrintVector(const char* name,
- std::vector<std::pair<cmStdString,
- std::vector<cmStdString> > >& m)
-{
- std::cout << name << "\n";
- for(std::vector<std::pair<cmStdString, std::vector<cmStdString> >
- >::iterator i = m.begin(); i != m.end(); ++i)
- {
- std::cout << i->first << ": ";
- for(std::vector<cmStdString>::iterator l = i->second.begin();
- l != i->second.end(); ++l)
- {
- std::cout << *l << " ";
- }
- std::cout << "\n";
- }
-}
-
-void cmOrderLinkDirectories::GetFullPathLibraries(std::vector<cmStdString>&
- libs)
-{
- for(std::map<cmStdString, Library>::iterator i =
- this->FullPathLibraries.begin();
- i != this->FullPathLibraries.end(); ++i)
- {
- libs.push_back(i->first);
- }
-
-}
-
-//----------------------------------------------------------------------------
-bool cmOrderLinkDirectories::LibraryMayConflict(const char* desiredLib,
- const char* dir,
- const char* fname)
-{
- // We need to check whether the given file may be picked up by the
- // linker. This will occur if it exists as given or may be built
- // using the name given.
- bool found = false;
- std::string path = dir;
- path += "/";
- path += fname;
- if(this->ManifestFiles.find(path) != this->ManifestFiles.end())
- {
- found = true;
- }
- else if(cmSystemTools::FileExists(path.c_str()))
- {
- found = true;
- }
-
- // When linking with a multi-configuration build tool the
- // per-configuration subdirectory is added to each link path. Check
- // this subdirectory too.
- if(!found && !this->ConfigSubdir.empty())
- {
- path = dir;
- path += "/";
- path += this->ConfigSubdir;
- path += "/";
- path += fname;
- if(this->ManifestFiles.find(path) != this->ManifestFiles.end())
- {
- found = true;
- }
- else if(cmSystemTools::FileExists(path.c_str()))
- {
- found = true;
- }
- }
-
- // A library conflicts if it is found and is not a symlink back to
- // the desired library.
- if(found)
- {
- return !cmSystemTools::SameFile(desiredLib, path.c_str());
- }
- return false;
-}
diff --git a/Source/cmOrderLinkDirectories.h b/Source/cmOrderLinkDirectories.h
deleted file mode 100644
index a3bc75a..0000000
--- a/Source/cmOrderLinkDirectories.h
+++ /dev/null
@@ -1,192 +0,0 @@
-/*=========================================================================
-
- Program: CMake - Cross-Platform Makefile Generator
- Module: $RCSfile$
- Language: C++
- Date: $Date$
- Version: $Revision$
-
- Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
- See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
-
- This software is distributed WITHOUT ANY WARRANTY; without even
- the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- PURPOSE. See the above copyright notices for more information.
-
-=========================================================================*/
-#ifndef cmOrderLinkDirectories_h
-#define cmOrderLinkDirectories_h
-
-#include <cmStandardIncludes.h>
-#include <map>
-#include <vector>
-#include "cmTarget.h"
-#include "cmsys/RegularExpression.hxx"
-
-
-/** \class cmOrderLinkDirectories
- * \brief Compute the best -L path order
- *
- * This class computes the best order for -L paths.
- * It tries to make sure full path specified libraries are
- * used. For example if you have /usr/mylib/libfoo.a on as
- * a link library for a target, and you also have /usr/lib/libbar.a
- * and you also have /usr/lib/libfoo.a, then you would
- * want -L/usr/mylib -L/usr/lib to make sure the correct libfoo.a is
- * found by the linker. The algorithm is as follows:
- * - foreach library create a vector of directories it exists in.
- * - foreach directory create a vector of directories that must come
- * after it, put this in a map<dir, vector<dir>> mapping from a directory
- * to the vector of directories that it must be before.
- * - put all directories into a vector
- * - sort the vector with a compare function CanBeBefore
- * CanBeBefore returns true if a directory is OK to be before
- * another directory. This is determined by looking at the
- * map<dir vector<dir>> and seeing if d1 is in the vector for d2.
- */
-class cmOrderLinkDirectories
-{
-public:
- cmOrderLinkDirectories();
- ///! set link information from the target
- void SetLinkInformation(const char* targetName,
- const std::vector<std::string>& linkLibraries,
- const std::vector<std::string>& linkDirectories,
- const cmTargetManifest& manifest,
- const char* configSubdir);
- ///! Compute the best order for -L paths from GetLinkLibraries
- bool DetermineLibraryPathOrder();
- ///! Get the results from DetermineLibraryPathOrder
- void GetLinkerInformation(std::vector<cmStdString>& searchPaths,
- std::vector<cmStdString>& linkItems)
- {
- linkItems = this->LinkItems;
- searchPaths = this->SortedSearchPaths;
- }
- // should be set from CMAKE_STATIC_LIBRARY_SUFFIX,
- // CMAKE_SHARED_LIBRARY_SUFFIX
- // CMAKE_LINK_LIBRARY_SUFFIX
- enum LinkType { LinkUnknown, LinkStatic, LinkShared };
- void AddLinkExtension(const char* e, LinkType type = LinkUnknown)
- {
- if(e && *e)
- {
- if(type == LinkStatic)
- {
- this->StaticLinkExtensions.push_back(e);
- }
- if(type == LinkShared)
- {
- this->SharedLinkExtensions.push_back(e);
- }
- this->LinkExtensions.push_back(e);
- }
- }
- // should be set from CMAKE_STATIC_LIBRARY_PREFIX
- void AddLinkPrefix(const char* s)
- {
- if(s)
- {
- this->LinkPrefixes.insert(s);
- }
- }
- // Return any warnings if the exist
- std::string GetWarnings();
- // return a list of all full path libraries
- void GetFullPathLibraries(std::vector<cmStdString>& libs);
-
- // Provide flags for switching library link type.
- void SetLinkTypeInformation(LinkType start_link_type,
- const char* static_link_type_flag,
- const char* shared_link_type_flag);
-
- // structure to hold a full path library link item
- struct Library
- {
- cmStdString FullPath;
- cmStdString File;
- cmStdString Path;
- };
- friend struct cmOrderLinkDirectoriesCompare;
- void DebugOn()
- {
- this->Debug = true;
- }
-
-private:
- void CreateRegularExpressions();
- std::string CreateExtensionRegex(std::vector<cmStdString> const& exts);
- void DetermineLibraryPathOrder(std::vector<cmStdString>& searchPaths,
- std::vector<cmStdString>& libs,
- std::vector<cmStdString>& sortedPaths);
- void PrepareLinkTargets();
- bool LibraryInDirectory(const char* desiredLib,
- const char* dir, const char* lib);
- void FindLibrariesInSearchPaths();
- void FindIndividualLibraryOrders();
- void PrintMap(const char* name,
- std::map<cmStdString, std::vector<cmStdString> >& m);
- void PrintVector(const char* name,
- std::vector<std::pair<cmStdString,
- std::vector<cmStdString> > >& m);
- void OrderPaths(std::vector<cmStdString>& paths);
- bool FindPathNotInDirectoryToAfterList(cmStdString& path);
- std::string NoCaseExpression(const char* str);
- bool LibraryMayConflict(const char* desiredLib,
- const char* dir, const char* fname);
-private:
- // set of files that will exist when the build occurs
- std::set<cmStdString> ManifestFiles;
- // map from library to directories that it is in other than its full path
- std::map<cmStdString, std::vector<cmStdString> > LibraryToDirectories;
- // map from directory to vector of directories that must be after it
- std::vector<std::pair<cmStdString, std::vector<cmStdString> > >
- DirectoryToAfterList;
- std::set<cmStdString> DirectoryToAfterListEmitted;
- // map from full path to a Library struct
- std::map<cmStdString, Library> FullPathLibraries;
- // libraries that are found in multiple directories
- std::vector<Library> MultiDirectoryLibraries;
- // libraries that are only found in one directory
- std::vector<Library> SingleDirectoryLibraries;
- // This is a vector of all the link objects -lm or m
- std::vector<cmStdString> LinkItems;
- // Unprocessed link items
- std::vector<cmStdString> RawLinkItems;
- // This vector holds the sorted -L paths
- std::vector<cmStdString> SortedSearchPaths;
- // This vector holds the -F paths
- std::set<cmStdString> EmittedFrameworkPaths;
- // This is the set of -L paths unsorted, but unique
- std::set<cmStdString> LinkPathSet;
- // the names of link extensions
- std::vector<cmStdString> StaticLinkExtensions;
- std::vector<cmStdString> SharedLinkExtensions;
- std::vector<cmStdString> LinkExtensions;
- // the names of link prefixes
- std::set<cmStdString> LinkPrefixes;
- // set of directories that can not be put in the correct order
- std::set<cmStdString> ImpossibleDirectories;
- // Name of target
- cmStdString TargetName;
- // Subdirectory used for this configuration if any.
- cmStdString ConfigSubdir;
-
- // Link type adjustment.
- LinkType StartLinkType;
- LinkType CurrentLinkType;
- cmStdString StaticLinkTypeFlag;
- cmStdString SharedLinkTypeFlag;
- bool LinkTypeEnabled;
- void SetCurrentLinkType(LinkType lt);
-
- // library regular expressions
- cmsys::RegularExpression RemoveLibraryExtension;
- cmsys::RegularExpression ExtractStaticLibraryName;
- cmsys::RegularExpression ExtractSharedLibraryName;
- cmsys::RegularExpression ExtractAnyLibraryName;
- cmsys::RegularExpression SplitFramework;
- bool Debug;
-};
-
-#endif
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 787e08e..ab303ab 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -35,7 +35,6 @@ cmTarget::cmTarget()
{
this->Makefile = 0;
this->LinkLibrariesAnalyzed = false;
- this->LinkDirectoriesComputed = false;
this->HaveInstallRule = false;
this->DLLPlatform = false;
this->IsImportedTarget = false;
@@ -843,71 +842,15 @@ void cmTarget::MergeLinkLibraries( cmMakefile& mf,
void cmTarget::AddLinkDirectory(const char* d)
{
// Make sure we don't add unnecessary search directories.
- if(std::find(this->ExplicitLinkDirectories.begin(),
- this->ExplicitLinkDirectories.end(), d)
- == this->ExplicitLinkDirectories.end() )
+ if(this->LinkDirectoriesEmmitted.insert(d).second)
{
- this->ExplicitLinkDirectories.push_back( d );
- this->LinkDirectoriesComputed = false;
+ this->LinkDirectories.push_back(d);
}
}
//----------------------------------------------------------------------------
const std::vector<std::string>& cmTarget::GetLinkDirectories()
{
- // Make sure all library dependencies have been analyzed.
- if(!this->LinkLibrariesAnalyzed && !this->LinkLibraries.empty())
- {
- cmSystemTools::Error(
- "cmTarget::GetLinkDirectories called before "
- "cmTarget::AnalyzeLibDependencies on target ",
- this->Name.c_str());
- }
-
- // Make sure the complete set of link directories has been computed.
- if(!this->LinkDirectoriesComputed)
- {
- // Check whether we should use an import library for linking a target.
- bool implib =
- this->Makefile->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX") != 0;
-
- // Compute the full set of link directories including the
- // locations of targets that have been linked in. Start with the
- // link directories given explicitly.
- this->LinkDirectories = this->ExplicitLinkDirectories;
- for(LinkLibraryVectorType::iterator ll = this->LinkLibraries.begin();
- ll != this->LinkLibraries.end(); ++ll)
- {
- // If this library is a CMake target then add its location as a
- // link directory.
- std::string lib = ll->first;
- cmTarget* tgt = 0;
- if(this->Makefile && this->Makefile->GetLocalGenerator() &&
- this->Makefile->GetLocalGenerator()->GetGlobalGenerator())
- {
- tgt = (this->Makefile->GetLocalGenerator()->GetGlobalGenerator()
- ->FindTarget(0, lib.c_str(), false));
- }
- if(tgt)
- {
- // Add the directory only if it is not already present. This
- // is an N^2 algorithm for adding the directories, but N
- // should not get very big.
- const char* libpath = tgt->GetDirectory(0, implib);
- if(std::find(this->LinkDirectories.begin(),
- this->LinkDirectories.end(),
- libpath) == this->LinkDirectories.end())
- {
- this->LinkDirectories.push_back(libpath);
- }
- }
- }
-
- // The complete set of link directories has now been computed.
- this->LinkDirectoriesComputed = true;
- }
-
- // Return the complete set of link directories.
return this->LinkDirectories;
}
@@ -2245,6 +2188,76 @@ void cmTarget::GetExecutableNamesInternal(std::string& name,
}
//----------------------------------------------------------------------------
+void cmTarget::GenerateTargetManifest(const char* config)
+{
+ cmMakefile* mf = this->Makefile;
+ cmLocalGenerator* lg = mf->GetLocalGenerator();
+ cmGlobalGenerator* gg = lg->GetGlobalGenerator();
+
+ // Get the names.
+ std::string name;
+ std::string soName;
+ std::string realName;
+ std::string impName;
+ std::string pdbName;
+ if(this->GetType() == cmTarget::EXECUTABLE)
+ {
+ this->GetExecutableNames(name, realName, impName, pdbName, config);
+ }
+ else if(this->GetType() == cmTarget::STATIC_LIBRARY ||
+ this->GetType() == cmTarget::SHARED_LIBRARY ||
+ this->GetType() == cmTarget::MODULE_LIBRARY)
+ {
+ this->GetLibraryNames(name, soName, realName, impName, pdbName, config);
+ }
+ else
+ {
+ return;
+ }
+
+ // Get the directory.
+ std::string dir = this->GetDirectory(config, false);
+
+ // Add each name.
+ std::string f;
+ if(!name.empty())
+ {
+ f = dir;
+ f += "/";
+ f += name;
+ gg->AddToManifest(config? config:"", f);
+ }
+ if(!soName.empty())
+ {
+ f = dir;
+ f += "/";
+ f += soName;
+ gg->AddToManifest(config? config:"", f);
+ }
+ if(!realName.empty())
+ {
+ f = dir;
+ f += "/";
+ f += realName;
+ gg->AddToManifest(config? config:"", f);
+ }
+ if(!pdbName.empty())
+ {
+ f = dir;
+ f += "/";
+ f += pdbName;
+ gg->AddToManifest(config? config:"", f);
+ }
+ if(!impName.empty())
+ {
+ f = this->GetDirectory(config, true);
+ f += "/";
+ f += impName;
+ gg->AddToManifest(config? config:"", f);
+ }
+}
+
+//----------------------------------------------------------------------------
void cmTarget::SetPropertyDefault(const char* property,
const char* default_value)
{
diff --git a/Source/cmTarget.h b/Source/cmTarget.h
index d1b48e6..50e8429 100644
--- a/Source/cmTarget.h
+++ b/Source/cmTarget.h
@@ -271,6 +271,9 @@ public:
std::string& impName,
std::string& pdbName, const char* config);
+ /** Add the target output files to the global generator manifest. */
+ void GenerateTargetManifest(const char* config);
+
/**
* Compute whether this target must be relinked before installing.
*/
@@ -414,10 +417,9 @@ private:
LinkLibraryVectorType LinkLibraries;
LinkLibraryVectorType PrevLinkedLibraries;
bool LinkLibrariesAnalyzed;
- bool LinkDirectoriesComputed;
std::vector<std::string> Frameworks;
std::vector<std::string> LinkDirectories;
- std::vector<std::string> ExplicitLinkDirectories;
+ std::set<cmStdString> LinkDirectoriesEmmitted;
bool HaveInstallRule;
std::string InstallNameFixupPath;
std::string InstallPath;