浏览代码

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.
Brad King 18 年之前
父节点
当前提交
96fd5909d9

+ 8 - 0
Modules/CMakeCInformation.cmake

@@ -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>")
     "<CMAKE_C_COMPILER> <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS>  -o <TARGET> <LINK_LIBRARIES>")
 ENDIF(NOT CMAKE_C_LINK_EXECUTABLE)
 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(
 MARK_AS_ADVANCED(
 CMAKE_C_FLAGS
 CMAKE_C_FLAGS
 CMAKE_C_FLAGS_DEBUG
 CMAKE_C_FLAGS_DEBUG

+ 12 - 0
Modules/CMakeCXXInformation.cmake

@@ -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})
   SET(CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP})
 ENDIF(NOT CMAKE_SHARED_LIBRARY_RUNTIME_CXX_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)
 IF(NOT CMAKE_INCLUDE_FLAG_CXX)
   SET(CMAKE_INCLUDE_FLAG_CXX ${CMAKE_INCLUDE_FLAG_C})
   SET(CMAKE_INCLUDE_FLAG_CXX ${CMAKE_INCLUDE_FLAG_C})
 ENDIF(NOT CMAKE_INCLUDE_FLAG_CXX)
 ENDIF(NOT CMAKE_INCLUDE_FLAG_CXX)

+ 12 - 0
Modules/CMakeFortranInformation.cmake

@@ -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})
   SET(CMAKE_SHARED_MODULE_RUNTIME_Fortran_FLAG_SEP ${CMAKE_SHARED_MODULE_RUNTIME_C_FLAG_SEP})
 ENDIF(NOT CMAKE_SHARED_MODULE_RUNTIME_Fortran_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)
 IF(NOT CMAKE_INCLUDE_FLAG_Fortran)
   SET(CMAKE_INCLUDE_FLAG_Fortran ${CMAKE_INCLUDE_FLAG_C})
   SET(CMAKE_INCLUDE_FLAG_Fortran ${CMAKE_INCLUDE_FLAG_C})
 ENDIF(NOT CMAKE_INCLUDE_FLAG_Fortran)
 ENDIF(NOT CMAKE_INCLUDE_FLAG_Fortran)

+ 14 - 6
Modules/Platform/AIX.cmake

@@ -1,15 +1,23 @@
 SET(CMAKE_SHARED_LIBRARY_PREFIX "lib")          # lib
 SET(CMAKE_SHARED_LIBRARY_PREFIX "lib")          # lib
 SET(CMAKE_SHARED_LIBRARY_SUFFIX ".so")          # .so
 SET(CMAKE_SHARED_LIBRARY_SUFFIX ".so")          # .so
 SET(CMAKE_DL_LIBS "-lld")
 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
 # CXX Compiler
 IF(CMAKE_COMPILER_IS_GNUCXX) 
 IF(CMAKE_COMPILER_IS_GNUCXX) 
   SET(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS "-shared -Wl,-G")       # -shared
   SET(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS "-shared -Wl,-G")       # -shared
 ELSE(CMAKE_COMPILER_IS_GNUCXX) 
 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_LIBRARY_CXX_FLAGS " ")
   SET(CMAKE_SHARED_MODULE_CXX_FLAGS  " ")
   SET(CMAKE_SHARED_MODULE_CXX_FLAGS  " ")
   SET (CMAKE_CXX_FLAGS_DEBUG_INIT "-g")
   SET (CMAKE_CXX_FLAGS_DEBUG_INIT "-g")
@@ -22,8 +30,8 @@ ENDIF(CMAKE_COMPILER_IS_GNUCXX)
 IF(CMAKE_COMPILER_IS_GNUCC)
 IF(CMAKE_COMPILER_IS_GNUCC)
   SET(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-shared -Wl,-G")       # -shared
   SET(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-shared -Wl,-G")       # -shared
 ELSE(CMAKE_COMPILER_IS_GNUCC)
 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_LIBRARY_C_FLAGS " ")
   SET(CMAKE_SHARED_MODULE_C_FLAGS  " ")
   SET(CMAKE_SHARED_MODULE_C_FLAGS  " ")
   SET (CMAKE_C_FLAGS_DEBUG_INIT "-g")
   SET (CMAKE_C_FLAGS_DEBUG_INIT "-g")

+ 26 - 15
Modules/Platform/HP-UX.cmake

@@ -2,15 +2,18 @@ SET(CMAKE_SHARED_LIBRARY_SUFFIX ".sl")          # .so
 SET(CMAKE_DL_LIBS "dld")
 SET(CMAKE_DL_LIBS "dld")
 SET(CMAKE_FIND_LIBRARY_SUFFIXES ".sl" ".so" ".a")
 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
 # fortran
 IF(CMAKE_COMPILER_IS_GNUG77)
 IF(CMAKE_COMPILER_IS_GNUG77)
   SET(CMAKE_SHARED_LIBRARY_Fortran_FLAGS "-fPIC")            # -pic 
   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_SONAME_Fortran_FLAG "-Wl,+h")
   SET(CMAKE_SHARED_LIBRARY_Fortran_FLAGS "-fPIC")     # -pic 
   SET(CMAKE_SHARED_LIBRARY_Fortran_FLAGS "-fPIC")     # -pic 
 ELSE(CMAKE_COMPILER_IS_GNUG77)
 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>")
       "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_Fortran_FLAGS "+Z")            # -pic 
   SET(CMAKE_SHARED_LIBRARY_CREATE_Fortran_FLAGS "-E -b -L/usr/lib")       # -shared
   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_SHARED_LIBRARY_SONAME_Fortran_FLAG "+h")
+  SET(CMAKE_EXECUTABLE_RUNTIME_Fortran_FLAG "-Wl,+b")       # -rpath
 ENDIF(CMAKE_COMPILER_IS_GNUG77)
 ENDIF(CMAKE_COMPILER_IS_GNUG77)
