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.
This commit is contained in:
Brad King 2012-12-05 13:46:04 -05:00
parent 2dd67c7ea0
commit cc676c3a08
10 changed files with 94 additions and 22 deletions

View File

@ -50,6 +50,7 @@ endif()
set(CMAKE_C_IMPLICIT_LINK_LIBRARIES "@CMAKE_C_IMPLICIT_LINK_LIBRARIES@") 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_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_CMCLDEPS_EXECUTABLE@
@SET_CMAKE_CL_SHOWINCLUDE_PREFIX@ @SET_CMAKE_CL_SHOWINCLUDE_PREFIX@

View File

@ -51,6 +51,7 @@ endif()
set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "@CMAKE_CXX_IMPLICIT_LINK_LIBRARIES@") 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_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_CMCLDEPS_EXECUTABLE@
@SET_CMAKE_CL_SHOWINCLUDE_PREFIX@ @SET_CMAKE_CL_SHOWINCLUDE_PREFIX@

View File

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

View File

@ -52,3 +52,4 @@ endif()
set(CMAKE_Fortran_IMPLICIT_LINK_LIBRARIES "@CMAKE_Fortran_IMPLICIT_LINK_LIBRARIES@") 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_DIRECTORIES "@CMAKE_Fortran_IMPLICIT_LINK_DIRECTORIES@")
set(CMAKE_Fortran_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "@CMAKE_Fortran_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES@")

View File

@ -16,9 +16,10 @@
# This is used internally by CMake and should not be included by user # This is used internally by CMake and should not be included by user
# code. # 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_libs_tmp "")
set(implicit_dirs_tmp) set(implicit_dirs_tmp)
set(implicit_fwks_tmp)
set(log "") set(log "")
# Parse implicit linker arguments. # 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") set(log "${log} Library search paths: [${implicit_dirs_match}]\n")
list(APPEND implicit_dirs_tmp ${implicit_dirs_match}) list(APPEND implicit_dirs_tmp ${implicit_dirs_match})
endif() 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. # Cleanup list of libraries and flags.
# We remove items that are not language-specific. # 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() endif()
endforeach() endforeach()
# Cleanup list of library directories. # Cleanup list of library and framework directories.
set(implicit_dirs "") set(desc_dirs "library")
foreach(d IN LISTS implicit_dirs_tmp) set(desc_fwks "framework")
foreach(t dirs fwks)
set(implicit_${t} "")
foreach(d IN LISTS implicit_${t}_tmp)
get_filename_component(dir "${d}" ABSOLUTE) get_filename_component(dir "${d}" ABSOLUTE)
string(FIND "${dir}" "${CMAKE_FILES_DIRECTORY}/" pos) string(FIND "${dir}" "${CMAKE_FILES_DIRECTORY}/" pos)
if(NOT pos LESS 0) if(NOT pos LESS 0)
set(msg ", skipping non-system directory") set(msg ", skipping non-system directory")
else() else()
set(msg "") set(msg "")
list(APPEND implicit_dirs "${dir}") list(APPEND implicit_${t} "${dir}")
endif() endif()
set(log "${log} collapse library dir [${d}] ==> [${dir}]${msg}\n") set(log "${log} collapse ${desc_${t}} dir [${d}] ==> [${dir}]${msg}\n")
endforeach()
list(REMOVE_DUPLICATES implicit_${t})
endforeach() endforeach()
list(REMOVE_DUPLICATES implicit_dirs)
# Log results. # Log results.
set(log "${log} implicit libs: [${implicit_libs}]\n") set(log "${log} implicit libs: [${implicit_libs}]\n")
set(log "${log} implicit dirs: [${implicit_dirs}]\n") set(log "${log} implicit dirs: [${implicit_dirs}]\n")
set(log "${log} implicit fwks: [${implicit_fwks}]\n")
# Return results. # Return results.
set(${lib_var} "${implicit_libs}" PARENT_SCOPE) set(${lib_var} "${implicit_libs}" PARENT_SCOPE)
set(${dir_var} "${implicit_dirs}" PARENT_SCOPE) set(${dir_var} "${implicit_dirs}" PARENT_SCOPE)
set(${fwk_var} "${implicit_fwks}" PARENT_SCOPE)
set(${log_var} "${log}" PARENT_SCOPE) set(${log_var} "${log}" PARENT_SCOPE)
endfunction() endfunction()

View File

