From 6c313797418a90f4e108a04e9b9e70b1c32e74ff Mon Sep 17 00:00:00 2001 From: Adam Strzelecki Date: Wed, 3 Sep 2014 21:42:53 +0200 Subject: BundleUtilities: Use find on UNIX for fast executable lookup It makes whole executable process quicker on UNIX, especially for large bundles containing many files, since using find narrows results to only files having executable flags then all further tests follow. Since find ... -perm +0111 is not clearly POSIX compliant and some Linux versions refuse it, it is better to use longer but portable: find ... -perm \( -perm -0100 -o -perm -0010 -o -perm -0001 \) --- Modules/BundleUtilities.cmake | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/Modules/BundleUtilities.cmake b/Modules/BundleUtilities.cmake index 0046c97..9e21231 100644 --- a/Modules/BundleUtilities.cmake +++ b/Modules/BundleUtilities.cmake @@ -378,7 +378,25 @@ endfunction() function(get_bundle_all_executables bundle exes_var) set(exes "") - file(GLOB_RECURSE file_list "${bundle}/*") + if(UNIX) + find_program(find_cmd "find") + mark_as_advanced(find_cmd) + endif() + + # find command is much quicker than checking every file one by one on Unix + # which can take long time for large bundles, and since anyway we expect + # executable to have execute flag set we can narrow the list much quicker. + if(find_cmd) + execute_process(COMMAND "${find_cmd}" "${bundle}" + -type f \( -perm -0100 -o -perm -0010 -o -perm -0001 \) + OUTPUT_VARIABLE file_list + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + string(REPLACE "\n" ";" file_list "${file_list}") + else() + file(GLOB_RECURSE file_list "${bundle}/*") + endif() + foreach(f ${file_list}) is_file_executable("${f}" is_executable) if(is_executable) -- cgit v0.12 From 14bc686fffd1ecf3073d2d394af96bdb6e5b8769 Mon Sep 17 00:00:00 2001 From: Adam Strzelecki Date: Thu, 4 Sep 2014 12:28:41 +0200 Subject: GetPrerequisites: Make sure dyld placeholders are prefixes Mac OS X dyld placeholders should be always prefixes, otherwise this can lead to some undefined behavior. --- Modules/GetPrerequisites.cmake | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/GetPrerequisites.cmake b/Modules/GetPrerequisites.cmake index 05c2edb..49443e3 100644 --- a/Modules/GetPrerequisites.cmake +++ b/Modules/GetPrerequisites.cmake @@ -329,7 +329,7 @@ function(gp_resolve_item context item exepath dirs resolved_item_var) endif() if(NOT resolved) - if(item MATCHES "@executable_path") + if(item MATCHES "^@executable_path") # # @executable_path references are assumed relative to exepath # @@ -347,7 +347,7 @@ function(gp_resolve_item context item exepath dirs resolved_item_var) endif() if(NOT resolved) - if(item MATCHES "@loader_path") + if(item MATCHES "^@loader_path") # # @loader_path references are assumed relative to the # PATH of the given "context" (presumably another library) @@ -367,7 +367,7 @@ function(gp_resolve_item context item exepath dirs resolved_item_var) endif() if(NOT resolved) - if(item MATCHES "@rpath") + if(item MATCHES "^@rpath") # # @rpath references are relative to the paths built into the binaries with -rpath # We handle this case like we do for other Unixes -- cgit v0.12 From f7df82acaaf83515c84d2aa006a06b94f144953e Mon Sep 17 00:00:00 2001 From: Adam Strzelecki Date: Thu, 4 Sep 2014 13:19:29 +0200 Subject: BundleUtilities: Resolve & replace @rpath placeholders This is done by gathering LC_RPATH commands for main bundle executable and using it for @rpath lookup in dependent frameworks. All functions that need to carry rpaths to now take optional argument. This enabled apps using @rpath to be bundled correctly, which will be necessary for upcoming Qt 5.4 that will use @rpath for all frameworks. Check that install_name_tool has -delete_rpath before using it. Otherwise it will fail with Xcode 3.x on 10.5 which has no -delete_rpath option for install_name_tool command, that was first introduced in 10.6 SDK, even that 10.5 supports LC_RPATH and @rpath. --- Modules/BundleUtilities.cmake | 101 ++++++++++++++++++++++++++++++++++------- Modules/GetPrerequisites.cmake | 23 ++++++---- 2 files changed, 98 insertions(+), 26 deletions(-) diff --git a/Modules/BundleUtilities.cmake b/Modules/BundleUtilities.cmake index 9e21231..f7f7128 100644 --- a/Modules/BundleUtilities.cmake +++ b/Modules/BundleUtilities.cmake @@ -19,6 +19,7 @@ # get_bundle_and_executable # get_bundle_all_executables # get_item_key +# get_item_rpaths # clear_bundle_keys # set_bundle_key_values # get_bundle_keys @@ -124,7 +125,7 @@ # :: # # SET_BUNDLE_KEY_VALUES( -# ) +# []) # # Add a key to the list (if necessary) for the given item. If added, # also set all the variables associated with that key. @@ -408,6 +409,29 @@ function(get_bundle_all_executables bundle exes_var) endfunction() +function(get_item_rpaths item rpaths_var) + if(APPLE) + find_program(otool_cmd "otool") + mark_as_advanced(otool_cmd) + endif() + + if(otool_cmd) + execute_process( + COMMAND "${otool_cmd}" -l "${item}" + OUTPUT_VARIABLE load_cmds_ov + ) + string(REGEX REPLACE "[^\n]+cmd LC_RPATH\n[^\n]+\n[^\n]+path ([^\n]+) \\(offset[^\n]+\n" "rpath \\1\n" load_cmds_ov "${load_cmds_ov}") + string(REGEX MATCHALL "rpath [^\n]+" load_cmds_ov "${load_cmds_ov}") + string(REGEX REPLACE "rpath " "" load_cmds_ov "${load_cmds_ov}") + if(load_cmds_ov) + gp_append_unique(${rpaths_var} "${load_cmds_ov}") + endif() + endif() + + set(${rpaths_var} ${${rpaths_var}} PARENT_SCOPE) +endfunction() + + function(get_item_key item key_var) get_filename_component(item_name "${item}" NAME) if(WIN32) @@ -426,12 +450,14 @@ function(clear_bundle_keys keys_var) set(${key}_EMBEDDED_ITEM PARENT_SCOPE) set(${key}_RESOLVED_EMBEDDED_ITEM PARENT_SCOPE) set(${key}_COPYFLAG PARENT_SCOPE) + set(${key}_RPATHS PARENT_SCOPE) endforeach() set(${keys_var} PARENT_SCOPE) endfunction() function(set_bundle_key_values keys_var context item exepath dirs copyflag) + set(rpaths "${ARGV6}") get_filename_component(item_name "${item}" NAME) get_item_key("${item}" key) @@ -441,10 +467,12 @@ function(set_bundle_key_values keys_var context item exepath dirs copyflag) list(LENGTH ${keys_var} length_after) if(NOT length_before EQUAL length_after) - gp_resolve_item("${context}" "${item}" "${exepath}" "${dirs}" resolved_item) + gp_resolve_item("${context}" "${item}" "${exepath}" "${dirs}" resolved_item "${rpaths}") gp_item_default_embedded_path("${item}" default_embedded_path) + get_item_rpaths("${resolved_item}" item_rpaths) + if(item MATCHES "[^/]+\\.framework/") # For frameworks, construct the name under the embedded path from the # opening "${item_name}.framework/" to the closing "/${item_name}": @@ -480,6 +508,8 @@ function(set_bundle_key_values keys_var context item exepath dirs copyflag) set(${key}_EMBEDDED_ITEM "${embedded_item}" PARENT_SCOPE) set(${key}_RESOLVED_EMBEDDED_ITEM "${resolved_embedded_item}" PARENT_SCOPE) set(${key}_COPYFLAG "${copyflag}" PARENT_SCOPE) + set(${key}_RPATHS "${item_rpaths}" PARENT_SCOPE) + set(${key}_RDEP_RPATHS "${rpaths}" PARENT_SCOPE) else() #message("warning: item key '${key}' already in the list, subsequent references assumed identical to first") endif() @@ -500,18 +530,27 @@ function(get_bundle_keys app libs dirs keys_var) # get_bundle_all_executables("${bundle}" exes) + # Set keys for main executable first: + # + set_bundle_key_values(${keys_var} "${executable}" "${executable}" "${exepath}" "${dirs}" 0) + + # Get rpaths specified by main executable: + # + get_item_key("${executable}" executable_key) + set(main_rpaths "${${executable_key}_RPATHS}") + # For each extra lib, accumulate a key as well and then also accumulate # any of its prerequisites. (Extra libs are typically dynamically loaded # plugins: libraries that are prerequisites for full runtime functionality # but that do not show up in otool -L output...) # foreach(lib ${libs}) - set_bundle_key_values(${keys_var} "${lib}" "${lib}" "${exepath}" "${dirs}" 0) + set_bundle_key_values(${keys_var} "${lib}" "${lib}" "${exepath}" "${dirs}" 0 "${main_rpaths}") set(prereqs "") - get_prerequisites("${lib}" prereqs 1 1 "${exepath}" "${dirs}") + get_prerequisites("${lib}" prereqs 1 1 "${exepath}" "${dirs}" "${main_rpaths}") foreach(pr ${prereqs}) - set_bundle_key_values(${keys_var} "${lib}" "${pr}" "${exepath}" "${dirs}" 1) + set_bundle_key_values(${keys_var} "${lib}" "${pr}" "${exepath}" "${dirs}" 1 "${main_rpaths}") endforeach() endforeach() @@ -520,16 +559,27 @@ function(get_bundle_keys app libs dirs keys_var) # binaries in the bundle have been analyzed. # foreach(exe ${exes}) - # Add the exe itself to the keys: + # Main executable is scanned first above: # - set_bundle_key_values(${keys_var} "${exe}" "${exe}" "${exepath}" "${dirs}" 0) + if(NOT "${exe}" STREQUAL "${executable}") + # Add the exe itself to the keys: + # + set_bundle_key_values(${keys_var} "${exe}" "${exe}" "${exepath}" "${dirs}" 0 "${main_rpaths}") + + # Get rpaths specified by executable: + # + get_item_key("${exe}" exe_key) + set(exe_rpaths "${main_rpaths}" "${${exe_key}_RPATHS}") + else() + set(exe_rpaths "${main_rpaths}") + endif() # Add each prerequisite to the keys: # set(prereqs "") - get_prerequisites("${exe}" prereqs 1 1 "${exepath}" "${dirs}") + get_prerequisites("${exe}" prereqs 1 1 "${exepath}" "${dirs}" "${exe_rpaths}") foreach(pr ${prereqs}) - set_bundle_key_values(${keys_var} "${exe}" "${pr}" "${exepath}" "${dirs}" 1) + set_bundle_key_values(${keys_var} "${exe}" "${pr}" "${exepath}" "${dirs}" 1 "${exe_rpaths}") endforeach() endforeach() @@ -543,6 +593,8 @@ function(get_bundle_keys app libs dirs keys_var) set(${key}_EMBEDDED_ITEM "${${key}_EMBEDDED_ITEM}" PARENT_SCOPE) set(${key}_RESOLVED_EMBEDDED_ITEM "${${key}_RESOLVED_EMBEDDED_ITEM}" PARENT_SCOPE) set(${key}_COPYFLAG "${${key}_COPYFLAG}" PARENT_SCOPE) + set(${key}_RPATHS "${${key}_RPATHS}" PARENT_SCOPE) + set(${key}_RDEP_RPATHS "${${key}_RDEP_RPATHS}" PARENT_SCOPE) endforeach() endif() endfunction() @@ -648,8 +700,10 @@ function(fixup_bundle_item resolved_embedded_item exepath dirs) message(FATAL_ERROR "cannot fixup an item that is not in the bundle...") endif() + set(rpaths "${${ikey}_RPATHS}" "${${ikey}_RDEP_RPATHS}") + set(prereqs "") - get_prerequisites("${resolved_embedded_item}" prereqs 1 0 "${exepath}" "${dirs}") + get_prerequisites("${resolved_embedded_item}" prereqs 1 0 "${exepath}" "${dirs}" "${rpaths}") set(changes "") @@ -669,12 +723,28 @@ function(fixup_bundle_item resolved_embedded_item exepath dirs) execute_process(COMMAND chmod u+w "${resolved_embedded_item}") endif() + # Only if install_name_tool supports -delete_rpath: + # + execute_process(COMMAND install_name_tool + OUTPUT_VARIABLE install_name_tool_usage + ERROR_VARIABLE install_name_tool_usage + ) + if(install_name_tool_usage MATCHES ".*-delete_rpath.*") + foreach(rpath ${${ikey}_RPATHS}) + set(changes ${changes} -delete_rpath "${rpath}") + endforeach() + endif() + + if(${ikey}_EMBEDDED_ITEM) + set(changes ${changes} -id "${${ikey}_EMBEDDED_ITEM}") + endif() + # Change this item's id and all of its references in one call # to install_name_tool: # - execute_process(COMMAND install_name_tool - ${changes} -id "${${ikey}_EMBEDDED_ITEM}" "${resolved_embedded_item}" - ) + if(changes) + execute_process(COMMAND install_name_tool ${changes} "${resolved_embedded_item}") + endif() endfunction() @@ -765,10 +835,8 @@ function(verify_bundle_prerequisites bundle result_var info_var) get_bundle_main_executable("${bundle}" main_bundle_exe) - file(GLOB_RECURSE file_list "${bundle}/*") + get_bundle_all_executables("${bundle}" file_list) foreach(f ${file_list}) - is_file_executable("${f}" is_executable) - if(is_executable) get_filename_component(exepath "${f}" PATH) math(EXPR count "${count} + 1") @@ -807,7 +875,6 @@ function(verify_bundle_prerequisites bundle result_var info_var) set(result 0) set(info ${info} "external prerequisites found:\nf='${f}'\nexternal_prereqs='${external_prereqs}'\n") endif() - endif() endforeach() if(result) diff --git a/Modules/GetPrerequisites.cmake b/Modules/GetPrerequisites.cmake index 49443e3..9963517 100644 --- a/Modules/GetPrerequisites.cmake +++ b/Modules/GetPrerequisites.cmake @@ -41,7 +41,7 @@ # :: # # GET_PREREQUISITES( -# ) +# []) # # Get the list of shared library files required by . The list # in the variable named should be empty on first @@ -113,7 +113,8 @@ # # :: # -# GP_RESOLVE_ITEM( ) +# GP_RESOLVE_ITEM( +# []) # # Resolve an item into an existing full path file. # @@ -122,7 +123,8 @@ # # :: # -# GP_RESOLVED_FILE_TYPE( ) +# GP_RESOLVED_FILE_TYPE( +# []) # # Return the type of with respect to . String # describing type of prerequisite is returned in variable named @@ -321,6 +323,7 @@ endfunction() function(gp_resolve_item context item exepath dirs resolved_item_var) set(resolved 0) set(resolved_item "${item}") + set(rpaths "${ARGV5}") # Is it already resolved? # @@ -375,9 +378,9 @@ function(gp_resolve_item context item exepath dirs resolved_item_var) string(REPLACE "@rpath/" "" norpath_item "${item}") set(ri "ri-NOTFOUND") - find_file(ri "${norpath_item}" ${exepath} ${dirs} NO_DEFAULT_PATH) + find_file(ri "${norpath_item}" ${exepath} ${dirs} ${rpaths} NO_DEFAULT_PATH) if(ri) - #message(STATUS "info: 'find_file' in exepath/dirs (${ri})") + #message(STATUS "info: 'find_file' in exepath/dirs/rpaths (${ri})") set(resolved 1) set(resolved_item "${ri}") set(ri "ri-NOTFOUND") @@ -471,6 +474,7 @@ endfunction() function(gp_resolved_file_type original_file file exepath dirs type_var) + set(rpaths "${ARGV5}") #message(STATUS "**") if(NOT IS_ABSOLUTE "${original_file}") @@ -489,7 +493,7 @@ function(gp_resolved_file_type original_file file exepath dirs type_var) if(NOT is_embedded) if(NOT IS_ABSOLUTE "${file}") - gp_resolve_item("${original_file}" "${file}" "${exepath}" "${dirs}" resolved_file) + gp_resolve_item("${original_file}" "${file}" "${exepath}" "${dirs}" resolved_file "${rpaths}") endif() string(TOLOWER "${original_file}" original_lower) @@ -612,6 +616,7 @@ endfunction() function(get_prerequisites target prerequisites_var exclude_system recurse exepath dirs) set(verbose 0) set(eol_char "E") + set(rpaths "${ARGV6}") if(NOT IS_ABSOLUTE "${target}") message("warning: target '${target}' is not absolute...") @@ -834,7 +839,7 @@ function(get_prerequisites target prerequisites_var exclude_system recurse exepa if(add_item AND ${exclude_system}) set(type "") - gp_resolved_file_type("${target}" "${item}" "${exepath}" "${dirs}" type) + gp_resolved_file_type("${target}" "${item}" "${exepath}" "${dirs}" type "${rpaths}") if("${type}" STREQUAL "system") set(add_item 0) @@ -855,7 +860,7 @@ function(get_prerequisites target prerequisites_var exclude_system recurse exepa # that the analysis tools can simply accept it as input. # if(NOT list_length_before_append EQUAL list_length_after_append) - gp_resolve_item("${target}" "${item}" "${exepath}" "${dirs}" resolved_item) + gp_resolve_item("${target}" "${item}" "${exepath}" "${dirs}" resolved_item "${rpaths}") set(unseen_prereqs ${unseen_prereqs} "${resolved_item}") endif() endif() @@ -874,7 +879,7 @@ function(get_prerequisites target prerequisites_var exclude_system recurse exepa if(${recurse}) set(more_inputs ${unseen_prereqs}) foreach(input ${more_inputs}) - get_prerequisites("${input}" ${prerequisites_var} ${exclude_system} ${recurse} "${exepath}" "${dirs}") + get_prerequisites("${input}" ${prerequisites_var} ${exclude_system} ${recurse} "${exepath}" "${dirs}" "${rpaths}") endforeach() endif() -- cgit v0.12 From 83a06bb4abb0302c70095c70306f9d51071c02e4 Mon Sep 17 00:00:00 2001 From: Adam Strzelecki Date: Thu, 4 Sep 2014 15:01:17 +0200 Subject: BundleUtilities: Framework codesign Resources/Info.plist & Current We need to ensure copied framework has proper layout with Resources/Info.plist present next to versioned binary and Current symlink in Versions: https://developer.apple.com/library/mac/technotes/tn2206 https://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/FrameworkAnatomy.html If Resources/ is not present we may try to copy Contents/Info.plist if present to embedded Resources/Info.plist. This is a case of Qt5 that has obsolete/invalid framework layout (see QTBUG-38511). --- Modules/BundleUtilities.cmake | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/Modules/BundleUtilities.cmake b/Modules/BundleUtilities.cmake index f7f7128..445c719 100644 --- a/Modules/BundleUtilities.cmake +++ b/Modules/BundleUtilities.cmake @@ -650,11 +650,30 @@ function(copy_resolved_framework_into_bundle resolved_item resolved_embedded_ite execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}") # Plus Resources, if they exist: - string(REGEX REPLACE "^(.*)/[^/]+/[^/]+/[^/]+$" "\\1/Resources" resolved_resources "${resolved_item}") - string(REGEX REPLACE "^(.*)/[^/]+/[^/]+/[^/]+$" "\\1/Resources" resolved_embedded_resources "${resolved_embedded_item}") + string(REGEX REPLACE "^(.*)/[^/]+$" "\\1/Resources" resolved_resources "${resolved_item}") + string(REGEX REPLACE "^(.*)/[^/]+$" "\\1/Resources" resolved_embedded_resources "${resolved_embedded_item}") if(EXISTS "${resolved_resources}") #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy_directory '${resolved_resources}' '${resolved_embedded_resources}'") execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${resolved_resources}" "${resolved_embedded_resources}") + else() + # Otherwise try at least copy Contents/Info.plist to Resources/Info.plist, if it exists: + string(REGEX REPLACE "^(.*)/[^/]+/[^/]+/[^/]+$" "\\1/Contents/Info.plist" resolved_info_plist "${resolved_item}") + string(REGEX REPLACE "^(.*)/[^/]+$" "\\1/Resources/Info.plist" resolved_embedded_info_plist "${resolved_embedded_item}") + if(EXISTS "${resolved_info_plist}") + #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy_directory '${resolved_info_plist}' '${resolved_embedded_info_plist}'") + execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_info_plist}" "${resolved_embedded_info_plist}") + endif() + endif() + + # Check if framework is versioned and fix it layout + string(REGEX REPLACE "^.*/([^/]+)/[^/]+$" "\\1" resolved_embedded_version "${resolved_embedded_item}") + string(REGEX REPLACE "^(.*)/[^/]+/[^/]+$" "\\1" resolved_embedded_versions "${resolved_embedded_item}") + string(REGEX REPLACE "^.*/([^/]+)/[^/]+/[^/]+$" "\\1" resolved_embedded_versions_basename "${resolved_embedded_item}") + if(resolved_embedded_versions_basename STREQUAL "Versions") + # Ensure Current symlink points to the framework version + if(NOT EXISTS "${resolved_embedded_versions}/Current") + execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "${resolved_embedded_version}" "${resolved_embedded_versions}/Current") + endif() endif() endif() if(UNIX AND NOT APPLE) -- cgit v0.12 From 9b98fd528da4821f316505e7dcc0b12510ae77bc Mon Sep 17 00:00:00 2001 From: Adam Strzelecki Date: Thu, 4 Sep 2014 14:50:59 +0200 Subject: cmake-gui: Make sure we bundle Qt5 Cocoa platform plugin Otherwise CMake.app bundle will not run when using Qt5. --- Source/QtDialog/CMakeLists.txt | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/Source/QtDialog/CMakeLists.txt b/Source/QtDialog/CMakeLists.txt index 8da88c1..03c2fb4 100644 --- a/Source/QtDialog/CMakeLists.txt +++ b/Source/QtDialog/CMakeLists.txt @@ -35,6 +35,32 @@ if (Qt5Widgets_FOUND) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}") + # We need to install Cocoa platform plugin and add qt.conf for Qt5 on Mac. + # FIXME: This should be part of Qt5 CMake scripts, but unfortunatelly + # Qt5 Mac support is missing there. + if(APPLE) + macro(install_qt5_plugin _qt_plugin_name _qt_plugins_var) + get_target_property(_qt_plugin_path "${_qt_plugin_name}" LOCATION) + if(EXISTS "${_qt_plugin_path}") + get_filename_component(_qt_plugin_file "${_qt_plugin_path}" NAME) + get_filename_component(_qt_plugin_type "${_qt_plugin_path}" PATH) + get_filename_component(_qt_plugin_type "${_qt_plugin_type}" NAME) + set(_qt_plugin_dest "${CMAKE_INSTALL_PREFIX}/PlugIns/${_qt_plugin_type}") + install(FILES "${_qt_plugin_path}" + DESTINATION "${_qt_plugin_dest}") + set(${_qt_plugins_var} + "${${_qt_plugins_var}};${_qt_plugin_dest}/${_qt_plugin_file}") + else() + message(FATAL_ERROR "QT plugin ${_qt_plugin_name} not found") + endif() + endmacro() + install_qt5_plugin("Qt5::QCocoaIntegrationPlugin" QT_PLUGINS) + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/qt.conf" + "[Paths]\nPlugins = PlugIns\n") + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/qt.conf" + DESTINATION "${CMAKE_INSTALL_PREFIX}/Resources") + endif() + if(WIN32 AND TARGET Qt5::Core) get_property(_Qt5_Core_LOCATION TARGET Qt5::Core PROPERTY LOCATION) get_filename_component(Qt_BIN_DIR "${_Qt5_Core_LOCATION}" PATH) @@ -168,7 +194,7 @@ if(APPLE OR WIN32) install(CODE " include(\"${CMake_SOURCE_DIR}/Modules/BundleUtilities.cmake\") set(BU_CHMOD_BUNDLE_ITEMS ON) - fixup_bundle(\"${fixup_exe}\" \"\" \"${QT_LIBRARY_DIR};${QT_BINARY_DIR}\") + fixup_bundle(\"${fixup_exe}\" \"${QT_PLUGINS}\" \"${QT_LIBRARY_DIR};${QT_BINARY_DIR}\") ") endif() -- cgit v0.12 From 50e261ddb680f46e7011fe5173dc59d64b12c882 Mon Sep 17 00:00:00 2001 From: Clinton Stimpson Date: Mon, 6 Oct 2014 22:24:10 -0600 Subject: OSX: Warn when attempting to change runtime paths on OS X 10.5 Even though 10.5 supports @rpath, the support is not complete enough for CMake. For instance, install_name_tool doesn't support adding and removing rpaths. Also modifying BundleUtilities test to remove an undesirable cmake generated runtime path. The intent was to build with the install rpath as is done with the other cases in this test. --- Source/cmInstallTargetGenerator.cxx | 80 ++++++++++++++++++++++++------------ Tests/BundleUtilities/CMakeLists.txt | 3 +- 2 files changed, 55 insertions(+), 28 deletions(-) diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx index 8a1c53e..d689c89 100644 --- a/Source/cmInstallTargetGenerator.cxx +++ b/Source/cmInstallTargetGenerator.cxx @@ -677,46 +677,72 @@ cmInstallTargetGenerator return; } - if(this->Target->GetMakefile()->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) + cmMakefile* mf = this->Target->GetMakefile(); + + if(mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) { // If using install_name_tool, set up the rules to modify the rpaths. std::string installNameTool = - this->Target->GetMakefile()-> - GetSafeDefinition("CMAKE_INSTALL_NAME_TOOL"); + mf->GetSafeDefinition("CMAKE_INSTALL_NAME_TOOL"); std::vector oldRuntimeDirs, newRuntimeDirs; cli->GetRPath(oldRuntimeDirs, false); cli->GetRPath(newRuntimeDirs, true); - // Note: These paths are kept unique to avoid install_name_tool corruption. - std::set runpaths; - for(std::vector::const_iterator i = oldRuntimeDirs.begin(); - i != oldRuntimeDirs.end(); ++i) - { - std::string runpath = this->Target->GetMakefile()->GetLocalGenerator()-> - GetGlobalGenerator()->ExpandCFGIntDir(*i, config); + std::string darwin_major_version_s = + mf->GetSafeDefinition("DARWIN_MAJOR_VERSION"); - if(runpaths.find(runpath) == runpaths.end()) - { - runpaths.insert(runpath); - os << indent << "execute_process(COMMAND " << installNameTool << "\n"; - os << indent << " -delete_rpath \"" << runpath << "\"\n"; - os << indent << " \"" << toDestDirPath << "\")\n"; - } + std::stringstream ss(darwin_major_version_s); + int darwin_major_version; + ss >> darwin_major_version; + if(!ss.fail() && darwin_major_version <= 9 && + (!oldRuntimeDirs.empty() || !newRuntimeDirs.empty()) + ) + { + cmOStringStream msg; + msg << "WARNING: Target \"" << this->Target->GetName() + << "\" has runtime paths which cannot be changed during install. " + << "To change runtime paths, OS X version 10.6 or newer is required. " + << "Therefore, runtime paths will not be changed when installing. " + << "CMAKE_BUILD_WITH_INSTALL_RPATH may be used to work around" + " this limitation."; + mf->IssueMessage(cmake::WARNING, msg.str()); } - - runpaths.clear(); - for(std::vector::const_iterator i = newRuntimeDirs.begin(); - i != newRuntimeDirs.end(); ++i) + else { - std::string runpath = this->Target->GetMakefile()->GetLocalGenerator()-> - GetGlobalGenerator()->ExpandCFGIntDir(*i, config); + // Note: These paths are kept unique to avoid + // install_name_tool corruption. + std::set runpaths; + for(std::vector::const_iterator i = oldRuntimeDirs.begin(); + i != oldRuntimeDirs.end(); ++i) + { + std::string runpath = + mf->GetLocalGenerator()-> + GetGlobalGenerator()->ExpandCFGIntDir(*i, config); + + if(runpaths.find(runpath) == runpaths.end()) + { + runpaths.insert(runpath); + os << indent << "execute_process(COMMAND " << installNameTool <<"\n"; + os << indent << " -delete_rpath \"" << runpath << "\"\n"; + os << indent << " \"" << toDestDirPath << "\")\n"; + } + } - if(runpaths.find(runpath) == runpaths.end()) + runpaths.clear(); + for(std::vector::const_iterator i = newRuntimeDirs.begin(); + i != newRuntimeDirs.end(); ++i) { - os << indent << "execute_process(COMMAND " << installNameTool << "\n"; - os << indent << " -add_rpath \"" << runpath << "\"\n"; - os << indent << " \"" << toDestDirPath << "\")\n"; + std::string runpath = + mf->GetLocalGenerator()-> + GetGlobalGenerator()->ExpandCFGIntDir(*i, config); + + if(runpaths.find(runpath) == runpaths.end()) + { + os << indent << "execute_process(COMMAND " << installNameTool <<"\n"; + os << indent << " -add_rpath \"" << runpath << "\"\n"; + os << indent << " \"" << toDestDirPath << "\")\n"; + } } } } diff --git a/Tests/BundleUtilities/CMakeLists.txt b/Tests/BundleUtilities/CMakeLists.txt index 3a1cf55..69ef535 100644 --- a/Tests/BundleUtilities/CMakeLists.txt +++ b/Tests/BundleUtilities/CMakeLists.txt @@ -109,7 +109,8 @@ if(APPLE AND NOT CMAKE_SYSTEM_VERSION VERSION_LESS 9.0) target_link_libraries(testbundleutils3 shared-3 framework-3 ${CMAKE_DL_LIBS}) set_target_properties(testbundleutils3 module3 PROPERTIES - LINK_FLAGS "-Wl,-rpath,@loader_path/") + LINK_FLAGS "-Wl,-rpath,@loader_path/" + BUILD_WITH_INSTALL_RPATH 1) # add custom target to install and test the app add_custom_target(testbundleutils3_test ALL -- cgit v0.12 From 631fadeae9b9077831fc310e7bdc62029a2204df Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 10 Oct 2014 10:23:52 -0400 Subject: Help: Add notes for topic 'fix-OSX-bundle-rpaths-and-Qt5' --- Help/release/dev/fix-OSX-bundle-rpaths-and-Qt5.rst | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 Help/release/dev/fix-OSX-bundle-rpaths-and-Qt5.rst diff --git a/Help/release/dev/fix-OSX-bundle-rpaths-and-Qt5.rst b/Help/release/dev/fix-OSX-bundle-rpaths-and-Qt5.rst new file mode 100644 index 0000000..c8246c5 --- /dev/null +++ b/Help/release/dev/fix-OSX-bundle-rpaths-and-Qt5.rst @@ -0,0 +1,6 @@ +fix-OSX-bundle-rpaths-and-Qt5 +----------------------------- + +* The :module:`BundleUtilities` module learned to resolve and replace + ``@rpath`` placeholders on OS X to correctly bundle applications + using them. -- cgit v0.12