+
 # C compiler
 # C compiler
 IF(CMAKE_COMPILER_IS_GNUCC)
 IF(CMAKE_COMPILER_IS_GNUCC)
   # gnu gcc
   # gnu gcc
   SET(CMAKE_SHARED_LIBRARY_C_FLAGS "-fPIC")            # -pic 
   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 "-Wl,+b")       # -rpath
   SET(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP ":")   # : or empty
   SET(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP ":")   # : or empty
   SET(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-Wl,+h")
   SET(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-Wl,+h")
@@ -40,28 +46,33 @@ ELSE(CMAKE_COMPILER_IS_GNUCC)
   SET(CMAKE_C_CREATE_SHARED_LIBRARY
   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>")
       "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_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 "+b")       # -rpath
+  SET(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP ":")   # : or empty
   SET(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "+h")
   SET(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "+h")
+  SET(CMAKE_EXECUTABLE_RUNTIME_C_FLAG "-Wl,+b")       # -rpath
 ENDIF(CMAKE_COMPILER_IS_GNUCC)
 ENDIF(CMAKE_COMPILER_IS_GNUCC)
 
 
 # CXX compiler
 # CXX compiler
 IF(CMAKE_COMPILER_IS_GNUCXX) 
 IF(CMAKE_COMPILER_IS_GNUCXX) 
   # for gnu C++
   # for gnu C++
   SET(CMAKE_SHARED_LIBRARY_CXX_FLAGS "-fPIC")            # -pic 
   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 "-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_CXX_FLAGS "-fPIC")     # -pic 
   SET(CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG "-Wl,+h")
   SET(CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG "-Wl,+h")
 ELSE(CMAKE_COMPILER_IS_GNUCXX)
 ELSE(CMAKE_COMPILER_IS_GNUCXX)
   # for hp aCC
   # for hp aCC
   SET(CMAKE_SHARED_LIBRARY_CXX_FLAGS "+Z")            # -pic 
   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 "-Wl,+b")       # -rpath
+  SET(CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG_SEP ":")   # : or empty
   SET(CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG "-Wl,+h")
   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_INIT "")
   SET (CMAKE_CXX_FLAGS_DEBUG_INIT "-g")
   SET (CMAKE_CXX_FLAGS_DEBUG_INIT "-g")
   SET (CMAKE_CXX_FLAGS_MINSIZEREL_INIT "+O3 -DNDEBUG")
   SET (CMAKE_CXX_FLAGS_MINSIZEREL_INIT "+O3 -DNDEBUG")

+ 2 - 1
Source/CMakeLists.txt

@@ -87,6 +87,8 @@ SET(SRCS
   cmCommandArgumentLexer.cxx
   cmCommandArgumentLexer.cxx
   cmCommandArgumentParser.cxx
   cmCommandArgumentParser.cxx
   cmCommandArgumentParserHelper.cxx
   cmCommandArgumentParserHelper.cxx
+  cmComputeLinkInformation.cxx
+  cmComputeLinkInformation.h
   cmCustomCommand.cxx
   cmCustomCommand.cxx
   cmCustomCommand.h
   cmCustomCommand.h
   cmDepends.cxx
   cmDepends.cxx
@@ -151,7 +153,6 @@ SET(SRCS
   cmMakefileExecutableTargetGenerator.cxx
   cmMakefileExecutableTargetGenerator.cxx
   cmMakefileLibraryTargetGenerator.cxx
   cmMakefileLibraryTargetGenerator.cxx
   cmMakefileUtilityTargetGenerator.cxx
   cmMakefileUtilityTargetGenerator.cxx
-  cmOrderLinkDirectories.cxx
   cmProperty.cxx
   cmProperty.cxx
   cmProperty.h
   cmProperty.h
   cmPropertyDefinition.cxx
   cmPropertyDefinition.cxx

+ 1157 - 0
Source/cmComputeLinkInformation.cxx

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

+ 165 - 0
Source/cmComputeLinkInformation.h

@@ -0,0 +1,165 @@
+/*=========================================================================
+
+  Program:   CMake - Cross-Platform Makefile Generator
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
+  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+#ifndef cmComputeLinkInformation_h
+#define cmComputeLinkInformation_h
+
+#include "cmStandardIncludes.h"
+
+#include <cmsys/RegularExpression.hxx>
+
+class cmGlobalGenerator;
+class cmLocalGenerator;
+class cmMakefile;
+class cmTarget;
+
+/** \class cmComputeLinkInformation
+ * \brief Compute link information for a target in one configuration.
+ */
+class cmComputeLinkInformation
+{
+public:
+  cmComputeLinkInformation(cmTarget* target, const char* config);
+  bool Compute();
+
+  struct Item
+  {
+    Item(): Value(), IsPath(true) {}
+    Item(Item const& item): Value(item.Value), IsPath(item.IsPath) {}
+    Item(std::string const& v, bool p): Value(v), IsPath(p) {}
+    std::string Value;
+    bool IsPath;
+  };
+  typedef std::vector<Item> ItemVector;
+  ItemVector const& GetItems();
+  std::vector<std::string> const& GetDirectories();
+  std::vector<std::string> const& GetDepends();
+  std::vector<std::string> const& GetFrameworkPaths();
+  const char* GetLinkLanguage() const { return this->LinkLanguage; }
+  std::vector<std::string> const& GetRuntimeSearchPath();
+private:
+  void AddItem(std::string const& item);
+
+  // Output information.
+  ItemVector Items;
+  std::vector<std::string> Directories;
+  std::vector<std::string> Depends;
+  std::vector<std::string> FrameworkPaths;
+  std::vector<std::string> RuntimeSearchPath;
+
+  // Context information.
+  cmTarget* Target;
+  cmMakefile* Makefile;
+  cmLocalGenerator* LocalGenerator;
+  cmGlobalGenerator* GlobalGenerator;
+
+  // Configuration information.
+  const char* Config;
+  const char* LinkLanguage;
+
+  // System info.
+  bool UseImportLibrary;
+  const char* LoaderFlag;
+  std::string LibLinkFlag;
+  std::string LibLinkSuffix;
+
+  // Link type adjustment.
+  void ComputeLinkTypeInfo();
+  enum LinkType { LinkUnknown, LinkStatic, LinkShared };
+  LinkType StartLinkType;
+  LinkType CurrentLinkType;
+  std::string StaticLinkTypeFlag;
+  std::string SharedLinkTypeFlag;
+  bool LinkTypeEnabled;
+  void SetCurrentLinkType(LinkType lt);
+
+  // Link item parsing.
+  void ComputeItemParserInfo();
+  std::vector<std::string> StaticLinkExtensions;
+  std::vector<std::string> SharedLinkExtensions;
+  std::vector<std::string> LinkExtensions;
+  std::set<cmStdString> LinkPrefixes;
+  cmsys::RegularExpression RemoveLibraryExtension;
+  cmsys::RegularExpression ExtractStaticLibraryName;
+  cmsys::RegularExpression ExtractSharedLibraryName;
+  cmsys::RegularExpression ExtractAnyLibraryName;
+  void AddLinkPrefix(const char* p);
+  void AddLinkExtension(const char* e, LinkType type);
+  std::string CreateExtensionRegex(std::vector<std::string> const& exts);
+  std::string NoCaseExpression(const char* str);
+
+  // Handling of link items that are not targets or full file paths.
+  void AddUserItem(std::string const& item);
+  void AddDirectoryItem(std::string const& item);
+  void AddFrameworkItem(std::string const& item);
+  void DropDirectoryItem(std::string const& item);
+
+  // Framework info.
+  void ComputeFrameworkInfo();
+  void AddFrameworkPath(std::string const& p);
+  std::set<cmStdString> FrameworkPathsEmmitted;
+  cmsys::RegularExpression SplitFramework;
+
+  // Linker search path computation.
+  void ComputeLinkerSearchDirectories();
+  void AddLinkerSearchDirectories(std::vector<std::string> const& dirs);
+  std::set<cmStdString> DirectoriesEmmitted;
+
+  // Runtime path computation.
+  struct LibraryRuntimeEntry
+  {
+    // The file name of the library.
+    std::string FileName;
+
+    // The soname of the shared library if it is known.
+    std::string SOName;
+
+    // The directory in which the library is supposed to be found.
+    std::string Directory;
+
+    // The index assigned to the directory.
+    int DirectoryIndex;
+  };
+  bool RuntimeSearchPathComputed;
+  std::vector<LibraryRuntimeEntry> LibraryRuntimeInfo;
+  std::set<cmStdString> LibraryRuntimeInfoEmmitted;
+  std::vector<std::string> RuntimeDirectories;
+  std::map<cmStdString, int> RuntimeDirectoryIndex;
+  std::vector<char> RuntimeDirectoryVisited;
+  void AddLibraryRuntimeInfo(std::string const& fullPath, cmTarget* target);
+  void AddLibraryRuntimeInfo(std::string const& fullPath,
+                             const char* soname = 0);
+  void CollectRuntimeDirectories();
+  int AddRuntimeDirectory(std::string const& dir);
+  void FindConflictingLibraries();
+  void FindDirectoriesForLib(unsigned int lri);
+  void OrderRuntimeSearchPath();
+  void VisitRuntimeDirectory(unsigned int i, bool top);
+  void DiagnoseCycle();
+  bool CycleDiagnosed;
+
+  // Adjacency-list representation of runtime path ordering graph.
+  // This maps from directory to those that must come *before* it.
+  // Each entry that must come before is a pair.  The first element is
+  // the index of the directory that must come first.  The second
+  // element is the index of the runtime library that added the
+  // constraint.
+  typedef std::pair<int, int> RuntimeConflictPair;
+  struct RuntimeConflictList: public std::vector<RuntimeConflictPair> {};
+  std::vector<RuntimeConflictList> RuntimeConflictGraph;
+};
+
+#endif

+ 6 - 0
Source/cmDocumentVariables.cxx

@@ -1035,6 +1035,12 @@ void cmDocumentVariables::DefineVariables(cmake* cm)
                      cmProperty::VARIABLE,0,0);
                      cmProperty::VARIABLE,0,0);
   cm->DefineProperty("CMAKE_SHARED_LIBRARY_RUNTIME_<LANG>_FLAG_SEP",
   cm->DefineProperty("CMAKE_SHARED_LIBRARY_RUNTIME_<LANG>_FLAG_SEP",
                      cmProperty::VARIABLE,0,0);
                      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",
   cm->DefineProperty("CMAKE_SHARED_MODULE_CREATE_<LANG>_FLAGS",
                      cmProperty::VARIABLE,0,0);
                      cmProperty::VARIABLE,0,0);
   cm->DefineProperty("CMAKE_SHARED_MODULE_<LANG>_FLAGS",
   cm->DefineProperty("CMAKE_SHARED_MODULE_<LANG>_FLAGS",

+ 42 - 1
Source/cmGlobalGenerator.cxx

@@ -27,6 +27,8 @@
 #include "cmVersion.h"
 #include "cmVersion.h"
 #include "cmInstallExportGenerator.h"
 #include "cmInstallExportGenerator.h"
 
 
+#include <cmsys/Directory.hxx>
+
 #include <stdlib.h> // required for atof
 #include <stdlib.h> // required for atof
 
 
 #include <assert.h>
 #include <assert.h>
@@ -784,7 +786,7 @@ void cmGlobalGenerator::Generate()
   // Compute the manifest of main targets generated.
   // Compute the manifest of main targets generated.
   for (i = 0; i < this->LocalGenerators.size(); ++i)
   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
   // Create a map from local generator to the complete set of targets
@@ -1880,3 +1882,42 @@ cmGlobalGenerator
     this->FilesReplacedDuringGenerate.end(),
     this->FilesReplacedDuringGenerate.end(),
     std::back_inserter(filenames));
     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;
+}

+ 21 - 0
Source/cmGlobalGenerator.h

@@ -150,6 +150,9 @@ public:
   ///! Get the export target set with the   given name
   ///! Get the export target set with the   given name
   const std::vector<cmTargetExport*>* GetExportSet(const char* name) const;
   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();
   void EnableInstallTarget();
 
 
   int TryCompileTimeout;
   int TryCompileTimeout;
@@ -209,6 +212,13 @@ public:
       configuration.  This is valid during generation only.  */
       configuration.  This is valid during generation only.  */
   cmTargetManifest const& GetTargetManifest() { return this->TargetManifest; }
   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);
   void AddTarget(cmTargets::value_type &v);
 
 
   virtual const char* GetAllTargetName()          { return "ALL_BUILD"; }
   virtual const char* GetAllTargetName()          { return "ALL_BUILD"; }
