Просмотр исходного кода

OS X: Detect implicit linker framework search paths

Previously we hard-coded a list of implicit framework directories but
did not account for CMAKE_OSX_SYSROOT or for changes to the list across
OS X versions.  Instead we should automatically detect the framework
directories for the active toolchain.

The parent commit added the "-Wl,-v" option to ask "ld" to print its
implicit directories.  It displays a block such as:

 Framework search paths:
	/...

Parse this block to extract the list of framework directories.

Detection may fail on toolchains that do not list their framework
directories, such as older OS X linkers.  Always treat the paths

 <sdk>/Library/Frameworks
 <sdk>/System/Library/Frameworks
 <sdk>/Network/Library/Frameworks # Older OS X only
 /System/Library/Frameworks

as implicit.  Note that /System/Library/Frameworks should always be
considered implicit so that frameworks CMake finds there will not
override the SDK copies.
Brad King 13 лет назад
Родитель
Сommit
cc676c3a08

+ 1 - 0
Modules/CMakeCCompiler.cmake.in

@@ -50,6 +50,7 @@ endif()
 
 set(CMAKE_C_IMPLICIT_LINK_LIBRARIES "@CMAKE_C_IMPLICIT_LINK_LIBRARIES@")
 set(CMAKE_C_IMPLICIT_LINK_DIRECTORIES "@CMAKE_C_IMPLICIT_LINK_DIRECTORIES@")
+set(CMAKE_C_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "@CMAKE_C_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES@")
 
 @SET_CMAKE_CMCLDEPS_EXECUTABLE@
 @SET_CMAKE_CL_SHOWINCLUDE_PREFIX@

+ 1 - 0
Modules/CMakeCXXCompiler.cmake.in

@@ -51,6 +51,7 @@ endif()
 
 set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "@CMAKE_CXX_IMPLICIT_LINK_LIBRARIES@")
 set(CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "@CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES@")
+set(CMAKE_CXX_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "@CMAKE_CXX_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES@")
 
 @SET_CMAKE_CMCLDEPS_EXECUTABLE@
 @SET_CMAKE_CL_SHOWINCLUDE_PREFIX@

+ 3 - 1
Modules/CMakeDetermineCompilerABI.cmake

@@ -72,8 +72,9 @@ function(CMAKE_DETERMINE_COMPILER_ABI lang src)
       # Parse implicit linker information for this language, if available.
       set(implicit_dirs "")
       set(implicit_libs "")
+      set(implicit_fwks "")
       if(CMAKE_${lang}_VERBOSE_FLAG)
-        CMAKE_PARSE_IMPLICIT_LINK_INFO("${OUTPUT}" implicit_libs implicit_dirs log
+        CMAKE_PARSE_IMPLICIT_LINK_INFO("${OUTPUT}" implicit_libs implicit_dirs implicit_fwks log
           "${CMAKE_${lang}_IMPLICIT_OBJECT_REGEX}")
         file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
           "Parsed ${lang} implicit link information from above output:\n${log}\n\n")
@@ -111,6 +112,7 @@ function(CMAKE_DETERMINE_COMPILER_ABI lang src)
 
       set(CMAKE_${lang}_IMPLICIT_LINK_LIBRARIES "${implicit_libs}" PARENT_SCOPE)
       set(CMAKE_${lang}_IMPLICIT_LINK_DIRECTORIES "${implicit_dirs}" PARENT_SCOPE)
+      set(CMAKE_${lang}_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "${implicit_fwks}" PARENT_SCOPE)
 
       # Detect library architecture directory name.
       if(CMAKE_LIBRARY_ARCHITECTURE_REGEX)

+ 1 - 0
Modules/CMakeFortranCompiler.cmake.in

@@ -52,3 +52,4 @@ endif()
 
 set(CMAKE_Fortran_IMPLICIT_LINK_LIBRARIES "@CMAKE_Fortran_IMPLICIT_LINK_LIBRARIES@")
 set(CMAKE_Fortran_IMPLICIT_LINK_DIRECTORIES "@CMAKE_Fortran_IMPLICIT_LINK_DIRECTORIES@")
