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.
This commit is contained in:
Brad King 2008-01-22 09:13:04 -05:00
parent 0df9e6904c
commit 96fd5909d9
25 changed files with 1781 additions and 1790 deletions

View File

@ -149,6 +149,14 @@ IF(NOT CMAKE_C_LINK_EXECUTABLE)
"<CMAKE_C_COMPILER> <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
ENDIF(NOT CMAKE_C_LINK_EXECUTABLE)
IF(NOT CMAKE_EXECUTABLE_RUNTIME_C_FLAG)
SET(CMAKE_EXECUTABLE_RUNTIME_C_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG})
ENDIF(NOT CMAKE_EXECUTABLE_RUNTIME_C_FLAG)
IF(NOT CMAKE_EXECUTABLE_RUNTIME_C_FLAG_SEP)
SET(CMAKE_EXECUTABLE_RUNTIME_C_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP})
ENDIF(NOT CMAKE_EXECUTABLE_RUNTIME_C_FLAG_SEP)
MARK_AS_ADVANCED(
CMAKE_C_FLAGS
CMAKE_C_FLAGS_DEBUG

View File

@ -84,6 +84,18 @@ IF(NOT CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG_SEP)
SET(CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP})
ENDIF(NOT CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG_SEP)
IF(NOT CMAKE_EXECUTABLE_RUNTIME_CXX_FLAG)
SET(CMAKE_EXECUTABLE_RUNTIME_CXX_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG})
ENDIF(NOT CMAKE_EXECUTABLE_RUNTIME_CXX_FLAG)
IF(NOT CMAKE_EXECUTABLE_RUNTIME_CXX_FLAG_SEP)
SET(CMAKE_EXECUTABLE_RUNTIME_CXX_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP})
ENDIF(NOT CMAKE_EXECUTABLE_RUNTIME_CXX_FLAG_SEP)
IF(NOT DEFINED CMAKE_SHARED_LIBRARY_LINK_CXX_WITH_RUNTIME_PATH)
SET(CMAKE_SHARED_LIBRARY_LINK_CXX_WITH_RUNTIME_PATH ${CMAKE_SHARED_LIBRARY_LINK_C_WITH_RUNTIME_PATH})
ENDIF(NOT DEFINED CMAKE_SHARED_LIBRARY_LINK_CXX_WITH_RUNTIME_PATH)
IF(NOT CMAKE_INCLUDE_FLAG_CXX)
SET(CMAKE_INCLUDE_FLAG_CXX ${CMAKE_INCLUDE_FLAG_C})
ENDIF(NOT CMAKE_INCLUDE_FLAG_CXX)

View File

@ -76,6 +76,18 @@ IF(NOT CMAKE_SHARED_MODULE_RUNTIME_Fortran_FLAG_SEP)
SET(CMAKE_SHARED_MODULE_RUNTIME_Fortran_FLAG_SEP ${CMAKE_SHARED_MODULE_RUNTIME_C_FLAG_SEP})
ENDIF(NOT CMAKE_SHARED_MODULE_RUNTIME_Fortran_FLAG_SEP)
IF(NOT CMAKE_EXECUTABLE_RUNTIME_Fortran_FLAG)
SET(CMAKE_EXECUTABLE_RUNTIME_Fortran_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_Fortran_FLAG})
ENDIF(NOT CMAKE_EXECUTABLE_RUNTIME_Fortran_FLAG)
IF(NOT CMAKE_EXECUTABLE_RUNTIME_Fortran_FLAG_SEP)
SET(CMAKE_EXECUTABLE_RUNTIME_Fortran_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_Fortran_FLAG_SEP})
ENDIF(NOT CMAKE_EXECUTABLE_RUNTIME_Fortran_FLAG_SEP)
IF(NOT DEFINED CMAKE_SHARED_LIBRARY_LINK_Fortran_WITH_RUNTIME_PATH)
SET(CMAKE_SHARED_LIBRARY_LINK_Fortran_WITH_RUNTIME_PATH ${CMAKE_SHARED_LIBRARY_LINK_C_WITH_RUNTIME_PATH})
ENDIF(NOT DEFINED CMAKE_SHARED_LIBRARY_LINK_Fortran_WITH_RUNTIME_PATH)
IF(NOT CMAKE_INCLUDE_FLAG_Fortran)
SET(CMAKE_INCLUDE_FLAG_Fortran ${CMAKE_INCLUDE_FLAG_C})
ENDIF(NOT CMAKE_INCLUDE_FLAG_Fortran)