@@ -304,6 +314,17 @@ private:
                       std::vector<cmTarget const*>& steps);
                       std::vector<cmTarget const*>& steps);
   typedef std::map<cmTarget const*, TargetDependSet> TargetDependMap;
   typedef std::map<cmTarget const*, TargetDependSet> TargetDependMap;
   TargetDependMap TargetDependencies;
   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
 #endif

+ 49 - 39
Source/cmGlobalXCodeGenerator.cxx

@@ -22,6 +22,7 @@ PURPOSE.  See the above copyright notices for more information.
 #include "cmXCode21Object.h"
 #include "cmXCode21Object.h"
 #include "cmake.h"
 #include "cmake.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratedFileStream.h"
+#include "cmComputeLinkInformation.h"
 #include "cmSourceFile.h"
 #include "cmSourceFile.h"
 
 
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
@@ -2107,23 +2108,27 @@ void cmGlobalXCodeGenerator
       }
       }
 
 
     // Compute the link library and directory information.
     // 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.
     // 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());
       target->AddDependLibrary(configName, j->c_str());
       }
       }
+    }
 
 
-    std::string linkDirs;
     // add the library search paths
     // 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)
         libDir != libDirs.end(); ++libDir)
       {
       {
       if(libDir->size() && *libDir != "/usr/lib")
       if(libDir->size() && *libDir != "/usr/lib")
@@ -2141,45 +2146,50 @@ void cmGlobalXCodeGenerator
       }
       }
     this->AppendBuildSettingAttribute(target, "LIBRARY_SEARCH_PATHS",
     this->AppendBuildSettingAttribute(target, "LIBRARY_SEARCH_PATHS",
                                       linkDirs.c_str(), configName);
                                       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
     // now add the link libraries
     if(cmtarget->GetType() != cmTarget::STATIC_LIBRARY)
     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
         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);
       }
       }
     }
     }
 }
 }