+set(CMAKE_Fortran_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "@CMAKE_Fortran_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES@")

+ 26 - 14
Modules/CMakeParseImplicitLinkInfo.cmake

@@ -16,9 +16,10 @@
 # This is used internally by CMake and should not be included by user
 # code.
 
-function(CMAKE_PARSE_IMPLICIT_LINK_INFO text lib_var dir_var log_var obj_regex)
+function(CMAKE_PARSE_IMPLICIT_LINK_INFO text lib_var dir_var fwk_var log_var obj_regex)
   set(implicit_libs_tmp "")
   set(implicit_dirs_tmp)
+  set(implicit_fwks_tmp)
   set(log "")
 
   # Parse implicit linker arguments.
@@ -113,6 +114,11 @@ function(CMAKE_PARSE_IMPLICIT_LINK_INFO text lib_var dir_var log_var obj_regex)
     set(log "${log}  Library search paths: [${implicit_dirs_match}]\n")
     list(APPEND implicit_dirs_tmp ${implicit_dirs_match})
   endif()
+  if("${output_lines}" MATCHES ";Framework search paths:((;\t[^;]+)+)")
+    string(REPLACE ";\t" ";" implicit_fwks_match "${CMAKE_MATCH_1}")
+    set(log "${log}  Framework search paths: [${implicit_fwks_match}]\n")
+    list(APPEND implicit_fwks_tmp ${implicit_fwks_match})
+  endif()
 
   # Cleanup list of libraries and flags.
   # We remove items that are not language-specific.
@@ -125,27 +131,33 @@ function(CMAKE_PARSE_IMPLICIT_LINK_INFO text lib_var dir_var log_var obj_regex)
     endif()
   endforeach()
 
-  # Cleanup list of library directories.
-  set(implicit_dirs "")
-  foreach(d IN LISTS implicit_dirs_tmp)
-    get_filename_component(dir "${d}" ABSOLUTE)
-    string(FIND "${dir}" "${CMAKE_FILES_DIRECTORY}/" pos)
-    if(NOT pos LESS 0)
-      set(msg ", skipping non-system directory")
-    else()
-      set(msg "")
-      list(APPEND implicit_dirs "${dir}")
-    endif()
-    set(log "${log}  collapse library dir [${d}] ==> [${dir}]${msg}\n")
+  # Cleanup list of library and framework directories.
+  set(desc_dirs "library")
+  set(desc_fwks "framework")
+  foreach(t dirs fwks)
+    set(implicit_${t} "")
+    foreach(d IN LISTS implicit_${t}_tmp)
+      get_filename_component(dir "${d}" ABSOLUTE)
+      string(FIND "${dir}" "${CMAKE_FILES_DIRECTORY}/" pos)
+      if(NOT pos LESS 0)
+        set(msg ", skipping non-system directory")
+      else()
+        set(msg "")
+        list(APPEND implicit_${t} "${dir}")
+      endif()
+      set(log "${log}  collapse ${desc_${t}} dir [${d}] ==> [${dir}]${msg}\n")
+    endforeach()
+    list(REMOVE_DUPLICATES implicit_${t})
   endforeach()
-  list(REMOVE_DUPLICATES implicit_dirs)
 
   # Log results.
   set(log "${log}  implicit libs: [${implicit_libs}]\n")
   set(log "${log}  implicit dirs: [${implicit_dirs}]\n")
+  set(log "${log}  implicit fwks: [${implicit_fwks}]\n")
 
   # Return results.
   set(${lib_var} "${implicit_libs}" PARENT_SCOPE)
   set(${dir_var} "${implicit_dirs}" PARENT_SCOPE)
+  set(${fwk_var} "${implicit_fwks}" PARENT_SCOPE)
   set(${log_var} "${log}" PARENT_SCOPE)
 endfunction()

+ 18 - 0
Modules/Platform/Darwin.cmake