View File

@ -1,15 +1,23 @@
SET(CMAKE_SHARED_LIBRARY_PREFIX "lib") # lib
SET(CMAKE_SHARED_LIBRARY_SUFFIX ".so") # .so
SET(CMAKE_DL_LIBS "-lld")
SET(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-G -Wl,-brtl") # -shared
SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "-Wl,-brtl,-bexpall") # +s, flag for exe link to use shared lib
# RPATH support on AIX is called libpath. By default the runtime
# libpath is paths specified by -L followed by /usr/lib and /lib. In
# order to prevent the -L paths from being used we must force use of
# -Wl,-blibpath:/usr/lib:/lib whether RPATH support is on or not.
# When our own RPATH is to be added it may be inserted before the
# "always" paths.
SET(CMAKE_PLATFORM_REQUIRED_RUNTIME_PATH /usr/lib /lib)
SET(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "-Wl,-blibpath:")
SET(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP ":")
# CXX Compiler
IF(CMAKE_COMPILER_IS_GNUCXX)
SET(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS "-shared -Wl,-G") # -shared
ELSE(CMAKE_COMPILER_IS_GNUCXX)
SET(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS "-G -Wl,-brtl") # -shared
SET(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "-Wl,-brtl,-bexpall") # +s, flag for exe link to use shared lib
SET(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS "-G -Wl,-brtl,-bnoipath") # -shared
SET(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "-Wl,-brtl,-bnoipath,-bexpall") # +s, flag for exe link to use shared lib
SET(CMAKE_SHARED_LIBRARY_CXX_FLAGS " ")
SET(CMAKE_SHARED_MODULE_CXX_FLAGS " ")
SET (CMAKE_CXX_FLAGS_DEBUG_INIT "-g")
@ -22,8 +30,8 @@ ENDIF(CMAKE_COMPILER_IS_GNUCXX)
IF(CMAKE_COMPILER_IS_GNUCC)
SET(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-shared -Wl,-G") # -shared
ELSE(CMAKE_COMPILER_IS_GNUCC)
SET(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-G -Wl,-brtl") # -shared
SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "-Wl,-brtl,-bexpall") # +s, flag for exe link to use shared lib
SET(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-G -Wl,-brtl,-bnoipath") # -shared
SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "-Wl,-brtl,-bnoipath,-bexpall") # +s, flag for exe link to use shared lib
SET(CMAKE_SHARED_LIBRARY_C_FLAGS " ")
SET(CMAKE_SHARED_MODULE_C_FLAGS " ")
SET (CMAKE_C_FLAGS_DEBUG_INIT "-g")

View File

@ -2,15 +2,18 @@ SET(CMAKE_SHARED_LIBRARY_SUFFIX ".sl") # .so
SET(CMAKE_DL_LIBS "dld")
SET(CMAKE_FIND_LIBRARY_SUFFIXES ".sl" ".so" ".a")
SET(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP ":") # : or empty
# The HP linker needs to find transitive shared library dependencies
# in the -L path. Therefore the runtime path must be added to the
# link line with -L flags.
SET(CMAKE_SHARED_LIBRARY_LINK_C_WITH_RUNTIME_PATH 1)
# fortran
IF(CMAKE_COMPILER_IS_GNUG77)
SET(CMAKE_SHARED_LIBRARY_Fortran_FLAGS "-fPIC") # -pic
SET(CMAKE_SHARED_LIBRARY_CREATE_Fortran_FLAGS "-shared -Wl,-E -Wl,-b") # -shared
SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "-Wl,+s -Wl,-E") # +s, flag for exe link to use shared lib
SET(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "-Wl,+b") # -rpath
SET(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP ":") # : or empty
SET(CMAKE_SHARED_LIBRARY_CREATE_Fortran_FLAGS "-shared -Wl,-E,-b,+nodefaultrpath") # -shared
SET(CMAKE_SHARED_LIBRARY_LINK_Fortran_FLAGS "-Wl,+s,-E,+nodefaultrpath") # +s, flag for exe link to use shared lib
SET(CMAKE_SHARED_LIBRARY_RUNTIME_Fortran_FLAG "-Wl,+b") # -rpath
SET(CMAKE_SHARED_LIBRARY_RUNTIME_Fortran_FLAG_SEP ":") # : or empty
SET(CMAKE_SHARED_LIBRARY_SONAME_Fortran_FLAG "-Wl,+h")
SET(CMAKE_SHARED_LIBRARY_Fortran_FLAGS "-fPIC") # -pic
ELSE(CMAKE_COMPILER_IS_GNUG77)
@ -19,16 +22,19 @@ ELSE(CMAKE_COMPILER_IS_GNUG77)
"ld <CMAKE_SHARED_LIBRARY_CREATE_Fortran_FLAGS> <CMAKE_SHARED_LIBRARY_SONAME_Fortran_FLAG><TARGET_SONAME> <LINK_FLAGS> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>")
SET(CMAKE_SHARED_LIBRARY_Fortran_FLAGS "+Z") # -pic
SET(CMAKE_SHARED_LIBRARY_CREATE_Fortran_FLAGS "-E -b -L/usr/lib") # -shared
SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "-Wl,+s -Wl,-E") # +s, flag for exe link to use shared lib
SET(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "+b") # -rpath
SET(CMAKE_SHARED_LIBRARY_LINK_Fortran_FLAGS "-Wl,+s,-E,+nodefaultrpath") # +s, flag for exe link to use shared lib
SET(CMAKE_SHARED_LIBRARY_RUNTIME_Fortran_FLAG "+b") # -rpath
SET(CMAKE_SHARED_LIBRARY_RUNTIME_Fortran_FLAG_SEP ":") # : or empty
SET(CMAKE_SHARED_LIBRARY_SONAME_Fortran_FLAG "+h")
SET(CMAKE_EXECUTABLE_RUNTIME_Fortran_FLAG "-Wl,+b") # -rpath
ENDIF(CMAKE_COMPILER_IS_GNUG77)
# C compiler
IF(CMAKE_COMPILER_IS_GNUCC)
# gnu gcc
SET(CMAKE_SHARED_LIBRARY_C_FLAGS "-fPIC") # -pic
SET(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-shared -Wl,-E -Wl,-b") # -shared
SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "-Wl,+s -Wl,-E") # +s, flag for exe link to use shared lib
SET(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-shared -Wl,-E,-b,+nodefaultrpath") # -shared
SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "-Wl,+s,-E,+nodefaultrpath") # +s, flag for exe link to use shared lib
SET(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "-Wl,+b") # -rpath
SET(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP ":") # : or empty
SET(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-Wl,+h")
@ -40,28 +46,33 @@ ELSE(CMAKE_COMPILER_IS_GNUCC)
SET(CMAKE_C_CREATE_SHARED_LIBRARY
"ld <CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS> <CMAKE_SHARED_LIBRARY_SONAME_C_FLAG><TARGET_SONAME> <LINK_FLAGS> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>")
SET(CMAKE_SHARED_LIBRARY_C_FLAGS "+Z") # -pic
SET(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-E -b -L/usr/lib") # -shared
SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "-Wl,+s -Wl,-E") # +s, flag for exe link to use shared lib
SET(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-E -b +nodefaultrpath -L/usr/lib") # -shared
SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "-Wl,+s,-E,+nodefaultrpath") # +s, flag for exe link to use shared lib
SET(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "+b") # -rpath
SET(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP ":") # : or empty
SET(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "+h")
SET(CMAKE_EXECUTABLE_RUNTIME_C_FLAG "-Wl,+b") # -rpath
ENDIF(CMAKE_COMPILER_IS_GNUCC)
# CXX compiler
IF(CMAKE_COMPILER_IS_GNUCXX)
# for gnu C++
SET(CMAKE_SHARED_LIBRARY_CXX_FLAGS "-fPIC") # -pic
SET(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS "-shared -Wl,-E -Wl,-b") # -shared
SET(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "-Wl,+s -Wl,-E") # +s, flag for exe link to use shared lib
SET(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS "-shared -Wl,-E,-b,+nodefaultrpath") # -shared
SET(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "-Wl,+s,-E,+nodefaultrpath") # +s, flag for exe link to use shared lib
SET(CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG "-Wl,+b") # -rpath
SET(CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG_SEP ":") # : or empty
SET(CMAKE_SHARED_LIBRARY_CXX_FLAGS "-fPIC") # -pic
SET(CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG "-Wl,+h")
ELSE(CMAKE_COMPILER_IS_GNUCXX)
# for hp aCC
SET(CMAKE_SHARED_LIBRARY_CXX_FLAGS "+Z") # -pic
SET(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS "+Z -Wl,-E -b -L/usr/lib") # -shared
SET(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "-Wl,+s -Wl,-E") # +s, flag for exe link to use shared lib
SET(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS "+Z -Wl,-E -b +nodefaultrpath -L/usr/lib") # -shared
SET(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "-Wl,+s,-E,+nodefaultrpath") # +s, flag for exe link to use shared lib
SET(CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG "-Wl,+b") # -rpath
SET(CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG_SEP ":") # : or empty
SET(CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG "-Wl,+h")
SET(CMAKE_EXECUTABLE_RUNTIME_CXX_FLAG "-Wl,+b") # -rpath
SET (CMAKE_CXX_FLAGS_INIT "")
SET (CMAKE_CXX_FLAGS_DEBUG_INIT "-g")
SET (CMAKE_CXX_FLAGS_MINSIZEREL_INIT "+O3 -DNDEBUG")

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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",

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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;
// Embed runtime search paths if possible and if required.
bool outputRuntime = true;
std::string runtimeFlag;
std::string runtimeSep;
const char* config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE");
const char* linkLanguage =
tgt.GetLinkerLanguage(this->GetGlobalGenerator());
if(!linkLanguage)
cmComputeLinkInformation cli(&tgt, config);
if(!cli.Compute())
{
cmSystemTools::
Error("CMake can not determine linker language for target:",
tgt.GetName());
return false;
}
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());
const char* linkLanguage = cli.GetLinkLanguage();
// Embed runtime search paths if possible and if required.
bool outputRuntime = !this->Makefile->IsOn("CMAKE_SKIP_RPATH");
// Lookup rpath specification flags.
std::string runtimeFlag;
std::string runtimeSep;
if(tgt.GetType() != cmTarget::STATIC_LIBRARY)
{
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());
}
// 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)
// 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))
{
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(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);
}
}
}
}
// Append the link libraries.
for(std::vector<cmStdString>::iterator lib = libNames.begin();
lib != libNames.end(); ++lib)
if(runtimeAlways)
{
linkLibs += *lib;
linkLibs += " ";
// Add runtime paths required by the platform to always be
// present. This is done even when skipping rpath support.
cmSystemTools::ExpandListArgument(runtimeAlways, runtimeDirs);
}
// Convert the runtime directory names for use in the build file.
for(std::vector<std::string>::iterator ri = runtimeDirs.begin();
ri != runtimeDirs.end(); ++ri)
{
*ri = this->Convert(ri->c_str(), FULL, SHELL, false);
}
if(!runtimeDirs.empty())
@ -1714,257 +1711,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,