+ 112 - 366
Source/cmLocalGenerator.cxx

@@ -16,6 +16,7 @@
 =========================================================================*/
 =========================================================================*/
 #include "cmLocalGenerator.h"
 #include "cmLocalGenerator.h"
 
 
+#include "cmComputeLinkInformation.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGlobalGenerator.h"
 #include "cmGlobalGenerator.h"
 #include "cmInstallGenerator.h"
 #include "cmInstallGenerator.h"
@@ -23,7 +24,6 @@
 #include "cmInstallScriptGenerator.h"
 #include "cmInstallScriptGenerator.h"
 #include "cmInstallTargetGenerator.h"
 #include "cmInstallTargetGenerator.h"
 #include "cmMakefile.h"
 #include "cmMakefile.h"
-#include "cmOrderLinkDirectories.h"
 #include "cmSourceFile.h"
 #include "cmSourceFile.h"
 #include "cmTest.h"
 #include "cmTest.h"
 #include "cmake.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.
   // Collect the set of configuration types.
   std::vector<std::string> configNames;
   std::vector<std::string> configNames;
@@ -500,34 +500,17 @@ void cmLocalGenerator::GenerateTargetManifest(cmTargetManifest& manifest)
   for(cmTargets::iterator t = targets.begin(); t != targets.end(); ++t)
   for(cmTargets::iterator t = targets.begin(); t != targets.end(); ++t)
     {
     {
     cmTarget& target = t->second;
     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
   // collect all the flags needed for linking libraries
   linkLibs = "";
   linkLibs = "";
 
 
-  // Try to emit each search path once
-  std::set<cmStdString> emitted;
+  const char* config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE");
+
+  cmComputeLinkInformation cli(&tgt, config);
+  if(!cli.Compute())
+    {
+    return false;
+    }
+
+  const char* linkLanguage = cli.GetLinkLanguage();
+
   // Embed runtime search paths if possible and if required.
   // Embed runtime search paths if possible and if required.
-  bool outputRuntime = true;
+  bool outputRuntime = !this->Makefile->IsOn("CMAKE_SKIP_RPATH");
+
+  // Lookup rpath specification flags.
   std::string runtimeFlag;
   std::string runtimeFlag;
   std::string runtimeSep;
   std::string runtimeSep;
-
-  const char* config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE");
-  const char* linkLanguage = 
-      tgt.GetLinkerLanguage(this->GetGlobalGenerator());
-  if(!linkLanguage)
+  if(tgt.GetType() != cmTarget::STATIC_LIBRARY)
     {
     {
-    cmSystemTools::
-      Error("CMake can not determine linker language for target:",
-            tgt.GetName());
-    return false;
+    std::string runTimeFlagVar = "CMAKE_";
+    if(tgt.GetType() == cmTarget::EXECUTABLE)
+      {
+      runTimeFlagVar += "EXECUTABLE";
+      }
+    else
+      {
+      runTimeFlagVar += "SHARED_LIBRARY";
+      }
+    runTimeFlagVar += "_RUNTIME_";
+    runTimeFlagVar += linkLanguage;
+    runTimeFlagVar += "_FLAG";
+    std::string runTimeFlagSepVar = runTimeFlagVar + "_SEP";
+    runtimeFlag = this->Makefile->GetSafeDefinition(runTimeFlagVar.c_str());
+    runtimeSep = this->Makefile->GetSafeDefinition(runTimeFlagSepVar.c_str());
     }
     }
-  std::string runTimeFlagVar = "CMAKE_SHARED_LIBRARY_RUNTIME_";
-  runTimeFlagVar += linkLanguage;
-  runTimeFlagVar += "_FLAG";
-  std::string runTimeFlagSepVar = runTimeFlagVar + "_SEP";
-  runtimeFlag = this->Makefile->GetSafeDefinition(runTimeFlagVar.c_str());
-  runtimeSep = this->Makefile->GetSafeDefinition(runTimeFlagSepVar.c_str());
-  
   // concatenate all paths or no?
   // 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;
     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 = 
   std::string libPathFlag = 
     this->Makefile->GetRequiredDefinition("CMAKE_LIBRARY_PATH_FLAG");
     this->Makefile->GetRequiredDefinition("CMAKE_LIBRARY_PATH_FLAG");
   std::string libPathTerminator = 
   std::string libPathTerminator = 
@@ -1539,10 +1525,43 @@ bool cmLocalGenerator::GetLinkerArgs(std::string& rpath,
     linkLibs += " ";
     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
   // Select whether to generate an rpath for the install tree or the
   // build tree.
   // build tree.
@@ -1562,68 +1581,46 @@ bool cmLocalGenerator::GetLinkerArgs(std::string& rpath,
     {
     {
     const char* install_rpath = tgt.GetProperty("INSTALL_RPATH");
     const char* install_rpath = tgt.GetProperty("INSTALL_RPATH");
     cmSystemTools::ExpandListArgument(install_rpath, runtimeDirs);
     cmSystemTools::ExpandListArgument(install_rpath, runtimeDirs);
-    for(unsigned int i=0; i < runtimeDirs.size(); ++i)
-      {
-      runtimeDirs[i] =
-        this->Convert(runtimeDirs[i].c_str(), FULL, SHELL, false);
-      }
     }
     }
-
-  // Append the library search path flags.
-  for(std::vector<cmStdString>::const_iterator libDir = libDirs.begin();
-      libDir != libDirs.end(); ++libDir)
+  if(use_build_rpath || use_link_rpath)
     {
     {
-   std::string libpath = this->ConvertToOutputForExisting(libDir->c_str());
-    if(emitted.insert(libpath).second)
+    std::vector<std::string> const& rdirs = cli.GetRuntimeSearchPath();
+    for(std::vector<std::string>::const_iterator ri = rdirs.begin();
+        ri != rdirs.end(); ++ri)
       {
       {
-      std::string fullLibPath;
-      if(!this->WindowsShell && this->UseRelativePaths)
+      // Put this directory in the rpath if using build-tree rpath
+      // support or if using the link path as an rpath.
+      if(use_build_rpath)
         {
         {
-        fullLibPath = "\"`cd ";
+        runtimeDirs.push_back(*ri);
         }
         }
-      fullLibPath += libpath;
-      if(!this->WindowsShell && this->UseRelativePaths)
+      else if(use_link_rpath)
         {
         {
-        fullLibPath += ";pwd`\"";
-        }
-      std::string::size_type pos = libDir->find(libPathFlag.c_str());
-      if((pos == std::string::npos || pos > 0)
-         && libDir->find("${") == std::string::npos)
-        {
-        linkLibs += libPathFlag;
-        linkLibs += fullLibPath;
-        linkLibs += libPathTerminator;
-        linkLibs += " ";
-
-        // Put this directory in the rpath if using build-tree rpath
-        // support or if using the link path as an rpath.
-        if(use_build_rpath)
-          {
-          runtimeDirs.push_back(fullLibPath);
-          }
-        else if(use_link_rpath)
+        // Do not add any path inside the source or build tree.
+        const char* topSourceDir = this->Makefile->GetHomeDirectory();
+        const char* topBinaryDir = this->Makefile->GetHomeOutputDirectory();
+        if(!cmSystemTools::ComparePath(ri->c_str(), topSourceDir) &&
+           !cmSystemTools::ComparePath(ri->c_str(), topBinaryDir) &&
+           !cmSystemTools::IsSubDirectory(ri->c_str(), topSourceDir) &&
+           !cmSystemTools::IsSubDirectory(ri->c_str(), topBinaryDir))
           {
           {
-          // Do not add any path inside the source or build tree.
-          const char* topSourceDir = this->Makefile->GetHomeDirectory();
-          const char* topBinaryDir = this->Makefile->GetHomeOutputDirectory();
-          if(!cmSystemTools::ComparePath(libDir->c_str(), topSourceDir) &&
-             !cmSystemTools::ComparePath(libDir->c_str(), topBinaryDir) &&
-             !cmSystemTools::IsSubDirectory(libDir->c_str(), topSourceDir) &&
-             !cmSystemTools::IsSubDirectory(libDir->c_str(), topBinaryDir))
-            {
-            runtimeDirs.push_back(fullLibPath);
-            }
+          runtimeDirs.push_back(*ri);
           }
           }
         }
         }
       }
       }
     }
     }
+  if(runtimeAlways)
+    {
+    // Add runtime paths required by the platform to always be
+    // present.  This is done even when skipping rpath support.
+    cmSystemTools::ExpandListArgument(runtimeAlways, runtimeDirs);
+    }
 
 
-  // Append the link libraries.
-  for(std::vector<cmStdString>::iterator lib = libNames.begin();
-      lib != libNames.end(); ++lib)
+  // Convert the runtime directory names for use in the build file.
+  for(std::vector<std::string>::iterator ri = runtimeDirs.begin();
+      ri != runtimeDirs.end(); ++ri)
     {
     {
-    linkLibs += *lib;
-    linkLibs += " ";
+    *ri = this->Convert(ri->c_str(), FULL, SHELL, false);
     }
     }
 
 
   if(!runtimeDirs.empty())
   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,
 void cmLocalGenerator::AddLanguageFlags(std::string& flags,
                                         const char* lang,
                                         const char* lang,

+ 1 - 8
Source/cmLocalGenerator.h

@@ -75,7 +75,7 @@ public:
   /**
   /**
    * Generate a manifest of target files that will be built.
    * Generate a manifest of target files that will be built.
    */
    */
-  virtual void GenerateTargetManifest(cmTargetManifest&);
+  virtual void GenerateTargetManifest();
 
 
   ///! Get the makefile for this generator
   ///! Get the makefile for this generator
   cmMakefile *GetMakefile() {
   cmMakefile *GetMakefile() {
@@ -174,13 +174,6 @@ public:
                                   bool /*color*/)
                                   bool /*color*/)
     { return true; }
     { 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.  */
   /** Get the include flags for the current makefile and language.  */
   void GetIncludeDirectories(std::vector<std::string>& dirs,
   void GetIncludeDirectories(std::vector<std::string>& dirs,
                              bool filter_system_dirs = true);
                              bool filter_system_dirs = true);

+ 21 - 6
Source/cmLocalVisualStudio6Generator.cxx

@@ -22,6 +22,8 @@
 #include "cmCacheManager.h"
 #include "cmCacheManager.h"
 #include "cmake.h"
 #include "cmake.h"
 
 
+#include "cmComputeLinkInformation.h"
+
 #include <cmsys/RegularExpression.hxx>
 #include <cmsys/RegularExpression.hxx>
 
 
 cmLocalVisualStudio6Generator::cmLocalVisualStudio6Generator()
 cmLocalVisualStudio6Generator::cmLocalVisualStudio6Generator()
@@ -1569,12 +1571,17 @@ void cmLocalVisualStudio6Generator
                      std::string& options)
                      std::string& options)
 {
 {
   // Compute the link information for this configuration.
   // 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.
   // 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)
       d != linkDirs.end(); ++d)
     {
     {
     std::string dir = *d;
     std::string dir = *d;
@@ -1592,11 +1599,19 @@ void cmLocalVisualStudio6Generator
       options += "\n";
       options += "\n";
       }
       }
     }
     }
-  for(std::vector<cmStdString>::const_iterator l = linkLibs.begin();
+  for(ItemVector::const_iterator l = linkLibs.begin();
       l != linkLibs.end(); ++l)
       l != linkLibs.end(); ++l)
     {
     {
     options += "# ADD LINK32 ";
     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";
     options += "\n";
     }
     }
 
 

+ 41 - 34
Source/cmLocalVisualStudio7Generator.cxx

@@ -24,12 +24,24 @@
 #include "cmCacheManager.h"
 #include "cmCacheManager.h"
 #include "cmake.h"
 #include "cmake.h"
 
 
+#include "cmComputeLinkInformation.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratedFileStream.h"
 
 
 #include <cmsys/System.h>
 #include <cmsys/System.h>
 
 
 #include <ctype.h> // for isspace
 #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[];
 extern cmVS7FlagTable cmLocalVisualStudio7GeneratorFlagTable[];
 
 
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
@@ -38,10 +50,12 @@ cmLocalVisualStudio7Generator::cmLocalVisualStudio7Generator()
   this->Version = 7;
   this->Version = 7;
   this->PlatformName = "Win32";
   this->PlatformName = "Win32";
   this->ExtraFlagTable = 0;
   this->ExtraFlagTable = 0;
+  this->Internal = new cmLocalVisualStudio7GeneratorInternals(this);
 }
 }
 
 
 cmLocalVisualStudio7Generator::~cmLocalVisualStudio7Generator()
 cmLocalVisualStudio7Generator::~cmLocalVisualStudio7Generator()
 {
 {
+  delete this->Internal;
 }
 }
 
 
 void cmLocalVisualStudio7Generator::AddHelperCommands()
 void cmLocalVisualStudio7Generator::AddHelperCommands()
@@ -748,20 +762,12 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
                            targetNameImport, targetNamePDB, configName);
                            targetNameImport, targetNamePDB, configName);
 
 
     // Compute the link library and directory information.
     // 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;
       return;
       }
       }