@@ -256,6 +256,24 @@ set(CMAKE_CXX_CREATE_MACOSX_FRAMEWORK
 if(NOT DEFINED CMAKE_FIND_FRAMEWORK)
   set(CMAKE_FIND_FRAMEWORK FIRST)
 endif()
+
+# Older OS X linkers do not report their framework search path
+# with -v but "man ld" documents the following locations.
+set(CMAKE_PLATFORM_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
+  ${_CMAKE_OSX_SYSROOT_PATH}/Library/Frameworks
+  ${_CMAKE_OSX_SYSROOT_PATH}/System/Library/Frameworks
+  )
+if(_CMAKE_OSX_SYSROOT_PATH)
+  # Treat some paths as implicit so we do not override the SDK versions.
+  list(APPEND CMAKE_PLATFORM_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
+    /System/Library/Frameworks)
+endif()
+if("${_CURRENT_OSX_VERSION}" VERSION_LESS "10.5")
+  # Older OS X tools had more implicit paths.
+  list(APPEND CMAKE_PLATFORM_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
+    ${_CMAKE_OSX_SYSROOT_PATH}/Network/Library/Frameworks)
+endif()
+
 # set up the default search directories for frameworks
 set(CMAKE_SYSTEM_FRAMEWORK_PATH
   ~/Library/Frameworks

+ 25 - 4
Source/cmComputeLinkInformation.cxx

@@ -1376,10 +1376,31 @@ void cmComputeLinkInformation::DropDirectoryItem(std::string const& item)
 //----------------------------------------------------------------------------
 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");
+  // Avoid adding implicit framework paths.
+  std::vector<std::string> implicitDirVec;
+
+  // Get platform-wide implicit directories.
+  if(const char* implicitLinks = this->Makefile->GetDefinition
+     ("CMAKE_PLATFORM_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES"))
+    {
+    cmSystemTools::ExpandListArgument(implicitLinks, implicitDirVec);
+    }
+
+  // Get language-specific implicit directories.
+  std::string implicitDirVar = "CMAKE_";
+  implicitDirVar += this->LinkLanguage;
+  implicitDirVar += "_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES";
+  if(const char* implicitDirs =
+     this->Makefile->GetDefinition(implicitDirVar.c_str()))
+    {
+    cmSystemTools::ExpandListArgument(implicitDirs, implicitDirVec);
+    }
+
+  for(std::vector<std::string>::const_iterator i = implicitDirVec.begin();
+      i != implicitDirVec.end(); ++i)
+    {
+    this->FrameworkPathsEmmitted.insert(*i);
+    }
 
   // Regular expression to extract a framework path and name.
   this->SplitFramework.compile("(.*)/(.*)\\.framework$");

+ 9 - 0
Source/cmDocumentVariables.cxx

@@ -1624,6 +1624,15 @@ void cmDocumentVariables::DefineVariables(cmake* cm)
      "reports the results in this variable.", false,
      "Variables for Languages");
 
+  cm->DefineProperty
+    ("CMAKE_<LANG>_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES", cmProperty::VARIABLE,
+     "Implicit linker framework search path detected for language <LANG>.",
+     "These paths are implicit linker framework search directories for "
+     "the compiler's language.  "
+     "CMake automatically detects these directories for each language and "
+     "reports the results in this variable.", false,
+     "Variables for Languages");
+
   cm->DefineProperty
     ("CMAKE_<LANG>_IMPLICIT_LINK_LIBRARIES", cmProperty::VARIABLE,
      "Implicit link libraries and flags detected for language <LANG>.",

+ 8 - 3
Tests/CMakeTests/ImplicitLinkInfoTest.cmake.in

@@ -120,6 +120,7 @@ Framework search paths:
 	/System/Library/Frameworks/")
 set(mac_i686_gcc_Wlv_libs "")
 set(mac_i686_gcc_Wlv_dirs "/usr/lib/i686-apple-darwin10/4.2.1;/usr/lib/gcc/i686-apple-darwin10/4.2.1;/usr/lib;/usr/local/lib")
+set(mac_i686_gcc_Wlv_fwks "/Library/Frameworks;/System/Library/Frameworks")
 list(APPEND platforms mac_i686_gcc_Wlv)
 
 # gcc -arch i686 dummy.c -v
@@ -146,6 +147,7 @@ Framework search paths:
 	/System/Library/Frameworks/")
 set(mac_i686_g++_Wlv_libs "stdc++")
 set(mac_i686_g++_Wlv_dirs "/usr/lib/i686-apple-darwin10/4.2.1;/usr/lib/gcc/i686-apple-darwin10/4.2.1;/usr/lib;/usr/local/lib")
+set(mac_i686_g++_Wlv_fwks "/Library/Frameworks;/System/Library/Frameworks")
 list(APPEND platforms mac_i686_g++_Wlv)
 
 # g++ -arch i686 dummy.cxx -v
@@ -169,6 +171,7 @@ Framework search paths:
 	/System/Library/Frameworks/")
 set(mac_i686_gfortran_Wlv_libs "gfortranbegin;gfortran")
 set(mac_i686_gfortran_Wlv_dirs "/usr/local/lib/gcc/i386-apple-darwin9.7.0/4.4.1;/usr/local/lib;/usr/lib")
+set(mac_i686_gfortran_Wlv_fwks "/Library/Frameworks;/System/Library/Frameworks")
 list(APPEND platforms mac_i686_gfortran_Wlv)
 
 # gfortran dummy.f -v
@@ -195,6 +198,7 @@ Framework search paths:
 	/System/Library/Frameworks/")
 set(mac_ppc_gcc_Wlv_libs "")
 set(mac_ppc_gcc_Wlv_dirs "/usr/lib/powerpc-apple-darwin10/4.2.1;/usr/lib/gcc/powerpc-apple-darwin10/4.2.1;/usr/lib;/usr/local/lib")
+set(mac_ppc_gcc_Wlv_fwks "/Library/Frameworks;/System/Library/Frameworks")
 list(APPEND platforms mac_ppc_gcc_Wlv)
 
 # gcc -arch ppc dummy.c -v
@@ -221,6 +225,7 @@ Framework search paths:
 	/System/Library/Frameworks/")
 set(mac_ppc_g++_Wlv_libs "stdc++")
 set(mac_ppc_g++_Wlv_dirs "/usr/lib/powerpc-apple-darwin10/4.2.1;/usr/lib/gcc/powerpc-apple-darwin10/4.2.1;/usr/lib;/usr/local/lib")
+set(mac_ppc_g++_Wlv_fwks "/Library/Frameworks;/System/Library/Frameworks")
 list(APPEND platforms mac_ppc_g++_Wlv)
 
 # g++ -arch ppc dummy.cxx -v
@@ -499,10 +504,10 @@ list(APPEND platforms msys_g77)
 # Test parsing for all above examples.
 
 foreach(p IN LISTS platforms)
-  cmake_parse_implicit_link_info("${${p}_text}" libs dirs log "${${p}_obj_regex}")
+  cmake_parse_implicit_link_info("${${p}_text}" libs dirs fwks log "${${p}_obj_regex}")
 
-  foreach(v libs dirs)
-    if(NOT "${${v}}" STREQUAL "${${p}_${v}}")
+  foreach(v libs dirs fwks)
+    if(DEFINED "${p}_${v}" AND NOT "${${v}}" STREQUAL "${${p}_${v}}")
       message(FATAL_ERROR
         "cmake_parse_implicit_link_info failed\n"
         "Expected '${p}' implicit ${v}\n"

+ 2 - 0
Tests/SystemInformation/SystemInformation.in

@@ -96,7 +96,9 @@ CMAKE_CXX_LINK_EXECUTABLE == "${CMAKE_CXX_LINK_EXECUTABLE}"
 // implicit link info
 CMAKE_C_IMPLICIT_LINK_LIBRARIES == "${CMAKE_C_IMPLICIT_LINK_LIBRARIES}"
 CMAKE_C_IMPLICIT_LINK_DIRECTORIES == "${CMAKE_C_IMPLICIT_LINK_DIRECTORIES}"
+CMAKE_C_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES == "${CMAKE_C_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES}"
 CMAKE_CXX_IMPLICIT_LINK_LIBRARIES == "${CMAKE_CXX_IMPLICIT_LINK_LIBRARIES}"
 CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES == "${CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES}"
+CMAKE_CXX_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES == "${CMAKE_CXX_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES}"
 
 XCODE_VERSION == "${XCODE_VERSION}"