@ -256,6 +256,24 @@ set(CMAKE_CXX_CREATE_MACOSX_FRAMEWORK
if(NOT DEFINED CMAKE_FIND_FRAMEWORK) if(NOT DEFINED CMAKE_FIND_FRAMEWORK)
set(CMAKE_FIND_FRAMEWORK FIRST) set(CMAKE_FIND_FRAMEWORK FIRST)
endif() 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 up the default search directories for frameworks
set(CMAKE_SYSTEM_FRAMEWORK_PATH set(CMAKE_SYSTEM_FRAMEWORK_PATH
~/Library/Frameworks ~/Library/Frameworks

View File

@ -1376,10 +1376,31 @@ void cmComputeLinkInformation::DropDirectoryItem(std::string const& item)
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void cmComputeLinkInformation::ComputeFrameworkInfo() void cmComputeLinkInformation::ComputeFrameworkInfo()
{ {
// Avoid adding system framework paths. See "man ld" on OS X. // Avoid adding implicit framework paths.
this->FrameworkPathsEmmitted.insert("/Library/Frameworks"); std::vector<std::string> implicitDirVec;
this->FrameworkPathsEmmitted.insert("/Network/Library/Frameworks");
this->FrameworkPathsEmmitted.insert("/System/Library/Frameworks"); // 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. // Regular expression to extract a framework path and name.
this->SplitFramework.compile("(.*)/(.*)\\.framework$"); this->SplitFramework.compile("(.*)/(.*)\\.framework$");

View File

@ -1624,6 +1624,15 @@ void cmDocumentVariables::DefineVariables(cmake* cm)
"reports the results in this variable.", false, "reports the results in this variable.", false,
"Variables for Languages"); "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 cm->DefineProperty
("CMAKE_<LANG>_IMPLICIT_LINK_LIBRARIES", cmProperty::VARIABLE, ("CMAKE_<LANG>_IMPLICIT_LINK_LIBRARIES", cmProperty::VARIABLE,
"Implicit link libraries and flags detected for language <LANG>.", "Implicit link libraries and flags detected for language <LANG>.",

View File

@ -120,6 +120,7 @@ Framework search paths:
/System/Library/Frameworks/") /System/Library/Frameworks/")
set(mac_i686_gcc_Wlv_libs "") 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_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) list(APPEND platforms mac_i686_gcc_Wlv)
# gcc -arch i686 dummy.c -v # gcc -arch i686 dummy.c -v
@ -146,6 +147,7 @@ Framework search paths:
/System/Library/Frameworks/") /System/Library/Frameworks/")
set(mac_i686_g++_Wlv_libs "stdc++") 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_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) list(APPEND platforms mac_i686_g++_Wlv)
# g++ -arch i686 dummy.cxx -v # g++ -arch i686 dummy.cxx -v
@ -169,6 +171,7 @@ Framework search paths:
/System/Library/Frameworks/") /System/Library/Frameworks/")
set(mac_i686_gfortran_Wlv_libs "gfortranbegin;gfortran") 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_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) list(APPEND platforms mac_i686_gfortran_Wlv)
# gfortran dummy.f -v # gfortran dummy.f -v
@ -195,6 +198,7 @@ Framework search paths:
/System/Library/Frameworks/") /System/Library/Frameworks/")
set(mac_ppc_gcc_Wlv_libs "") 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_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) list(APPEND platforms mac_ppc_gcc_Wlv)
# gcc -arch ppc dummy.c -v # gcc -arch ppc dummy.c -v
@ -221,6 +225,7 @@ Framework search paths:
/System/Library/Frameworks/") /System/Library/Frameworks/")
set(mac_ppc_g++_Wlv_libs "stdc++") 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_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) list(APPEND platforms mac_ppc_g++_Wlv)
# g++ -arch ppc dummy.cxx -v # g++ -arch ppc dummy.cxx -v
@ -499,10 +504,10 @@ list(APPEND platforms msys_g77)
# Test parsing for all above examples. # Test parsing for all above examples.
foreach(p IN LISTS platforms) 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) foreach(v libs dirs fwks)
if(NOT "${${v}}" STREQUAL "${${p}_${v}}") if(DEFINED "${p}_${v}" AND NOT "${${v}}" STREQUAL "${${p}_${v}}")
message(FATAL_ERROR message(FATAL_ERROR
"cmake_parse_implicit_link_info failed\n" "cmake_parse_implicit_link_info failed\n"
"Expected '${p}' implicit ${v}\n" "Expected '${p}' implicit ${v}\n"

View File

@ -96,7 +96,9 @@ CMAKE_CXX_LINK_EXECUTABLE == "${CMAKE_CXX_LINK_EXECUTABLE}"
// implicit link info // implicit link info
CMAKE_C_IMPLICIT_LINK_LIBRARIES == "${CMAKE_C_IMPLICIT_LINK_LIBRARIES}" CMAKE_C_IMPLICIT_LINK_LIBRARIES == "${CMAKE_C_IMPLICIT_LINK_LIBRARIES}"
CMAKE_C_IMPLICIT_LINK_DIRECTORIES == "${CMAKE_C_IMPLICIT_LINK_DIRECTORIES}" 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_LIBRARIES == "${CMAKE_CXX_IMPLICIT_LINK_LIBRARIES}"
CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES == "${CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES}" 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}" XCODE_VERSION == "${XCODE_VERSION}"