+    const char* linkLanguage = cli.GetLinkLanguage();
 
 
     // Compute the variable name to lookup standard libraries for this
     // Compute the variable name to lookup standard libraries for this
     // language.
     // language.
@@ -777,7 +783,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
     fout << "\t\t\t\tAdditionalDependencies=\"$(NOINHERIT) "
     fout << "\t\t\t\tAdditionalDependencies=\"$(NOINHERIT) "
          << this->Makefile->GetSafeDefinition(standardLibsVar.c_str())
          << this->Makefile->GetSafeDefinition(standardLibsVar.c_str())
          << " ";
          << " ";
-    this->OutputLibraries(fout, linkLibs);
+    this->Internal->OutputLibraries(fout, cli.GetItems());
     fout << "\"\n";
     fout << "\"\n";
     temp = target.GetDirectory(configName);
     temp = target.GetDirectory(configName);
     temp += "/";
     temp += "/";
@@ -787,7 +793,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
     this->WriteTargetVersionAttribute(fout, target);
     this->WriteTargetVersionAttribute(fout, target);
     linkOptions.OutputFlagMap(fout, "\t\t\t\t");
     linkOptions.OutputFlagMap(fout, "\t\t\t\t");
     fout << "\t\t\t\tAdditionalLibraryDirectories=\"";
     fout << "\t\t\t\tAdditionalLibraryDirectories=\"";