View File

@ -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);

View File

@ -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";
}

View File

@ -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.

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}
@ -2244,6 +2187,76 @@ void cmTarget::GetExecutableNamesInternal(std::string& name,
pdbName = prefix+base+".pdb";
}
//----------------------------------------------------------------------------
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)

View File

@ -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;

View File

@ -13,7 +13,6 @@ extern "C" {
#include "cmSystemTools.h"
#include "cmDynamicLoader.h"
#include "cmSystemTools.h"
#include "cmOrderLinkDirectories.h"
#include "cmGeneratedFileStream.h"
#include <cmsys/DynamicLoader.hxx>
#else
@ -69,99 +68,6 @@ void cmPassed(const char* Message, const char* m2="")
#endif
#ifdef COMPLEX_TEST_CMAKELIB
// Here is a stupid function that tries to use std::string methods
// so that the dec cxx compiler will instantiate the stuff that
// we are using from the CMakeLib library....
bool TestLibraryOrder(bool shouldFail)
{
std::string Adir = std::string(BINARY_DIR) + std::string("/A");
std::string Bdir = std::string(BINARY_DIR) + std::string("/B");
std::string Cdir = std::string(BINARY_DIR) + std::string("/C");
#ifdef _WIN32
// Avoid case problems for windows paths.
if(Adir[0] >= 'A' && Adir[0] <= 'Z') { Adir[0] += 'a' - 'A'; }
if(Bdir[0] >= 'A' && Bdir[0] <= 'Z') { Bdir[0] += 'a' - 'A'; }
if(Cdir[0] >= 'A' && Cdir[0] <= 'Z') { Cdir[0] += 'a' - 'A'; }
Adir = cmSystemTools::GetActualCaseForPath(Adir.c_str());
Bdir = cmSystemTools::GetActualCaseForPath(Bdir.c_str());
Cdir = cmSystemTools::GetActualCaseForPath(Cdir.c_str());
#endif
if(!shouldFail)
{
std::string rm = Bdir;
rm += "/libA.a";
cmSystemTools::RemoveFile(rm.c_str());
}
std::vector<std::string> linkLibraries;
std::vector<std::string> linkDirectories;
linkDirectories.push_back(Adir);
linkDirectories.push_back(Bdir);
linkDirectories.push_back(Cdir);
linkDirectories.push_back("/lib/extra/stuff");
Adir += "/libA.a";
Bdir += "/libB.a";
Cdir += "/libC.a";
linkLibraries.push_back(Adir);
linkLibraries.push_back(Bdir);
linkLibraries.push_back(Cdir);
linkLibraries.push_back("-lm");
std::vector<cmStdString> sortedpaths;
std::vector<cmStdString> linkItems;
cmOrderLinkDirectories orderLibs;
orderLibs.DebugOn();
orderLibs.AddLinkExtension(".so");
orderLibs.AddLinkExtension(".a");
orderLibs.AddLinkPrefix("lib");
cmTargetManifest manifest;
orderLibs.SetLinkInformation("test", linkLibraries, linkDirectories,
manifest, "");
bool ret = orderLibs.DetermineLibraryPathOrder();
if(!ret)
{
std::cout << orderLibs.GetWarnings() << "\n";
}
orderLibs.GetLinkerInformation(sortedpaths, linkItems);
std::cout << "Sorted Link Paths:\n";
for(std::vector<cmStdString>::iterator i = sortedpaths.begin();
i != sortedpaths.end(); ++i)
{
std::cout << *i << "\n";
}
std::cout << "Link Items: \n";
for(std::vector<cmStdString>::iterator i = linkItems.begin();
i != linkItems.end(); ++i)
{
std::cout << *i << "\n";
}
if(!(linkItems[0] == "A" &&
linkItems[1] == "B" &&
linkItems[2] == "C" &&
linkItems[3] == "-lm" ))
{
std::cout << "fail because link items should be A B C -lm and the are not\n";
return shouldFail;
}
// if this is not the fail test then the order should be f B C A
if(!shouldFail)
{
char order[5];
order[4] = 0;
for(int i =0; i < 4; ++i)
{
order[i] = sortedpaths[i][sortedpaths[i].size()-1];
}
if(!(strcmp(order, "fBCA") == 0 || strcmp(order, "BCAf") == 0))
{
std::cout << "fail because order should be /lib/extra/stuff B C A and it is not\n";
return false;
}
}
return ret;
}
// ======================================================================
void TestAndRemoveFile(const char* filename)
@ -286,6 +192,9 @@ void TestCMGeneratedFileSTream()
}
#endif
// Here is a stupid function that tries to use std::string methods
// so that the dec cxx compiler will instantiate the stuff that
// we are using from the CMakeLib library....
void ForceStringUse()
{
std::vector<std::string> v;
@ -1283,27 +1192,6 @@ int main()
#endif
#ifdef COMPLEX_TEST_CMAKELIB
// first run with shouldFail = true, this will
// run with A B C as set by the CMakeList.txt file.
if(!TestLibraryOrder(true))
{
cmPassed("CMake cmOrderLinkDirectories failed when it should.");
}
else
{
cmFailed("CMake cmOrderLinkDirectories failed to fail when given an impossible set of paths.");
}
// next run with shouldPass = true, this will
// run with B/libA.a removed and should create the order
// B C A
if(TestLibraryOrder(false))
{
cmPassed("CMake cmOrderLinkDirectories worked.");
}
else
{
cmFailed("CMake cmOrderLinkDirectories failed.");
}
// Test the generated file stream.
TestCMGeneratedFileSTream();
#endif

View File

@ -13,7 +13,6 @@ extern "C" {
#include "cmSystemTools.h"
#include "cmDynamicLoader.h"
#include "cmSystemTools.h"
#include "cmOrderLinkDirectories.h"
#include "cmGeneratedFileStream.h"
#include <cmsys/DynamicLoader.hxx>
#else
@ -69,99 +68,6 @@ void cmPassed(const char* Message, const char* m2="")
#endif
#ifdef COMPLEX_TEST_CMAKELIB
// Here is a stupid function that tries to use std::string methods
// so that the dec cxx compiler will instantiate the stuff that
// we are using from the CMakeLib library....
bool TestLibraryOrder(bool shouldFail)
{
std::string Adir = std::string(BINARY_DIR) + std::string("/A");
std::string Bdir = std::string(BINARY_DIR) + std::string("/B");
std::string Cdir = std::string(BINARY_DIR) + std::string("/C");
#ifdef _WIN32
// Avoid case problems for windows paths.
if(Adir[0] >= 'A' && Adir[0] <= 'Z') { Adir[0] += 'a' - 'A'; }
if(Bdir[0] >= 'A' && Bdir[0] <= 'Z') { Bdir[0] += 'a' - 'A'; }
if(Cdir[0] >= 'A' && Cdir[0] <= 'Z') { Cdir[0] += 'a' - 'A'; }
Adir = cmSystemTools::GetActualCaseForPath(Adir.c_str());
Bdir = cmSystemTools::GetActualCaseForPath(Bdir.c_str());
Cdir = cmSystemTools::GetActualCaseForPath(Cdir.c_str());
#endif
if(!shouldFail)
{
std::string rm = Bdir;
rm += "/libA.a";
cmSystemTools::RemoveFile(rm.c_str());
}
std::vector<std::string> linkLibraries;
std::vector<std::string> linkDirectories;
linkDirectories.push_back(Adir);
linkDirectories.push_back(Bdir);
linkDirectories.push_back(Cdir);
linkDirectories.push_back("/lib/extra/stuff");
Adir += "/libA.a";
Bdir += "/libB.a";
Cdir += "/libC.a";
linkLibraries.push_back(Adir);
linkLibraries.push_back(Bdir);
linkLibraries.push_back(Cdir);
linkLibraries.push_back("-lm");
std::vector<cmStdString> sortedpaths;
std::vector<cmStdString> linkItems;
cmOrderLinkDirectories orderLibs;
orderLibs.DebugOn();
orderLibs.AddLinkExtension(".so");
orderLibs.AddLinkExtension(".a");
orderLibs.AddLinkPrefix("lib");
cmTargetManifest manifest;
orderLibs.SetLinkInformation("test", linkLibraries, linkDirectories,
manifest, "");
bool ret = orderLibs.DetermineLibraryPathOrder();
if(!ret)
{
std::cout << orderLibs.GetWarnings() << "\n";
}
orderLibs.GetLinkerInformation(sortedpaths, linkItems);
std::cout << "Sorted Link Paths:\n";
for(std::vector<cmStdString>::iterator i = sortedpaths.begin();
i != sortedpaths.end(); ++i)
{
std::cout << *i << "\n";
}
std::cout << "Link Items: \n";
for(std::vector<cmStdString>::iterator i = linkItems.begin();
i != linkItems.end(); ++i)
{
std::cout << *i << "\n";
}
if(!(linkItems[0] == "A" &&
linkItems[1] == "B" &&
linkItems[2] == "C" &&
linkItems[3] == "-lm" ))
{
std::cout << "fail because link items should be A B C -lm and the are not\n";
return shouldFail;
}
// if this is not the fail test then the order should be f B C A
if(!shouldFail)
{
char order[5];
order[4] = 0;
for(int i =0; i < 4; ++i)
{
order[i] = sortedpaths[i][sortedpaths[i].size()-1];
}
if(!(strcmp(order, "fBCA") == 0 || strcmp(order, "BCAf") == 0))
{
std::cout << "fail because order should be /lib/extra/stuff B C A and it is not\n";
return false;
}
}
return ret;
}
// ======================================================================
void TestAndRemoveFile(const char* filename)
@ -286,6 +192,9 @@ void TestCMGeneratedFileSTream()
}
#endif
// Here is a stupid function that tries to use std::string methods
// so that the dec cxx compiler will instantiate the stuff that
// we are using from the CMakeLib library....
void ForceStringUse()
{
std::vector<std::string> v;
@ -1283,27 +1192,6 @@ int main()
#endif
#ifdef COMPLEX_TEST_CMAKELIB
// first run with shouldFail = true, this will
// run with A B C as set by the CMakeList.txt file.
if(!TestLibraryOrder(true))
{
cmPassed("CMake cmOrderLinkDirectories failed when it should.");
}
else
{
cmFailed("CMake cmOrderLinkDirectories failed to fail when given an impossible set of paths.");
}
// next run with shouldPass = true, this will
// run with B/libA.a removed and should create the order
// B C A
if(TestLibraryOrder(false))
{
cmPassed("CMake cmOrderLinkDirectories worked.");
}
else
{
cmFailed("CMake cmOrderLinkDirectories failed.");
}
// Test the generated file stream.
TestCMGeneratedFileSTream();
#endif

View File

@ -13,7 +13,6 @@ extern "C" {
#include "cmSystemTools.h"
#include "cmDynamicLoader.h"
#include "cmSystemTools.h"
#include "cmOrderLinkDirectories.h"
#include "cmGeneratedFileStream.h"
#include <cmsys/DynamicLoader.hxx>
#else
@ -69,99 +68,6 @@ void cmPassed(const char* Message, const char* m2="")
#endif
#ifdef COMPLEX_TEST_CMAKELIB
// Here is a stupid function that tries to use std::string methods
// so that the dec cxx compiler will instantiate the stuff that
// we are using from the CMakeLib library....
bool TestLibraryOrder(bool shouldFail)
{
std::string Adir = std::string(BINARY_DIR) + std::string("/A");
std::string Bdir = std::string(BINARY_DIR) + std::string("/B");
std::string Cdir = std::string(BINARY_DIR) + std::string("/C");
#ifdef _WIN32
// Avoid case problems for windows paths.
if(Adir[0] >= 'A' && Adir[0] <= 'Z') { Adir[0] += 'a' - 'A'; }
if(Bdir[0] >= 'A' && Bdir[0] <= 'Z') { Bdir[0] += 'a' - 'A'; }
if(Cdir[0] >= 'A' && Cdir[0] <= 'Z') { Cdir[0] += 'a' - 'A'; }
Adir = cmSystemTools::GetActualCaseForPath(Adir.c_str());
Bdir = cmSystemTools::GetActualCaseForPath(Bdir.c_str());
Cdir = cmSystemTools::GetActualCaseForPath(Cdir.c_str());
#endif
if(!shouldFail)
{
std::string rm = Bdir;
rm += "/libA.a";
cmSystemTools::RemoveFile(rm.c_str());
}
std::vector<std::string> linkLibraries;
std::vector<std::string> linkDirectories;
linkDirectories.push_back(Adir);
linkDirectories.push_back(Bdir);
linkDirectories.push_back(Cdir);
linkDirectories.push_back("/lib/extra/stuff");
Adir += "/libA.a";
Bdir += "/libB.a";
Cdir += "/libC.a";
linkLibraries.push_back(Adir);
linkLibraries.push_back(Bdir);
linkLibraries.push_back(Cdir);
linkLibraries.push_back("-lm");
std::vector<cmStdString> sortedpaths;
std::vector<cmStdString> linkItems;
cmOrderLinkDirectories orderLibs;
orderLibs.DebugOn();
orderLibs.AddLinkExtension(".so");
orderLibs.AddLinkExtension(".a");
orderLibs.AddLinkPrefix("lib");
cmTargetManifest manifest;
orderLibs.SetLinkInformation("test", linkLibraries, linkDirectories,
manifest, "");
bool ret = orderLibs.DetermineLibraryPathOrder();
if(!ret)
{
std::cout << orderLibs.GetWarnings() << "\n";
}
orderLibs.GetLinkerInformation(sortedpaths, linkItems);
std::cout << "Sorted Link Paths:\n";
for(std::vector<cmStdString>::iterator i = sortedpaths.begin();
i != sortedpaths.end(); ++i)
{
std::cout << *i << "\n";
}
std::cout << "Link Items: \n";
for(std::vector<cmStdString>::iterator i = linkItems.begin();
i != linkItems.end(); ++i)
{
std::cout << *i << "\n";
}
if(!(linkItems[0] == "A" &&
linkItems[1] == "B" &&
linkItems[2] == "C" &&
linkItems[3] == "-lm" ))
{
std::cout << "fail because link items should be A B C -lm and the are not\n";
return shouldFail;
}
// if this is not the fail test then the order should be f B C A
if(!shouldFail)
{
char order[5];
order[4] = 0;
for(int i =0; i < 4; ++i)
{
order[i] = sortedpaths[i][sortedpaths[i].size()-1];
}
if(!(strcmp(order, "fBCA") == 0 || strcmp(order, "BCAf") == 0))
{
std::cout << "fail because order should be /lib/extra/stuff B C A and it is not\n";
return false;
}
}
return ret;
}
// ======================================================================
void TestAndRemoveFile(const char* filename)
@ -286,6 +192,9 @@ void TestCMGeneratedFileSTream()
}
#endif
// Here is a stupid function that tries to use std::string methods
// so that the dec cxx compiler will instantiate the stuff that
// we are using from the CMakeLib library....
void ForceStringUse()
{
std::vector<std::string> v;
@ -1283,27 +1192,6 @@ int main()
#endif
#ifdef COMPLEX_TEST_CMAKELIB
// first run with shouldFail = true, this will
// run with A B C as set by the CMakeList.txt file.
if(!TestLibraryOrder(true))
{
cmPassed("CMake cmOrderLinkDirectories failed when it should.");
}
else
{
cmFailed("CMake cmOrderLinkDirectories failed to fail when given an impossible set of paths.");
}
// next run with shouldPass = true, this will
// run with B/libA.a removed and should create the order
// B C A
if(TestLibraryOrder(false))
{
cmPassed("CMake cmOrderLinkDirectories worked.");
}
else
{
cmFailed("CMake cmOrderLinkDirectories failed.");
}
// Test the generated file stream.
TestCMGeneratedFileSTream();
#endif

View File

@ -167,7 +167,7 @@ CMAKE_CXX_SOURCES="\
cmDocumentVariables \
cmCacheManager \
cmListFileCache \
cmOrderLinkDirectories \
cmComputeLinkInformation \
"
if ${cmake_system_mingw}; then