mirror of
https://gitlab.kitware.com/cmake/cmake.git
synced 2026-09-25 04:09:36 +03:00
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:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,1157 @@
|
||||
/*=========================================================================
|
||||
|
||||
Program: CMake - Cross-Platform Makefile Generator
|
||||
Module: $RCSfile$
|
||||
Language: C++
|
||||
Date: $Date$
|
||||
Version: $Revision$
|
||||
|
||||
Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
|
||||
See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY; without even
|
||||
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
PURPOSE. See the above copyright notices for more information.
|
||||
|
||||
=========================================================================*/
|
||||
#include "cmComputeLinkInformation.h"
|
||||
|
||||
#include "cmGlobalGenerator.h"
|
||||
#include "cmLocalGenerator.h"
|
||||
#include "cmMakefile.h"
|
||||
#include "cmTarget.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
/*
|
||||
Notes about linking on various platforms:
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
Linux, FreeBSD, Mac OS X, IRIX, Sun, Windows:
|
||||
|
||||
Linking to libraries using the full path works fine.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
On AIX, more work is needed.
|
||||
|
||||
The "-bnoipath" option is needed. From "man ld":
|
||||
|
||||
Note: If you specify a shared object, or an archive file
|
||||
containing a shared object, with an absolute or relative path
|
||||
name, instead of with the -lName flag, the path name is
|
||||
included in the import file ID string in the loader section of
|
||||
the output file. You can override this behavior with the
|
||||
-bnoipath option.
|
||||
|
||||
noipath
|
||||
|
||||
For shared objects listed on the command-line, rather than
|
||||
specified with the -l flag, use a null path component when
|
||||
listing the shared object in the loader section of the
|
||||
output file. A null path component is always used for
|
||||
shared objects specified with the -l flag. This option
|
||||
does not affect the specification of a path component by
|
||||
using a line beginning with #! in an import file. The
|
||||
default is the ipath option.
|
||||
|
||||
This prevents the full path specified on the compile line from being
|
||||
compiled directly into the binary.
|
||||
|
||||
By default the linker places -L paths in the embedded runtime path.
|
||||
In order to implement CMake's RPATH interface correctly, we need the
|
||||
-blibpath:Path option. From "man ld":
|
||||
|
||||
libpath:Path
|
||||
|
||||
Uses Path as the library path when writing the loader section
|
||||
of the output file. Path is neither checked for validity nor
|
||||
used when searching for libraries specified by the -l flag.
|
||||
Path overrides any library paths generated when the -L flag is
|
||||
used.
|
||||
|
||||
If you do not specify any -L flags, or if you specify the
|
||||
nolibpath option, the default library path information is
|
||||
written in the loader section of the output file. The default
|
||||
library path information is the value of the LIBPATH
|
||||
environment variable if it is defined, and /usr/lib:/lib,
|
||||
otherwise.
|
||||
|
||||
We can pass -Wl,-blibpath:/usr/lib:/lib always to avoid the -L stuff
|
||||
and not break when the user sets LIBPATH. Then if we want to add an
|
||||
rpath we insert it into the option before /usr/lib.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
On HP-UX, more work is needed. There are differences between
|
||||
versions.
|
||||
|
||||
ld: 92453-07 linker linker ld B.10.33 990520
|
||||
|
||||
Linking with a full path works okay for static and shared libraries.
|
||||
The linker seems to always put the full path to where the library
|
||||
was found in the binary whether using a full path or -lfoo syntax.
|
||||
Transitive link dependencies work just fine due to the full paths.
|
||||
|
||||
It has the "-l:libfoo.sl" option. The +nodefaultrpath is accepted
|
||||
but not documented and does not seem to do anything. There is no
|
||||
+forceload option.
|
||||
|
||||
ld: 92453-07 linker ld HP Itanium(R) B.12.41 IPF/IPF
|
||||
|
||||
Linking with a full path works okay for static libraries.
|
||||
|
||||
Linking with a full path works okay for shared libraries. However
|
||||
dependent (transitive) libraries of those linked directly must be
|
||||
either found with an rpath stored in the direct dependencies or
|
||||
found in -L paths as if they were specified with "-l:libfoo.sl"
|
||||
(really "-l:<soname>"). The search matches that of the dynamic
|
||||
loader but only with -L paths. In other words, if we have an
|
||||
executable that links to shared library bar which links to shared
|
||||
library foo, the link line for the exe must contain
|
||||
|
||||
/dir/with/bar/libbar.sl -L/dir/with/foo
|
||||
|
||||
It does not matter whether the exe wants to link to foo directly or
|
||||
whether /dir/with/foo/libfoo.sl is listed. The -L path must still
|
||||
be present. It should match the runtime path computed for the
|
||||
executable taking all directly and transitively linked libraries
|
||||
into account.
|
||||
|
||||
The "+nodefaultrpath" option should be used to avoid getting -L
|
||||
paths in the rpath unless we add our own rpath with +b. This means
|
||||
that skip-build-rpath should use this option.
|
||||
|
||||
See documentation in "man ld", "man dld.so", and
|
||||
http://docs.hp.com/en/B2355-90968/creatingandusinglibraries.htm
|
||||
|
||||
+[no]defaultrpath
|
||||
+defaultrpath is the default. Include any paths that are
|
||||
specified with -L in the embedded path, unless you specify the
|
||||
+b option. If you use +b, only the path list specified by +b is
|
||||
in the embedded path.
|
||||
|
||||
The +nodefaultrpath option removes all library paths that were
|
||||
specified with the -L option from the embedded path. The linker
|
||||
searches the library paths specified by the -L option at link
|
||||
time. At run time, the only library paths searched are those
|
||||
specified by the environment variables LD_LIBRARY_PATH and
|
||||
SHLIB_PATH, library paths specified by the +b linker option, and
|
||||
finally the default library paths.
|
||||
|
||||
+rpathfirst
|
||||
This option will cause the paths specified in RPATH (embedded
|
||||
path) to be used before the paths specified in LD_LIBRARY_PATH
|
||||
or SHLIB_PATH, in searching for shared libraries. This changes
|
||||
the default search order of LD_LIBRARY_PATH, SHLIB_PATH, and
|
||||
RPATH (embedded path).
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
cmComputeLinkInformation
|
||||
::cmComputeLinkInformation(cmTarget* target, const char* config)
|
||||
{
|
||||
// Store context information.
|
||||
this->Target = target;
|
||||
this->Makefile = this->Target->GetMakefile();
|
||||
this->LocalGenerator = this->Makefile->GetLocalGenerator();
|
||||
this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator();
|
||||
|
||||
// The configuration being linked.
|
||||
this->Config = config;
|
||||
|
||||
// Get the language used for linking this target.
|
||||
this->LinkLanguage =
|
||||
this->Target->GetLinkerLanguage(this->GlobalGenerator);
|
||||
|
||||
// Check whether we should use an import library for linking a target.
|
||||
this->UseImportLibrary =
|
||||
this->Makefile->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")?true:false;
|
||||
|
||||
// On platforms without import libraries there may be a special flag
|
||||
// to use when creating a plugin (module) that obtains symbols from
|
||||
// the program that will load it.
|
||||
this->LoaderFlag = 0;
|
||||
if(!this->UseImportLibrary &&
|
||||
this->Target->GetType() == cmTarget::MODULE_LIBRARY)
|
||||
{
|
||||
std::string loader_flag_var = "CMAKE_SHARED_MODULE_LOADER_";
|
||||
loader_flag_var += this->LinkLanguage;
|
||||
loader_flag_var += "_FLAG";
|
||||
this->LoaderFlag = this->Makefile->GetDefinition(loader_flag_var.c_str());
|
||||
}
|
||||
|
||||
// Get options needed to link libraries.
|
||||
this->LibLinkFlag =
|
||||
this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_FLAG");
|
||||
this->LibLinkSuffix =
|
||||
this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_SUFFIX");
|
||||
|
||||
// Get link type information.
|
||||
this->ComputeLinkTypeInfo();
|
||||
|
||||
// Setup the link item parser.
|
||||
this->ComputeItemParserInfo();
|
||||
|
||||
// Setup framework support.
|
||||
this->ComputeFrameworkInfo();
|
||||
|
||||
// Initial state.
|
||||
this->RuntimeSearchPathComputed = false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
cmComputeLinkInformation::ItemVector const&
|
||||
cmComputeLinkInformation::GetItems()
|
||||
{
|
||||
return this->Items;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
std::vector<std::string> const& cmComputeLinkInformation::GetDirectories()
|
||||
{
|
||||
return this->Directories;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
std::vector<std::string> const& cmComputeLinkInformation::GetDepends()
|
||||
{
|
||||
return this->Depends;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
std::vector<std::string> const& cmComputeLinkInformation::GetFrameworkPaths()
|
||||
{
|
||||
return this->FrameworkPaths;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool cmComputeLinkInformation::Compute()
|
||||
{
|
||||
// Skip targets that do not link.
|
||||
if(!(this->Target->GetType() == cmTarget::EXECUTABLE ||
|
||||
this->Target->GetType() == cmTarget::SHARED_LIBRARY ||
|
||||
this->Target->GetType() == cmTarget::MODULE_LIBRARY ||
|
||||
this->Target->GetType() == cmTarget::STATIC_LIBRARY))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// We require a link language for the target.
|
||||
if(!this->LinkLanguage)
|
||||
{
|
||||
cmSystemTools::
|
||||
Error("CMake can not determine linker language for target:",
|
||||
this->Target->GetName());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compute which library configuration to link.
|
||||
cmTarget::LinkLibraryType linkType = cmTarget::OPTIMIZED;
|
||||
if(this->Config && cmSystemTools::UpperCase(this->Config) == "DEBUG")
|
||||
{
|
||||
linkType = cmTarget::DEBUG;
|
||||
}
|
||||
|
||||
// Get the list of libraries against which this target wants to link.
|
||||
{
|
||||
const cmTarget::LinkLibraryVectorType& libs =
|
||||
this->Target->GetLinkLibraries();
|
||||
for(cmTarget::LinkLibraryVectorType::const_iterator li = libs.begin();
|
||||
li != libs.end(); ++li)
|
||||
{
|
||||
// Link to a library if it is not the same target and is meant for
|
||||
// this configuration type.
|
||||
if((this->Target->GetType() == cmTarget::EXECUTABLE ||
|
||||
li->first != this->Target->GetName()) &&
|
||||
(li->second == cmTarget::GENERAL || li->second == linkType))
|
||||
{
|
||||
this->AddItem(li->first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Restore the target link type so the correct system runtime
|
||||
// libraries are found.
|
||||
this->SetCurrentLinkType(this->StartLinkType);
|
||||
|
||||
// Compute the linker search path.
|
||||
this->ComputeLinkerSearchDirectories();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void cmComputeLinkInformation::AddItem(std::string const& item)
|
||||
{
|
||||
// Compute the proper name to use to link this library.
|
||||
// TODO: Change third argument to support imported libraries.
|
||||
cmTarget* tgt = this->GlobalGenerator->FindTarget(0, item.c_str(), false);
|
||||
const char* config = this->Config;
|
||||
bool implib = this->UseImportLibrary;
|
||||
bool impexe = (tgt &&
|
||||
tgt->GetType() == cmTarget::EXECUTABLE &&
|
||||
tgt->GetPropertyAsBool("ENABLE_EXPORTS"));
|
||||
if(impexe && !implib && !this->LoaderFlag)
|
||||
{
|
||||
// Skip linking to executables on platforms with no import
|
||||
// libraries or loader flags.
|
||||
return;
|
||||
}
|
||||
|
||||
if(tgt && (tgt->GetType() == cmTarget::STATIC_LIBRARY ||
|
||||
tgt->GetType() == cmTarget::SHARED_LIBRARY ||
|
||||
tgt->GetType() == cmTarget::MODULE_LIBRARY ||
|
||||
impexe))
|
||||
{
|
||||
// This is a CMake target. Ask the target for its real name.
|
||||
if(impexe && this->LoaderFlag)
|
||||
{
|
||||
// This link item is an executable that may provide symbols
|
||||
// used by this target. A special flag is needed on this
|
||||
// platform. Add it now.
|
||||
std::string linkItem;
|
||||
linkItem = this->LoaderFlag;
|
||||
std::string exe = tgt->GetFullPath(config, implib);
|
||||
linkItem += exe;
|
||||
this->Items.push_back(Item(linkItem, true));
|
||||
this->Depends.push_back(exe);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Pass the full path to the target file.
|
||||
std::string lib = tgt->GetFullPath(config, implib);
|
||||
this->Depends.push_back(lib);
|
||||
#ifdef __APPLE__
|
||||
if(tgt->GetType() == cmTarget::SHARED_LIBRARY &&
|
||||
tgt->GetPropertyAsBool("FRAMEWORK"))
|
||||
{
|
||||
// Frameworks on OS X need only the framework directory to
|
||||
// link.
|
||||
std::string fw = tgt->GetDirectory(config, implib);
|
||||
this->AddFrameworkItem(fw);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
this->Items.push_back(Item(lib, true));
|
||||
this->AddLibraryRuntimeInfo(lib, tgt);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is not a CMake target. Use the name given.
|
||||
if(cmSystemTools::FileIsFullPath(item.c_str()))
|
||||
{
|
||||
if(cmSystemTools::FileIsDirectory(item.c_str()))
|
||||
{
|
||||
// This is a directory.
|
||||
this->AddDirectoryItem(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use the full path given to the library file.
|
||||
this->Items.push_back(Item(item, true));
|
||||
this->Depends.push_back(item);
|
||||
this->AddLibraryRuntimeInfo(item);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is a library or option specified by the user.
|
||||
this->AddUserItem(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void cmComputeLinkInformation::ComputeLinkTypeInfo()
|
||||
{
|
||||
// First assume we cannot do link type stuff.
|
||||
this->LinkTypeEnabled = false;
|
||||
|
||||
// Lookup link type selection flags.
|
||||
const char* static_link_type_flag = 0;
|
||||
const char* shared_link_type_flag = 0;
|
||||
const char* target_type_str = 0;
|
||||
switch(this->Target->GetType())
|
||||
{
|
||||
case cmTarget::EXECUTABLE: target_type_str = "EXE"; break;
|
||||
case cmTarget::SHARED_LIBRARY: target_type_str = "SHARED_LIBRARY"; break;
|
||||
case cmTarget::MODULE_LIBRARY: target_type_str = "SHARED_MODULE"; break;
|
||||
default: break;
|
||||
}
|
||||
if(target_type_str)
|
||||
{
|
||||
std::string static_link_type_flag_var = "CMAKE_";
|
||||
static_link_type_flag_var += target_type_str;
|
||||
static_link_type_flag_var += "_LINK_STATIC_";
|
||||
static_link_type_flag_var += this->LinkLanguage;
|
||||
static_link_type_flag_var += "_FLAGS";
|
||||
static_link_type_flag =
|
||||
this->Makefile->GetDefinition(static_link_type_flag_var.c_str());
|
||||
|
||||
std::string shared_link_type_flag_var = "CMAKE_";
|
||||
shared_link_type_flag_var += target_type_str;
|
||||
shared_link_type_flag_var += "_LINK_DYNAMIC_";
|
||||
shared_link_type_flag_var += this->LinkLanguage;
|
||||
shared_link_type_flag_var += "_FLAGS";
|
||||
shared_link_type_flag =
|
||||
this->Makefile->GetDefinition(shared_link_type_flag_var.c_str());
|
||||
}
|
||||
|
||||
// We can support link type switching only if all needed flags are
|
||||
// known.
|
||||
if(static_link_type_flag && *static_link_type_flag &&
|
||||
shared_link_type_flag && *shared_link_type_flag)
|
||||
{
|
||||
this->LinkTypeEnabled = true;
|
||||
this->StaticLinkTypeFlag = static_link_type_flag;
|
||||
this->SharedLinkTypeFlag = shared_link_type_flag;
|
||||
}
|
||||
|
||||
// TODO: Lookup the starting link type from the target (is it being
|
||||
// linked statically?).
|
||||
this->StartLinkType = LinkShared;
|
||||
this->CurrentLinkType = this->StartLinkType;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void cmComputeLinkInformation::ComputeItemParserInfo()
|
||||
{
|
||||
// Get possible library name prefixes.
|
||||
cmMakefile* mf = this->Makefile;
|
||||
this->AddLinkPrefix(mf->GetDefinition("CMAKE_STATIC_LIBRARY_PREFIX"));
|
||||
this->AddLinkPrefix(mf->GetDefinition("CMAKE_SHARED_LIBRARY_PREFIX"));
|
||||
|
||||
// Import library names should be matched and treated as shared
|
||||
// libraries for the purposes of linking.
|
||||
this->AddLinkExtension(mf->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX"),
|
||||
LinkShared);
|
||||
this->AddLinkExtension(mf->GetDefinition("CMAKE_STATIC_LIBRARY_SUFFIX"),
|
||||
LinkStatic);
|
||||
this->AddLinkExtension(mf->GetDefinition("CMAKE_SHARED_LIBRARY_SUFFIX"),
|
||||
LinkShared);
|
||||
this->AddLinkExtension(mf->GetDefinition("CMAKE_LINK_LIBRARY_SUFFIX"),
|
||||
LinkUnknown);
|
||||
if(const char* linkSuffixes =
|
||||
mf->GetDefinition("CMAKE_EXTRA_LINK_EXTENSIONS"))
|
||||
{
|
||||
std::vector<std::string> linkSuffixVec;
|
||||
cmSystemTools::ExpandListArgument(linkSuffixes, linkSuffixVec);
|
||||
for(std::vector<std::string>::iterator i = linkSuffixVec.begin();
|
||||
i != linkSuffixVec.end(); ++i)
|
||||
{
|
||||
this->AddLinkExtension(i->c_str(), LinkUnknown);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute a regex to match link extensions.
|
||||
std::string libext = this->CreateExtensionRegex(this->LinkExtensions);
|
||||
|
||||
// Create regex to remove any library extension.
|
||||
std::string reg("(.*)");
|
||||
reg += libext;
|
||||
this->RemoveLibraryExtension.compile(reg.c_str());
|
||||
|
||||
// Create a regex to match a library name. Match index 1 will be
|
||||
// the prefix if it exists and empty otherwise. Match index 2 will
|
||||
// be the library name. Match index 3 will be the library
|
||||
// extension.
|
||||
reg = "^(";
|
||||
for(std::set<cmStdString>::iterator p = this->LinkPrefixes.begin();
|
||||
p != this->LinkPrefixes.end(); ++p)
|
||||
{
|
||||
reg += *p;
|
||||
reg += "|";
|
||||
}
|
||||
reg += ")";
|
||||
reg += "([^/]*)";
|
||||
|
||||
// Create a regex to match any library name.
|
||||
std::string reg_any = reg;
|
||||
reg_any += libext;
|
||||
#ifdef CM_COMPUTE_LINK_INFO_DEBUG
|
||||
fprintf(stderr, "any regex [%s]\n", reg_any.c_str());
|
||||
#endif
|
||||
this->ExtractAnyLibraryName.compile(reg_any.c_str());
|
||||
|
||||
// Create a regex to match static library names.
|
||||
if(!this->StaticLinkExtensions.empty())
|
||||
{
|
||||
std::string reg_static = reg;
|
||||
reg_static += this->CreateExtensionRegex(this->StaticLinkExtensions);
|
||||
#ifdef CM_COMPUTE_LINK_INFO_DEBUG
|
||||
fprintf(stderr, "static regex [%s]\n", reg_static.c_str());
|
||||
#endif
|
||||
this->ExtractStaticLibraryName.compile(reg_static.c_str());
|
||||
}
|
||||
|
||||
// Create a regex to match shared library names.
|
||||
if(!this->SharedLinkExtensions.empty())
|
||||
{
|
||||
std::string reg_shared = reg;
|
||||
reg_shared += this->CreateExtensionRegex(this->SharedLinkExtensions);
|
||||
#ifdef CM_COMPUTE_LINK_INFO_DEBUG
|
||||
fprintf(stderr, "shared regex [%s]\n", reg_shared.c_str());
|
||||
#endif
|
||||
this->ExtractSharedLibraryName.compile(reg_shared.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void cmComputeLinkInformation::AddLinkPrefix(const char* p)
|
||||
{
|
||||
if(p)
|
||||
{
|
||||
this->LinkPrefixes.insert(p);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void cmComputeLinkInformation::AddLinkExtension(const char* e, LinkType type)
|
||||
{
|
||||
if(e && *e)
|
||||
{
|
||||
if(type == LinkStatic)
|
||||
{
|
||||
this->StaticLinkExtensions.push_back(e);
|
||||
}
|
||||
if(type == LinkShared)
|
||||
{
|
||||
this->SharedLinkExtensions.push_back(e);
|
||||
}
|
||||
this->LinkExtensions.push_back(e);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
std::string
|
||||
cmComputeLinkInformation
|
||||
::CreateExtensionRegex(std::vector<std::string> const& exts)
|
||||
{
|
||||
// Build a list of extension choices.
|
||||
std::string libext = "(";
|
||||
const char* sep = "";
|
||||
for(std::vector<std::string>::const_iterator i = exts.begin();
|
||||
i != exts.end(); ++i)
|
||||
{
|
||||
// Separate this choice from the previous one.
|
||||
libext += sep;
|
||||
sep = "|";
|
||||
|
||||
// Store this extension choice with the "." escaped.
|
||||
libext += "\\";
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
libext += this->NoCaseExpression(i->c_str());
|
||||
#else
|
||||
libext += *i;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Finish the list.
|
||||
libext += ").*";
|
||||
return libext;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
std::string cmComputeLinkInformation::NoCaseExpression(const char* str)
|
||||
{
|
||||
std::string ret;
|
||||
const char* s = str;
|
||||
while(*s)
|
||||
{
|
||||
if(*s == '.')
|
||||
{
|
||||
ret += *s;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret += "[";
|
||||
ret += tolower(*s);
|
||||
ret += toupper(*s);
|
||||
ret += "]";
|
||||
}
|
||||
s++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
void cmComputeLinkInformation::SetCurrentLinkType(LinkType lt)
|
||||
{
|
||||
// If we are changing the current link type add the flag to tell the
|
||||
// linker about it.
|
||||
if(this->CurrentLinkType != lt)
|
||||
{
|
||||
this->CurrentLinkType = lt;
|
||||
|
||||
if(this->LinkTypeEnabled)
|
||||
{
|
||||
switch(this->CurrentLinkType)
|
||||
{
|
||||
case LinkStatic:
|
||||
this->Items.push_back(Item(this->StaticLinkTypeFlag, false));
|
||||
break;
|
||||
case LinkShared:
|
||||
this->Items.push_back(Item(this->SharedLinkTypeFlag, false));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void cmComputeLinkInformation::AddUserItem(std::string const& item)
|
||||
{
|
||||
// This is called to handle a link item that does not match a CMake
|
||||
// target and is not a full path. We check here if it looks like a
|
||||
// library file name to automatically request the proper link type
|
||||
// from the linker. For example:
|
||||
//
|
||||
// foo ==> -lfoo
|
||||
// libfoo.a ==> -Wl,-Bstatic -lfoo
|
||||
std::string lib;
|
||||
|
||||
// Parse out the prefix, base, and suffix components of the
|
||||
// library name. If the name matches that of a shared or static
|
||||
// library then set the link type accordingly.
|
||||
//
|
||||
// Search for shared library names first because some platforms
|
||||
// have shared libraries with names that match the static library
|
||||
// pattern. For example cygwin and msys use the convention
|
||||
// libfoo.dll.a for import libraries and libfoo.a for static
|
||||
// libraries. On AIX a library with the name libfoo.a can be
|
||||
// shared!
|
||||
if(this->ExtractSharedLibraryName.find(item))
|
||||
{
|
||||
// This matches a shared library file name.
|
||||
#ifdef CM_COMPUTE_LINK_INFO_DEBUG
|
||||
fprintf(stderr, "shared regex matched [%s] [%s] [%s]\n",
|
||||
this->ExtractSharedLibraryName.match(1).c_str(),
|
||||
this->ExtractSharedLibraryName.match(2).c_str(),
|
||||
this->ExtractSharedLibraryName.match(3).c_str());
|
||||
#endif
|
||||
// Set the link type to shared.
|
||||
this->SetCurrentLinkType(LinkShared);
|
||||
|
||||
// Use just the library name so the linker will search.
|
||||
lib = this->ExtractSharedLibraryName.match(2);
|
||||
}
|
||||
else if(this->ExtractStaticLibraryName.find(item))
|
||||
{
|
||||
// This matches a static library file name.
|
||||
#ifdef CM_COMPUTE_LINK_INFO_DEBUG
|
||||
fprintf(stderr, "static regex matched [%s] [%s] [%s]\n",
|
||||
this->ExtractStaticLibraryName.match(1).c_str(),
|
||||
this->ExtractStaticLibraryName.match(2).c_str(),
|
||||
this->ExtractStaticLibraryName.match(3).c_str());
|
||||
#endif
|
||||
// Set the link type to static.
|
||||
this->SetCurrentLinkType(LinkStatic);
|
||||
|
||||
// Use just the library name so the linker will search.
|
||||
lib = this->ExtractStaticLibraryName.match(2);
|
||||
}
|
||||
else if(this->ExtractAnyLibraryName.find(item))
|
||||
{
|
||||
// This matches a library file name.
|
||||
#ifdef CM_COMPUTE_LINK_INFO_DEBUG
|
||||
fprintf(stderr, "any regex matched [%s] [%s] [%s]\n",
|
||||
this->ExtractAnyLibraryName.match(1).c_str(),
|
||||
this->ExtractAnyLibraryName.match(2).c_str(),
|
||||
this->ExtractAnyLibraryName.match(3).c_str());
|
||||
#endif
|
||||
// Restore the target link type since this item does not specify
|
||||
// one.
|
||||
this->SetCurrentLinkType(this->StartLinkType);
|
||||
|
||||
// Use just the library name so the linker will search.
|
||||
lib = this->ExtractAnyLibraryName.match(2);
|
||||
}
|
||||
else if(item[0] == '-' || item[0] == '$' || item[0] == '`')
|
||||
{
|
||||
// This is a linker option provided by the user. Restore the
|
||||
// target link type since this item does not specify one.
|
||||
this->SetCurrentLinkType(this->StartLinkType);
|
||||
|
||||
// Use the item verbatim.
|
||||
this->Items.push_back(Item(item, false));
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is a name specified by the user. We must ask the linker
|
||||
// to search for a library with this name. Restore the target
|
||||
// link type since this item does not specify one.
|
||||
this->SetCurrentLinkType(this->StartLinkType);
|
||||
lib = item;
|
||||
}
|
||||
|
||||
// Create an option to ask the linker to search for the library.
|
||||
std::string out = this->LibLinkFlag;
|
||||
out += lib;
|
||||
out += this->LibLinkSuffix;
|
||||
this->Items.push_back(Item(out, false));
|
||||
|
||||
// Here we could try to find the library the linker will find and
|
||||
// add a runtime information entry for it. It would probably not be
|
||||
// reliable and we want to encourage use of full paths for library
|
||||
// specification.
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void cmComputeLinkInformation::AddFrameworkItem(std::string const& item)
|
||||
{
|
||||
// Try to separate the framework name and path.
|
||||
if(!this->SplitFramework.find(item.c_str()))
|
||||
{
|
||||
cmOStringStream e;
|
||||
e << "Could not parse framework path \"" << item << "\" "
|
||||
<< "linked by target " << this->Target->GetName() << ".";
|
||||
cmSystemTools::Error(e.str().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Add the directory portion to the framework search path.
|
||||
this->AddFrameworkPath(this->SplitFramework.match(1));
|
||||
|
||||
// Add the item using the -framework option.
|
||||
std::string fw = "-framework ";
|
||||
fw += this->SplitFramework.match(2);
|
||||
this->Items.push_back(Item(fw, false));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void cmComputeLinkInformation::AddDirectoryItem(std::string const& item)
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
if(cmSystemTools::IsPathToFramework(item.c_str()))
|
||||
{
|
||||
this->AddFrameworkItem(item);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
this->DropDirectoryItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void cmComputeLinkInformation::DropDirectoryItem(std::string const& item)
|
||||
{
|
||||
// A full path to a directory was found as a link item. Warn the
|
||||
// user.
|
||||
cmOStringStream e;
|
||||
e << "WARNING: Target \"" << this->Target->GetName()
|
||||
<< "\" requests linking to directory \"" << item << "\". "
|
||||
<< "Targets may link only to libraries. "
|
||||
<< "CMake is dropping the item.";
|
||||
cmSystemTools::Message(e.str().c_str());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void cmComputeLinkInformation::ComputeFrameworkInfo()
|
||||
{
|
||||
// Avoid adding system framework paths. See "man ld" on OS X.
|
||||
this->FrameworkPathsEmmitted.insert("/Library/Frameworks");
|
||||
this->FrameworkPathsEmmitted.insert("/Network/Library/Frameworks");
|
||||
this->FrameworkPathsEmmitted.insert("/System/Library/Frameworks");
|
||||
|
||||
// Regular expression to extract a framework path and name.
|
||||
this->SplitFramework.compile("(.*)/(.*)\\.framework$");
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void cmComputeLinkInformation::AddFrameworkPath(std::string const& p)
|
||||
{
|
||||
if(this->FrameworkPathsEmmitted.insert(p).second)
|
||||
{
|
||||
this->FrameworkPaths.push_back(p);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void cmComputeLinkInformation::ComputeLinkerSearchDirectories()
|
||||
{
|
||||
// Some search paths should never be emitted.
|
||||
this->DirectoriesEmmitted.insert("");
|
||||
if(const char* implicitLinks =
|
||||
(this->Makefile->GetDefinition
|
||||
("CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES")))
|
||||
{
|
||||
std::vector<std::string> implicitLinkVec;
|
||||
cmSystemTools::ExpandListArgument(implicitLinks, implicitLinkVec);
|
||||
for(std::vector<std::string>::const_iterator
|
||||
i = implicitLinkVec.begin();
|
||||
i != implicitLinkVec.end(); ++i)
|
||||
{
|
||||
this->DirectoriesEmmitted.insert(*i);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we need to include the runtime search path at link time.
|
||||
std::string var = "CMAKE_SHARED_LIBRARY_LINK_";
|
||||
var += this->LinkLanguage;
|
||||
var += "_WITH_RUNTIME_PATH";
|
||||
if(this->Makefile->IsOn(var.c_str()))
|
||||
{
|
||||
// This platform requires the runtime library path for shared
|
||||
// libraries to be specified at link time as -L paths. It needs
|
||||
// them so that transitive dependencies of the libraries linked
|
||||
// may be found by the linker.
|
||||
this->AddLinkerSearchDirectories(this->GetRuntimeSearchPath());
|
||||
}
|
||||
|
||||
// Get the search path entries requested by the user.
|
||||
this->AddLinkerSearchDirectories(this->Target->GetLinkDirectories());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void
|
||||
cmComputeLinkInformation
|
||||
::AddLinkerSearchDirectories(std::vector<std::string> const& dirs)
|
||||
{
|
||||
for(std::vector<std::string>::const_iterator i = dirs.begin();
|
||||
i != dirs.end(); ++i)
|
||||
{
|
||||
if(this->DirectoriesEmmitted.insert(*i).second)
|
||||
{
|
||||
this->Directories.push_back(*i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
std::vector<std::string> const&
|
||||
cmComputeLinkInformation::GetRuntimeSearchPath()
|
||||
{
|
||||
if(!this->RuntimeSearchPathComputed)
|
||||
{
|
||||
this->RuntimeSearchPathComputed = true;
|
||||
this->CollectRuntimeDirectories();
|
||||
this->FindConflictingLibraries();
|
||||
this->OrderRuntimeSearchPath();
|
||||
}
|
||||
return this->RuntimeSearchPath;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// Directory ordering computation.
|
||||
// - Useful to compute a safe runtime library path order
|
||||
// - Need runtime path for supporting INSTALL_RPATH_USE_LINK_PATH
|
||||
// - Need runtime path at link time to pickup transitive link dependencies
|
||||
// for shared libraries (in future when we do not always add them).
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void
|
||||
cmComputeLinkInformation::AddLibraryRuntimeInfo(std::string const& fullPath,
|
||||
cmTarget* target)
|
||||
{
|
||||
// Skip targets that are not shared libraries (modules cannot be linked).
|
||||
if(target->GetType() != cmTarget::SHARED_LIBRARY)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to get the soname of the library. Only files with this name
|
||||
// could possibly conflict.
|
||||
std::string soName;
|
||||
const char* soname = 0;
|
||||
if(!target->IsImported())
|
||||
{
|
||||
std::string name;
|
||||
std::string realName;
|
||||
std::string impName;
|
||||
std::string pdbName;
|
||||
target->GetLibraryNames(name, soName, realName, impName, pdbName,
|
||||
this->Config);
|
||||
soname = soName.c_str();
|
||||
}
|
||||
|
||||
// Add the library runtime entry.
|
||||
this->AddLibraryRuntimeInfo(fullPath, soname);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void
|
||||
cmComputeLinkInformation::AddLibraryRuntimeInfo(std::string const& fullPath,
|
||||
const char* soname)
|
||||
{
|
||||
// Get the name of the library from the file name.
|
||||
std::string file = cmSystemTools::GetFilenameName(fullPath);
|
||||
if(!this->ExtractSharedLibraryName.find(file.c_str()))
|
||||
{
|
||||
// This is not the name of a shared library.
|
||||
return;
|
||||
}
|
||||
|
||||
// Add the runtime information at most once.
|
||||
if(this->LibraryRuntimeInfoEmmitted.insert(fullPath).second)
|
||||
{
|
||||
// Construct the runtime information entry for this library.
|
||||
LibraryRuntimeEntry entry;
|
||||
entry.FileName = cmSystemTools::GetFilenameName(fullPath);
|
||||
entry.SOName = soname? soname : "";
|
||||
entry.Directory = cmSystemTools::GetFilenamePath(fullPath);
|
||||
this->LibraryRuntimeInfo.push_back(entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
// This can happen if the same library is linked multiple times.
|
||||
// In that case the runtime information check need be done only
|
||||
// once anyway. For shared libs we could add a check in AddItem
|
||||
// to not repeat them.
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void cmComputeLinkInformation::CollectRuntimeDirectories()
|
||||
{
|
||||
// Get all directories that should be in the runtime search path.
|
||||
|
||||
// Add directories containing libraries linked with full path.
|
||||
for(std::vector<LibraryRuntimeEntry>::iterator
|
||||
ei = this->LibraryRuntimeInfo.begin();
|
||||
ei != this->LibraryRuntimeInfo.end(); ++ei)
|
||||
{
|
||||
ei->DirectoryIndex = this->AddRuntimeDirectory(ei->Directory);
|
||||
}
|
||||
|
||||
// Add link directories specified for the target.
|
||||
std::vector<std::string> const& dirs = this->GetDirectories();
|
||||
for(std::vector<std::string>::const_iterator di = dirs.begin();
|
||||
di != dirs.end(); ++di)
|
||||
{
|
||||
this->AddRuntimeDirectory(*di);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
int cmComputeLinkInformation::AddRuntimeDirectory(std::string const& dir)
|
||||
{
|
||||
// Add the runtime directory with a unique index.
|
||||
std::map<cmStdString, int>::iterator i =
|
||||
this->RuntimeDirectoryIndex.find(dir);
|
||||
if(i == this->RuntimeDirectoryIndex.end())
|
||||
{
|
||||
std::map<cmStdString, int>::value_type
|
||||
entry(dir, static_cast<int>(this->RuntimeDirectories.size()));
|
||||
i = this->RuntimeDirectoryIndex.insert(entry).first;
|
||||
this->RuntimeDirectories.push_back(dir);
|
||||
}
|
||||
|
||||
return i->second;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
struct cmCLIRuntimeConflictCompare
|
||||
{
|
||||
typedef std::pair<int, int> RuntimeConflictPair;
|
||||
|
||||
// The conflict pair is unique based on just the directory
|
||||
// (first). The second element is only used for displaying
|
||||
// information about why the entry is present.
|
||||
bool operator()(RuntimeConflictPair const& l,
|
||||
RuntimeConflictPair const& r)
|
||||
{
|
||||
return l.first == r.first;
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void cmComputeLinkInformation::FindConflictingLibraries()
|
||||
{
|
||||
// Allocate the conflict graph.
|
||||
this->RuntimeConflictGraph.resize(this->RuntimeDirectories.size());
|
||||
this->RuntimeDirectoryVisited.resize(this->RuntimeDirectories.size(), 0);
|
||||
|
||||
// Find all runtime directories providing each library.
|
||||
for(unsigned int lri = 0; lri < this->LibraryRuntimeInfo.size(); ++lri)
|
||||
{
|
||||
this->FindDirectoriesForLib(lri);
|
||||
}
|
||||
|
||||
// Clean up the conflict graph representation.
|
||||
for(std::vector<RuntimeConflictList>::iterator
|
||||
i = this->RuntimeConflictGraph.begin();
|
||||
i != this->RuntimeConflictGraph.end(); ++i)
|
||||
{
|
||||
// Sort the outgoing edges for each graph node so that the
|
||||
// original order will be preserved as much as possible.
|
||||
std::sort(i->begin(), i->end());
|
||||
|
||||
// Make the edge list unique so cycle detection will be reliable.
|
||||
RuntimeConflictList::iterator last =
|
||||
std::unique(i->begin(), i->end(), cmCLIRuntimeConflictCompare());
|
||||
i->erase(last, i->end());
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void cmComputeLinkInformation::FindDirectoriesForLib(unsigned int lri)
|
||||
{
|
||||
// Search through the runtime directories to find those providing
|
||||
// this library.
|
||||
LibraryRuntimeEntry& re = this->LibraryRuntimeInfo[lri];
|
||||
for(unsigned int i = 0; i < this->RuntimeDirectories.size(); ++i)
|
||||
{
|
||||
// Skip the directory that is supposed to provide the library.
|
||||
if(this->RuntimeDirectories[i] == re.Directory)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Determine which type of check to do.
|
||||
if(!re.SOName.empty())
|
||||
{
|
||||
// We have the library soname. Check if it will be found.
|
||||
std::string file = this->RuntimeDirectories[i];
|
||||
file += "/";
|
||||
file += re.SOName;
|
||||
std::set<cmStdString> const& files =
|
||||
(this->GlobalGenerator
|
||||
->GetDirectoryContent(this->RuntimeDirectories[i], false));
|
||||
if(files.find(re.SOName) != files.end() ||
|
||||
cmSystemTools::FileExists(file.c_str(), true))
|
||||
{
|
||||
// The library will be found in this directory but this is not
|
||||
// the directory named for it. Add an entry to make sure the
|
||||
// desired directory comes before this one.
|
||||
RuntimeConflictPair p(re.DirectoryIndex, lri);
|
||||
this->RuntimeConflictGraph[i].push_back(p);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// We do not have the soname. Look for files in the directory
|
||||
// that may conflict.
|
||||
std::set<cmStdString> const& files =
|
||||
(this->GlobalGenerator
|
||||
->GetDirectoryContent(this->RuntimeDirectories[i], true));
|
||||
|
||||
// Get the extension which should appear in the soname.
|
||||
std::string ext =
|
||||
cmSystemTools::GetFilenameLastExtension(re.FileName);
|
||||
|
||||
// Get the set of files that might conflict.
|
||||
std::string base =
|
||||
cmSystemTools::GetFilenameWithoutLastExtension(re.FileName);
|
||||
std::set<cmStdString>::const_iterator first = files.lower_bound(base);
|
||||
++base[base.size()-1];
|
||||
std::set<cmStdString>::const_iterator last = files.upper_bound(base);
|
||||
bool found = false;
|
||||
for(std::set<cmStdString>::const_iterator fi = first;
|
||||
!found && fi != last; ++fi)
|
||||
{
|
||||
// This file name starts with the name of the library file.
|
||||
// If the name also contains the extension then this is
|
||||
// possibly an soname of the library.
|
||||
if(fi->find(ext, base.size()) != fi->npos)
|
||||
{
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(found)
|
||||
{
|
||||
// The library may be found in this directory but this is not
|
||||
// the directory named for it. Add an entry to make sure the
|
||||
// desired directory comes before this one.
|
||||
RuntimeConflictPair p(re.DirectoryIndex, lri);
|
||||
this->RuntimeConflictGraph[i].push_back(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void cmComputeLinkInformation::OrderRuntimeSearchPath()
|
||||
{
|
||||
// Allow a cycle to be diagnosed once.
|
||||
this->CycleDiagnosed = false;
|
||||
|
||||
// Iterate through the directories in the original order.
|
||||
for(unsigned int i=0; i < this->RuntimeDirectories.size(); ++i)
|
||||
{
|
||||
this->VisitRuntimeDirectory(i, true);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void cmComputeLinkInformation::VisitRuntimeDirectory(unsigned int i,
|
||||
bool top)
|
||||
{
|
||||
// Skip nodes already visited.
|
||||
if(this->RuntimeDirectoryVisited[i])
|
||||
{
|
||||
if(!top)
|
||||
{
|
||||
// We have reached a previously visited node but were not called
|
||||
// to start a new section of the graph. There is a cycle.
|
||||
this->DiagnoseCycle();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// We are not visiting this node so mark it.
|
||||
this->RuntimeDirectoryVisited[i] = 1;
|
||||
|
||||
// Visit the neighbors of the node first.
|
||||
RuntimeConflictList const& clist = this->RuntimeConflictGraph[i];
|
||||
for(RuntimeConflictList::const_iterator j = clist.begin();
|
||||
j != clist.end(); ++j)
|
||||
{
|
||||
this->VisitRuntimeDirectory(j->first, false);
|
||||
}
|
||||
|
||||
// Now that all directories required to come before this one have
|
||||
// been emmitted, emit this directory.
|
||||
this->RuntimeSearchPath.push_back(this->RuntimeDirectories[i]);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void cmComputeLinkInformation::DiagnoseCycle()
|
||||
{
|
||||
// Report the cycle at most once.
|
||||
if(this->CycleDiagnosed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
this->CycleDiagnosed = true;
|
||||
|
||||
// Construct the message.
|
||||
cmOStringStream e;
|
||||
e << "WARNING: Cannot generate a safe runtime path for target "
|
||||
<< this->Target->GetName()
|
||||
<< " because there is a cycle in the constraint graph:\n";
|
||||
|
||||
// Clean up the conflict graph representation.
|
||||
for(unsigned int i=0; i < this->RuntimeConflictGraph.size(); ++i)
|
||||
{
|
||||
RuntimeConflictList const& clist = this->RuntimeConflictGraph[i];
|
||||
e << "dir " << i << " is [" << this->RuntimeDirectories[i] << "]\n";
|
||||
for(RuntimeConflictList::const_iterator j = clist.begin();
|
||||
j != clist.end(); ++j)
|
||||
{
|
||||
e << " dir " << j->first << " must precede it due to [";
|
||||
LibraryRuntimeEntry const& re = this->LibraryRuntimeInfo[j->second];
|
||||
if(re.SOName.empty())
|
||||
{
|
||||
e << re.FileName;
|
||||
}
|
||||
else
|
||||
{
|
||||
e << re.SOName;
|
||||
}
|
||||
e << "]\n";
|
||||
}
|
||||
}
|
||||
cmSystemTools::Message(e.str().c_str());
|
||||
}
|
||||
@@ -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
|
||||
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+114
-368
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
+72
-59
@@ -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)
|
||||
|
||||
+4
-2
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user