-    this->OutputLibraryDirectories(fout, linkDirs);
+    this->OutputLibraryDirectories(fout, cli.GetDirectories());
     fout << "\"\n";
     fout << "\"\n";
     this->OutputModuleDefinitionFile(fout, target);
     this->OutputModuleDefinitionFile(fout, target);
     temp = target.GetDirectory(configName);
     temp = target.GetDirectory(configName);
@@ -825,20 +831,12 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
                               targetNameImport, targetNamePDB, configName);
                               targetNameImport, targetNamePDB, configName);
 
 
     // Compute the link library and directory information.
     // 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;
       return;
       }
       }
+    const char* linkLanguage = cli.GetLinkLanguage();
 
 
     // Compute the variable name to lookup standard libraries for this
     // Compute the variable name to lookup standard libraries for this
     // language.
     // language.
@@ -854,7 +852,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
     fout << "\t\t\t\tAdditionalDependencies=\"$(NOINHERIT) "
     fout << "\t\t\t\tAdditionalDependencies=\"$(NOINHERIT) "
          << this->Makefile->GetSafeDefinition(standardLibsVar.c_str())
          << this->Makefile->GetSafeDefinition(standardLibsVar.c_str())
          << " ";
          << " ";
-    this->OutputLibraries(fout, linkLibs);
+    this->Internal->OutputLibraries(fout, cli.GetItems());
     fout << "\"\n";
     fout << "\"\n";
     temp = target.GetDirectory(configName);
     temp = target.GetDirectory(configName);
     temp += "/";
     temp += "/";
@@ -864,7 +862,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout,
     this->WriteTargetVersionAttribute(fout, target);
     this->WriteTargetVersionAttribute(fout, target);
     linkOptions.OutputFlagMap(fout, "\t\t\t\t");
     linkOptions.OutputFlagMap(fout, "\t\t\t\t");
     fout << "\t\t\t\tAdditionalLibraryDirectories=\"";
     fout << "\t\t\t\tAdditionalLibraryDirectories=\"";
-    this->OutputLibraryDirectories(fout, linkDirs);
+    this->OutputLibraryDirectories(fout, cli.GetDirectories());
     fout << "\"\n";
     fout << "\"\n";
     fout << "\t\t\t\tProgramDataBaseFile=\""
     fout << "\t\t\t\tProgramDataBaseFile=\""
          << target.GetDirectory(configName) << "/" << targetNamePDB
          << target.GetDirectory(configName) << "/" << targetNamePDB
@@ -936,14 +934,23 @@ void cmLocalVisualStudio7Generator
 
 
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
 void
 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
 void
 cmLocalVisualStudio7Generator
 cmLocalVisualStudio7Generator
 ::OutputLibraryDirectories(std::ostream& fout,
 ::OutputLibraryDirectories(std::ostream& fout,
-                           std::vector<cmStdString> const& dirs)
+                           std::vector<std::string> const& dirs)
 {
 {
   const char* comma = "";
   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)
       d != dirs.end(); ++d)
     {
     {
     // Remove any trailing slash and skip empty paths.
     // Remove any trailing slash and skip empty paths.

+ 4 - 3
Source/cmLocalVisualStudio7Generator.h

@@ -27,6 +27,7 @@ struct cmVS7FlagTable;
 
 
 class cmLocalVisualStudio7GeneratorOptions;
 class cmLocalVisualStudio7GeneratorOptions;
 class cmLocalVisualStudio7GeneratorFCInfo;
 class cmLocalVisualStudio7GeneratorFCInfo;
+class cmLocalVisualStudio7GeneratorInternals;
 
 
 /** \class cmLocalVisualStudio7Generator
 /** \class cmLocalVisualStudio7Generator
  * \brief Write Visual Studio .NET project files.
  * \brief Write Visual Studio .NET project files.
@@ -96,10 +97,8 @@ private:
                          cmTarget &target, const char *libName);
                          cmTarget &target, const char *libName);
   void OutputBuildTool(std::ostream& fout, const char* configName,
   void OutputBuildTool(std::ostream& fout, const char* configName,
                        cmTarget& t);
                        cmTarget& t);
-  void OutputLibraries(std::ostream& fout,
-                       std::vector<cmStdString> const& libs);
   void OutputLibraryDirectories(std::ostream& fout,
   void OutputLibraryDirectories(std::ostream& fout,
-                                std::vector<cmStdString> const& dirs);
+                                std::vector<std::string> const& dirs);
   void OutputModuleDefinitionFile(std::ostream& fout, cmTarget &target);
   void OutputModuleDefinitionFile(std::ostream& fout, cmTarget &target);
   void WriteProjectStart(std::ostream& fout, const char *libName,
   void WriteProjectStart(std::ostream& fout, const char *libName,
                          cmTarget &tgt, std::vector<cmSourceGroup> &sgs);
                          cmTarget &tgt, std::vector<cmSourceGroup> &sgs);
@@ -120,11 +119,13 @@ private:
   virtual std::string GetTargetDirectory(cmTarget const&) const;
   virtual std::string GetTargetDirectory(cmTarget const&) const;
 
 
   friend class cmLocalVisualStudio7GeneratorFCInfo;
   friend class cmLocalVisualStudio7GeneratorFCInfo;
+  friend class cmLocalVisualStudio7GeneratorInternals;
 
 
   cmVS7FlagTable const* ExtraFlagTable;
   cmVS7FlagTable const* ExtraFlagTable;
   std::string ModuleDefinitionFile;
   std::string ModuleDefinitionFile;
   int Version;
   int Version;
   std::string PlatformName; // Win32 or x64 
   std::string PlatformName; // Win32 or x64 
+  cmLocalVisualStudio7GeneratorInternals* Internal;
 };
 };
 
 
 // This is a table mapping XML tag IDE names to command line options
 // This is a table mapping XML tag IDE names to command line options

+ 0 - 710
Source/cmOrderLinkDirectories.cxx

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

+ 0 - 192
Source/cmOrderLinkDirectories.h

@@ -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
Source/cmTarget.cxx

@@ -35,7 +35,6 @@ cmTarget::cmTarget()
 {
 {
   this->Makefile = 0;
   this->Makefile = 0;
   this->LinkLibrariesAnalyzed = false;
   this->LinkLibrariesAnalyzed = false;
-  this->LinkDirectoriesComputed = false;
   this->HaveInstallRule = false;
   this->HaveInstallRule = false;
   this->DLLPlatform = false;
   this->DLLPlatform = false;
   this->IsImportedTarget = false;
   this->IsImportedTarget = false;
@@ -843,71 +842,15 @@ void cmTarget::MergeLinkLibraries( cmMakefile& mf,
 void cmTarget::AddLinkDirectory(const char* d)
 void cmTarget::AddLinkDirectory(const char* d)
 {
 {
   // Make sure we don't add unnecessary search directories.
   // 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()
 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;
   return this->LinkDirectories;
 }
 }
 
 
@@ -2244,6 +2187,76 @@ void cmTarget::GetExecutableNamesInternal(std::string& name,
   pdbName = prefix+base+".pdb";
   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,
 void cmTarget::SetPropertyDefault(const char* property,
                                   const char* default_value)
                                   const char* default_value)

+ 4 - 2
Source/cmTarget.h

@@ -271,6 +271,9 @@ public:
                                std::string& impName,
                                std::string& impName,
                                std::string& pdbName, const char* config);
                                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.
    * Compute whether this target must be relinked before installing.
    */
    */
@@ -414,10 +417,9 @@ private:
   LinkLibraryVectorType LinkLibraries;
   LinkLibraryVectorType LinkLibraries;
   LinkLibraryVectorType PrevLinkedLibraries;
   LinkLibraryVectorType PrevLinkedLibraries;
   bool LinkLibrariesAnalyzed;
   bool LinkLibrariesAnalyzed;
-  bool LinkDirectoriesComputed;
   std::vector<std::string> Frameworks;
   std::vector<std::string> Frameworks;
   std::vector<std::string> LinkDirectories;
   std::vector<std::string> LinkDirectories;
-  std::vector<std::string> ExplicitLinkDirectories;
+  std::set<cmStdString> LinkDirectoriesEmmitted;
   bool HaveInstallRule;
   bool HaveInstallRule;
   std::string InstallNameFixupPath;
   std::string InstallNameFixupPath;
   std::string InstallPath;
   std::string InstallPath;

+ 3 - 115
Tests/Complex/Executable/complex.cxx

@@ -13,7 +13,6 @@ extern "C" {
 #include "cmSystemTools.h"
 #include "cmSystemTools.h"
 #include "cmDynamicLoader.h"
 #include "cmDynamicLoader.h"
 #include "cmSystemTools.h"
 #include "cmSystemTools.h"
-#include "cmOrderLinkDirectories.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratedFileStream.h"
 #include <cmsys/DynamicLoader.hxx>
 #include <cmsys/DynamicLoader.hxx>
 #else
 #else
@@ -69,99 +68,6 @@ void cmPassed(const char* Message, const char* m2="")
 #endif
 #endif
 
 
 #ifdef COMPLEX_TEST_CMAKELIB
 #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) 
 void TestAndRemoveFile(const char* filename) 
@@ -286,6 +192,9 @@ void TestCMGeneratedFileSTream()
 }
 }
 #endif
 #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()
 void ForceStringUse()
 {
 {
   std::vector<std::string> v;
   std::vector<std::string> v;
@@ -1283,27 +1192,6 @@ int main()
 #endif
 #endif
 
 
 #ifdef COMPLEX_TEST_CMAKELIB
 #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.
   // Test the generated file stream.
   TestCMGeneratedFileSTream();
   TestCMGeneratedFileSTream();
 #endif
 #endif

+ 3 - 115
Tests/ComplexOneConfig/Executable/complex.cxx

@@ -13,7 +13,6 @@ extern "C" {
 #include "cmSystemTools.h"
 #include "cmSystemTools.h"
 #include "cmDynamicLoader.h"
 #include "cmDynamicLoader.h"
 #include "cmSystemTools.h"
 #include "cmSystemTools.h"
-#include "cmOrderLinkDirectories.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratedFileStream.h"
 #include <cmsys/DynamicLoader.hxx>
 #include <cmsys/DynamicLoader.hxx>
 #else
 #else
@@ -69,99 +68,6 @@ void cmPassed(const char* Message, const char* m2="")
 #endif
 #endif
 
 
 #ifdef COMPLEX_TEST_CMAKELIB
 #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) 
 void TestAndRemoveFile(const char* filename) 
@@ -286,6 +192,9 @@ void TestCMGeneratedFileSTream()
 }
 }
 #endif
 #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()
 void ForceStringUse()
 {
 {
   std::vector<std::string> v;
   std::vector<std::string> v;
@@ -1283,27 +1192,6 @@ int main()
 #endif
 #endif
 
 
 #ifdef COMPLEX_TEST_CMAKELIB
 #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.
   // Test the generated file stream.
   TestCMGeneratedFileSTream();
   TestCMGeneratedFileSTream();
 #endif
 #endif

+ 3 - 115
Tests/ComplexRelativePaths/Executable/complex.cxx

@@ -13,7 +13,6 @@ extern "C" {
 #include "cmSystemTools.h"
 #include "cmSystemTools.h"
 #include "cmDynamicLoader.h"
 #include "cmDynamicLoader.h"
 #include "cmSystemTools.h"
 #include "cmSystemTools.h"
-#include "cmOrderLinkDirectories.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratedFileStream.h"
 #include <cmsys/DynamicLoader.hxx>
 #include <cmsys/DynamicLoader.hxx>
 #else
 #else
@@ -69,99 +68,6 @@ void cmPassed(const char* Message, const char* m2="")
 #endif
 #endif
 
 
 #ifdef COMPLEX_TEST_CMAKELIB
 #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) 
 void TestAndRemoveFile(const char* filename) 
@@ -286,6 +192,9 @@ void TestCMGeneratedFileSTream()
 }
 }
 #endif
 #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()
 void ForceStringUse()
 {
 {
   std::vector<std::string> v;
   std::vector<std::string> v;
@@ -1283,27 +1192,6 @@ int main()
 #endif
 #endif
 
 
 #ifdef COMPLEX_TEST_CMAKELIB
 #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.
   // Test the generated file stream.
   TestCMGeneratedFileSTream();
   TestCMGeneratedFileSTream();
 #endif
 #endif

+ 1 - 1
bootstrap

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