Switch to version of GetPrerequisites.cmake submitted to CMake

git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@5743 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
Bill Somerville 2015-07-31 11:14:31 +00:00
parent 50b307f905
commit eca29808ec
3 changed files with 544 additions and 276 deletions

View File

@ -1,8 +1,16 @@
# - Functions to help assemble a standalone bundle application. #.rst:
# BundleUtilities
# ---------------
#
# Functions to help assemble a standalone bundle application.
#
# A collection of CMake utility functions useful for dealing with .app # A collection of CMake utility functions useful for dealing with .app
# bundles on the Mac and bundle-like directories on any OS. # bundles on the Mac and bundle-like directories on any OS.
# #
# The following functions are provided by this module: # The following functions are provided by this module:
#
# ::
#
# fixup_bundle # fixup_bundle
# copy_and_fixup_bundle # copy_and_fixup_bundle
# verify_app # verify_app
@ -11,6 +19,7 @@
# get_bundle_and_executable # get_bundle_and_executable
# get_bundle_all_executables # get_bundle_all_executables
# get_item_key # get_item_key
# get_item_rpaths
# clear_bundle_keys # clear_bundle_keys
# set_bundle_key_values # set_bundle_key_values
# get_bundle_keys # get_bundle_keys
@ -19,128 +28,181 @@
# fixup_bundle_item # fixup_bundle_item
# verify_bundle_prerequisites # verify_bundle_prerequisites
# verify_bundle_symlinks # verify_bundle_symlinks
#
# Requires CMake 2.6 or greater because it uses function, break and # Requires CMake 2.6 or greater because it uses function, break and
# PARENT_SCOPE. Also depends on GetPrerequisites.cmake. # PARENT_SCOPE. Also depends on GetPrerequisites.cmake.
# #
# ::
#
# FIXUP_BUNDLE(<app> <libs> <dirs>) # FIXUP_BUNDLE(<app> <libs> <dirs>)
#
# Fix up a bundle in-place and make it standalone, such that it can be # Fix up a bundle in-place and make it standalone, such that it can be
# drag-n-drop copied to another machine and run on that machine as long as all # drag-n-drop copied to another machine and run on that machine as long
# of the system libraries are compatible. # as all of the system libraries are compatible.
# #
# If you pass plugins to fixup_bundle as the libs parameter, you should install # If you pass plugins to fixup_bundle as the libs parameter, you should
# them or copy them into the bundle before calling fixup_bundle. The "libs" # install them or copy them into the bundle before calling fixup_bundle.
# parameter is a list of libraries that must be fixed up, but that cannot be # The "libs" parameter is a list of libraries that must be fixed up, but
# determined by otool output analysis. (i.e., plugins) # that cannot be determined by otool output analysis. (i.e., plugins)
# #
# Gather all the keys for all the executables and libraries in a bundle, and # Gather all the keys for all the executables and libraries in a bundle,
# then, for each key, copy each prerequisite into the bundle. Then fix each one # and then, for each key, copy each prerequisite into the bundle. Then
# up according to its own list of prerequisites. # fix each one up according to its own list of prerequisites.
# #
# Then clear all the keys and call verify_app on the final bundle to ensure # Then clear all the keys and call verify_app on the final bundle to
# that it is truly standalone. # ensure that it is truly standalone.
#
# ::
# #
# COPY_AND_FIXUP_BUNDLE(<src> <dst> <libs> <dirs>) # COPY_AND_FIXUP_BUNDLE(<src> <dst> <libs> <dirs>)
# Makes a copy of the bundle <src> at location <dst> and then fixes up the #
# new copied bundle in-place at <dst>... # Makes a copy of the bundle <src> at location <dst> and then fixes up
# the new copied bundle in-place at <dst>...
#
# ::
# #
# VERIFY_APP(<app>) # VERIFY_APP(<app>)
# Verifies that an application <app> appears valid based on running analysis #
# tools on it. Calls "message(FATAL_ERROR" if the application is not verified. # Verifies that an application <app> appears valid based on running
# analysis tools on it. Calls "message(FATAL_ERROR" if the application
# is not verified.
#
# ::
# #
# GET_BUNDLE_MAIN_EXECUTABLE(<bundle> <result_var>) # GET_BUNDLE_MAIN_EXECUTABLE(<bundle> <result_var>)
# The result will be the full path name of the bundle's main executable file #
# or an "error:" prefixed string if it could not be determined. # The result will be the full path name of the bundle's main executable
# file or an "error:" prefixed string if it could not be determined.
#
# ::
# #
# GET_DOTAPP_DIR(<exe> <dotapp_dir_var>) # GET_DOTAPP_DIR(<exe> <dotapp_dir_var>)
# Returns the nearest parent dir whose name ends with ".app" given the full #
# path to an executable. If there is no such parent dir, then simply return # Returns the nearest parent dir whose name ends with ".app" given the
# the dir containing the executable. # full path to an executable. If there is no such parent dir, then
# simply return the dir containing the executable.
# #
# The returned directory may or may not exist. # The returned directory may or may not exist.
# #
# ::
#
# GET_BUNDLE_AND_EXECUTABLE(<app> <bundle_var> <executable_var> <valid_var>) # GET_BUNDLE_AND_EXECUTABLE(<app> <bundle_var> <executable_var> <valid_var>)
#
# Takes either a ".app" directory name or the name of an executable # Takes either a ".app" directory name or the name of an executable
# nested inside a ".app" directory and returns the path to the ".app" # nested inside a ".app" directory and returns the path to the ".app"
# directory in <bundle_var> and the path to its main executable in # directory in <bundle_var> and the path to its main executable in
# <executable_var> # <executable_var>
# #
# ::
#
# GET_BUNDLE_ALL_EXECUTABLES(<bundle> <exes_var>) # GET_BUNDLE_ALL_EXECUTABLES(<bundle> <exes_var>)
# Scans the given bundle recursively for all executable files and accumulates #
# them into a variable. # Scans the given bundle recursively for all executable files and
# accumulates them into a variable.
#
# ::
# #
# GET_ITEM_KEY(<item> <key_var>) # GET_ITEM_KEY(<item> <key_var>)
# Given a file (item) name, generate a key that should be unique considering
# the set of libraries that need copying or fixing up to make a bundle
# standalone. This is essentially the file name including extension with "."
# replaced by "_"
# #
# This key is used as a prefix for CMake variables so that we can associate a # Given a file (item) name, generate a key that should be unique
# set of variables with a given item based on its key. # considering the set of libraries that need copying or fixing up to
# make a bundle standalone. This is essentially the file name including
# extension with "." replaced by "_"
#
# This key is used as a prefix for CMake variables so that we can
# associate a set of variables with a given item based on its key.
#
# ::
# #
# CLEAR_BUNDLE_KEYS(<keys_var>) # CLEAR_BUNDLE_KEYS(<keys_var>)
# Loop over the list of keys, clearing all the variables associated with each
# key. After the loop, clear the list of keys itself.
# #
# Caller of get_bundle_keys should call clear_bundle_keys when done with list # Loop over the list of keys, clearing all the variables associated with
# of keys. # each key. After the loop, clear the list of keys itself.
#
# Caller of get_bundle_keys should call clear_bundle_keys when done with
# list of keys.
#
# ::
# #
# SET_BUNDLE_KEY_VALUES(<keys_var> <context> <item> <exepath> <dirs> # SET_BUNDLE_KEY_VALUES(<keys_var> <context> <item> <exepath> <dirs>
# <copyflag>) # <copyflag> [<rpaths>])
#
# Add a key to the list (if necessary) for the given item. If added, # Add a key to the list (if necessary) for the given item. If added,
# also set all the variables associated with that key. # also set all the variables associated with that key.
# #
# ::
#
# GET_BUNDLE_KEYS(<app> <libs> <dirs> <keys_var>) # GET_BUNDLE_KEYS(<app> <libs> <dirs> <keys_var>)
# Loop over all the executable and library files within the bundle (and given #
# as extra <libs>) and accumulate a list of keys representing them. Set # Loop over all the executable and library files within the bundle (and
# values associated with each key such that we can loop over all of them and # given as extra <libs>) and accumulate a list of keys representing
# copy prerequisite libs into the bundle and then do appropriate # them. Set values associated with each key such that we can loop over
# install_name_tool fixups. # all of them and copy prerequisite libs into the bundle and then do
# appropriate install_name_tool fixups.
#
# ::
# #
# COPY_RESOLVED_ITEM_INTO_BUNDLE(<resolved_item> <resolved_embedded_item>) # COPY_RESOLVED_ITEM_INTO_BUNDLE(<resolved_item> <resolved_embedded_item>)
# Copy a resolved item into the bundle if necessary. Copy is not necessary if #
# the resolved_item is "the same as" the resolved_embedded_item. # Copy a resolved item into the bundle if necessary. Copy is not
# necessary if the resolved_item is "the same as" the
# resolved_embedded_item.
#
# ::
# #
# COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE(<resolved_item> <resolved_embedded_item>) # COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE(<resolved_item> <resolved_embedded_item>)
# Copy a resolved framework into the bundle if necessary. Copy is not necessary
# if the resolved_item is "the same as" the resolved_embedded_item.
# #
# By default, BU_COPY_FULL_FRAMEWORK_CONTENTS is not set. If you want full # Copy a resolved framework into the bundle if necessary. Copy is not
# frameworks embedded in your bundles, set BU_COPY_FULL_FRAMEWORK_CONTENTS to # necessary if the resolved_item is "the same as" the
# ON before calling fixup_bundle. By default, # resolved_embedded_item.
# COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE copies the framework dylib itself plus #
# the framework Resources directory. # By default, BU_COPY_FULL_FRAMEWORK_CONTENTS is not set. If you want
# full frameworks embedded in your bundles, set
# BU_COPY_FULL_FRAMEWORK_CONTENTS to ON before calling fixup_bundle. By
# default, COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE copies the framework
# dylib itself plus the framework Resources directory.
#
# ::
# #
# FIXUP_BUNDLE_ITEM(<resolved_embedded_item> <exepath> <dirs>) # FIXUP_BUNDLE_ITEM(<resolved_embedded_item> <exepath> <dirs>)
# Get the direct/non-system prerequisites of the resolved embedded item. For
# each prerequisite, change the way it is referenced to the value of the
# _EMBEDDED_ITEM keyed variable for that prerequisite. (Most likely changing to
# an "@executable_path" style reference.)
# #
# This function requires that the resolved_embedded_item be "inside" the bundle # Get the direct/non-system prerequisites of the resolved embedded item.
# already. In other words, if you pass plugins to fixup_bundle as the libs # For each prerequisite, change the way it is referenced to the value of
# parameter, you should install them or copy them into the bundle before # the _EMBEDDED_ITEM keyed variable for that prerequisite. (Most likely
# calling fixup_bundle. The "libs" parameter is a list of libraries that must # changing to an "@executable_path" style reference.)
# be fixed up, but that cannot be determined by otool output analysis. (i.e.,
# plugins)
# #
# Also, change the id of the item being fixed up to its own _EMBEDDED_ITEM # This function requires that the resolved_embedded_item be "inside" the
# value. # bundle already. In other words, if you pass plugins to fixup_bundle
# as the libs parameter, you should install them or copy them into the
# bundle before calling fixup_bundle. The "libs" parameter is a list of
# libraries that must be fixed up, but that cannot be determined by
# otool output analysis. (i.e., plugins)
#
# Also, change the id of the item being fixed up to its own
# _EMBEDDED_ITEM value.
# #
# Accumulate changes in a local variable and make *one* call to # Accumulate changes in a local variable and make *one* call to
# install_name_tool at the end of the function with all the changes at once. # install_name_tool at the end of the function with all the changes at
# once.
# #
# If the BU_CHMOD_BUNDLE_ITEMS variable is set then bundle items will be # If the BU_CHMOD_BUNDLE_ITEMS variable is set then bundle items will be
# marked writable before install_name_tool tries to change them. # marked writable before install_name_tool tries to change them.
# #
# ::
#
# VERIFY_BUNDLE_PREREQUISITES(<bundle> <result_var> <info_var>) # VERIFY_BUNDLE_PREREQUISITES(<bundle> <result_var> <info_var>)
# Verifies that the sum of all prerequisites of all files inside the bundle #
# are contained within the bundle or are "system" libraries, presumed to exist # Verifies that the sum of all prerequisites of all files inside the
# everywhere. # bundle are contained within the bundle or are "system" libraries,
# presumed to exist everywhere.
#
# ::
# #
# VERIFY_BUNDLE_SYMLINKS(<bundle> <result_var> <info_var>) # VERIFY_BUNDLE_SYMLINKS(<bundle> <result_var> <info_var>)
# Verifies that any symlinks found in the bundle point to other files that are #
# already also in the bundle... Anything that points to an external file causes # Verifies that any symlinks found in the bundle point to other files
# this function to fail the verification. # that are already also in the bundle... Anything that points to an
# external file causes this function to fail the verification.
#============================================================================= #=============================================================================
# Copyright 2008-2009 Kitware, Inc. # Copyright 2008-2009 Kitware, Inc.
@ -174,8 +236,9 @@ function(get_bundle_main_executable bundle result_var)
# #
set(eol_char "E") set(eol_char "E")
file(READ "${bundle}/Contents/Info.plist" info_plist) file(READ "${bundle}/Contents/Info.plist" info_plist)
string(REGEX REPLACE ";" "\\\\;" info_plist "${info_plist}") string(REPLACE ";" "\\;" info_plist "${info_plist}")
string(REGEX REPLACE "\n" "${eol_char};" info_plist "${info_plist}") string(REPLACE "\n" "${eol_char};" info_plist "${info_plist}")
string(REPLACE "\r" "${eol_char};" info_plist "${info_plist}")
# Scan the lines for "<key>CFBundleExecutable</key>" - the line after that # Scan the lines for "<key>CFBundleExecutable</key>" - the line after that
# is the name of the main executable. # is the name of the main executable.
@ -186,7 +249,7 @@ function(get_bundle_main_executable bundle result_var)
break() break()
endif() endif()
if(line MATCHES "^.*<key>CFBundleExecutable</key>.*$") if(line MATCHES "<key>CFBundleExecutable</key>")
set(line_is_main_executable 1) set(line_is_main_executable 1)
endif() endif()
endforeach() endforeach()
@ -226,7 +289,7 @@ endfunction()
function(get_dotapp_dir exe dotapp_dir_var) function(get_dotapp_dir exe dotapp_dir_var)
set(s "${exe}") set(s "${exe}")
if(s MATCHES "^.*/.*\\.app/.*$") if(s MATCHES "/.*\\.app/")
# If there is a ".app" parent directory, # If there is a ".app" parent directory,
# ascend until we hit it: # ascend until we hit it:
# (typical of a Mac bundle executable) # (typical of a Mac bundle executable)
@ -316,7 +379,25 @@ endfunction()
function(get_bundle_all_executables bundle exes_var) function(get_bundle_all_executables bundle exes_var)
set(exes "") set(exes "")
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}/*") file(GLOB_RECURSE file_list "${bundle}/*")
endif()
foreach(f ${file_list}) foreach(f ${file_list})
is_file_executable("${f}" is_executable) is_file_executable("${f}" is_executable)
if(is_executable) if(is_executable)
@ -328,12 +409,35 @@ function(get_bundle_all_executables bundle exes_var)
endfunction() 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) function(get_item_key item key_var)
get_filename_component(item_name "${item}" NAME) get_filename_component(item_name "${item}" NAME)
if(WIN32) if(WIN32)
string(TOLOWER "${item_name}" item_name) string(TOLOWER "${item_name}" item_name)
endif() endif()
string(REGEX REPLACE "\\." "_" ${key_var} "${item_name}") string(REPLACE "." "_" ${key_var} "${item_name}")
set(${key_var} ${${key_var}} PARENT_SCOPE) set(${key_var} ${${key_var}} PARENT_SCOPE)
endfunction() endfunction()
@ -346,12 +450,18 @@ function(clear_bundle_keys keys_var)
set(${key}_EMBEDDED_ITEM PARENT_SCOPE) set(${key}_EMBEDDED_ITEM PARENT_SCOPE)
set(${key}_RESOLVED_EMBEDDED_ITEM PARENT_SCOPE) set(${key}_RESOLVED_EMBEDDED_ITEM PARENT_SCOPE)
set(${key}_COPYFLAG PARENT_SCOPE) set(${key}_COPYFLAG PARENT_SCOPE)
set(${key}_RPATHS PARENT_SCOPE)
endforeach() endforeach()
set(${keys_var} PARENT_SCOPE) set(${keys_var} PARENT_SCOPE)
endfunction() endfunction()
function(set_bundle_key_values keys_var context item exepath dirs copyflag) function(set_bundle_key_values keys_var context item exepath dirs copyflag)
if(ARGC GREATER 6)
set(rpaths "${ARGV6}")
else()
set(rpaths "")
endif()
get_filename_component(item_name "${item}" NAME) get_filename_component(item_name "${item}" NAME)
get_item_key("${item}" key) get_item_key("${item}" key)
@ -361,10 +471,12 @@ function(set_bundle_key_values keys_var context item exepath dirs copyflag)
list(LENGTH ${keys_var} length_after) list(LENGTH ${keys_var} length_after)
if(NOT length_before EQUAL 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) gp_item_default_embedded_path("${item}" default_embedded_path)
get_item_rpaths("${resolved_item}" item_rpaths)
if(item MATCHES "[^/]+\\.framework/") if(item MATCHES "[^/]+\\.framework/")
# For frameworks, construct the name under the embedded path from the # For frameworks, construct the name under the embedded path from the
# opening "${item_name}.framework/" to the closing "/${item_name}": # opening "${item_name}.framework/" to the closing "/${item_name}":
@ -400,6 +512,8 @@ function(set_bundle_key_values keys_var context item exepath dirs copyflag)
set(${key}_EMBEDDED_ITEM "${embedded_item}" PARENT_SCOPE) set(${key}_EMBEDDED_ITEM "${embedded_item}" PARENT_SCOPE)
set(${key}_RESOLVED_EMBEDDED_ITEM "${resolved_embedded_item}" PARENT_SCOPE) set(${key}_RESOLVED_EMBEDDED_ITEM "${resolved_embedded_item}" PARENT_SCOPE)
set(${key}_COPYFLAG "${copyflag}" PARENT_SCOPE) set(${key}_COPYFLAG "${copyflag}" PARENT_SCOPE)
set(${key}_RPATHS "${item_rpaths}" PARENT_SCOPE)
set(${key}_RDEP_RPATHS "${rpaths}" PARENT_SCOPE)
else() else()
#message("warning: item key '${key}' already in the list, subsequent references assumed identical to first") #message("warning: item key '${key}' already in the list, subsequent references assumed identical to first")
endif() endif()
@ -420,18 +534,27 @@ function(get_bundle_keys app libs dirs keys_var)
# #
get_bundle_all_executables("${bundle}" exes) 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 # For each extra lib, accumulate a key as well and then also accumulate
# any of its prerequisites. (Extra libs are typically dynamically loaded # any of its prerequisites. (Extra libs are typically dynamically loaded
# plugins: libraries that are prerequisites for full runtime functionality # plugins: libraries that are prerequisites for full runtime functionality
# but that do not show up in otool -L output...) # but that do not show up in otool -L output...)
# #
foreach(lib ${libs}) 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 "") set(prereqs "")
get_prerequisites("${lib}" prereqs 1 1 "${exepath}" "${dirs}") get_prerequisites("${lib}" prereqs 1 1 "${exepath}" "${dirs}" "${main_rpaths}")
foreach(pr ${prereqs}) 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()
endforeach() endforeach()
@ -440,16 +563,27 @@ function(get_bundle_keys app libs dirs keys_var)
# binaries in the bundle have been analyzed. # binaries in the bundle have been analyzed.
# #
foreach(exe ${exes}) foreach(exe ${exes})
# Main executable is scanned first above:
#
if(NOT "${exe}" STREQUAL "${executable}")
# Add the exe itself to the keys: # Add the exe itself to the keys:
# #
set_bundle_key_values(${keys_var} "${exe}" "${exe}" "${exepath}" "${dirs}" 0) 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: # Add each prerequisite to the keys:
# #
set(prereqs "") set(prereqs "")
get_prerequisites("${exe}" prereqs 1 1 "${exepath}" "${dirs}") get_prerequisites("${exe}" prereqs 1 1 "${exepath}" "${dirs}" "${exe_rpaths}")
foreach(pr ${prereqs}) 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()
endforeach() endforeach()
@ -463,6 +597,8 @@ function(get_bundle_keys app libs dirs keys_var)
set(${key}_EMBEDDED_ITEM "${${key}_EMBEDDED_ITEM}" PARENT_SCOPE) set(${key}_EMBEDDED_ITEM "${${key}_EMBEDDED_ITEM}" PARENT_SCOPE)
set(${key}_RESOLVED_EMBEDDED_ITEM "${${key}_RESOLVED_EMBEDDED_ITEM}" PARENT_SCOPE) set(${key}_RESOLVED_EMBEDDED_ITEM "${${key}_RESOLVED_EMBEDDED_ITEM}" PARENT_SCOPE)
set(${key}_COPYFLAG "${${key}_COPYFLAG}" 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() endforeach()
endif() endif()
endfunction() endfunction()
@ -518,12 +654,45 @@ function(copy_resolved_framework_into_bundle resolved_item resolved_embedded_ite
execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}") execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}")
# Plus Resources, if they exist: # Plus Resources, if they exist:
string(REGEX REPLACE "^(.*)/[^/]+/[^/]+/[^/]+$" "\\1/Resources" resolved_resources "${resolved_item}") 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_embedded_resources "${resolved_embedded_item}")
if(EXISTS "${resolved_resources}") if(EXISTS "${resolved_resources}")
#message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy_directory '${resolved_resources}' '${resolved_embedded_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}") execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${resolved_resources}" "${resolved_embedded_resources}")
endif() endif()
# Some frameworks e.g. Qt put Info.plist in wrong place, so when it is
# missing in resources, copy it from other well known incorrect locations:
if(NOT EXISTS "${resolved_resources}/Info.plist")
# Check for Contents/Info.plist in framework root (older Qt SDK):
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()
# Restore symlinks in framework root pointing to current framework
# binary and resources:
string(REGEX REPLACE "^(.*)/[^/]+/[^/]+/[^/]+$" "\\1" resolved_embedded_root "${resolved_embedded_item}")
string(REGEX REPLACE "^.*/([^/]+)$" "\\1" resolved_embedded_item_basename "${resolved_embedded_item}")
if(NOT EXISTS "${resolved_embedded_root}/${resolved_embedded_item_basename}")
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "Versions/Current/${resolved_embedded_item_basename}" "${resolved_embedded_root}/${resolved_embedded_item_basename}")
endif()
if(NOT EXISTS "${resolved_embedded_root}/Resources")
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "Versions/Current/Resources" "${resolved_embedded_root}/Resources")
endif()
endif()
endif() endif()
if(UNIX AND NOT APPLE) if(UNIX AND NOT APPLE)
file(RPATH_REMOVE FILE "${resolved_embedded_item}") file(RPATH_REMOVE FILE "${resolved_embedded_item}")
@ -568,8 +737,10 @@ function(fixup_bundle_item resolved_embedded_item exepath dirs)
message(FATAL_ERROR "cannot fixup an item that is not in the bundle...") message(FATAL_ERROR "cannot fixup an item that is not in the bundle...")
endif() endif()
set(rpaths "${${ikey}_RPATHS}" "${${ikey}_RDEP_RPATHS}")
set(prereqs "") 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 "") set(changes "")
@ -589,12 +760,33 @@ function(fixup_bundle_item resolved_embedded_item exepath dirs)
execute_process(COMMAND chmod u+w "${resolved_embedded_item}") execute_process(COMMAND chmod u+w "${resolved_embedded_item}")
endif() 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 # Change this item's id and all of its references in one call
# to install_name_tool: # to install_name_tool:
# #
execute_process(COMMAND install_name_tool if(changes)
${changes} -id "${${ikey}_EMBEDDED_ITEM}" "${resolved_embedded_item}" set(cmd install_name_tool ${changes} "${resolved_embedded_item}")
) execute_process(COMMAND ${cmd} RESULT_VARIABLE install_name_tool_result)
if(NOT install_name_tool_result EQUAL 0)
string(REPLACE ";" "' '" msg "'${cmd}'")
message(FATAL_ERROR "Command failed:\n ${msg}")
endif()
endif()
endfunction() endfunction()
@ -685,10 +877,8 @@ function(verify_bundle_prerequisites bundle result_var info_var)
get_bundle_main_executable("${bundle}" main_bundle_exe) 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}) foreach(f ${file_list})
is_file_executable("${f}" is_executable)
if(is_executable)
get_filename_component(exepath "${f}" PATH) get_filename_component(exepath "${f}" PATH)
math(EXPR count "${count} + 1") math(EXPR count "${count} + 1")
@ -727,7 +917,6 @@ function(verify_bundle_prerequisites bundle result_var info_var)
set(result 0) set(result 0)
set(info ${info} "external prerequisites found:\nf='${f}'\nexternal_prereqs='${external_prereqs}'\n") set(info ${info} "external prerequisites found:\nf='${f}'\nexternal_prereqs='${external_prereqs}'\n")
endif() endif()
endif()
endforeach() endforeach()
if(result) if(result)

View File

@ -1,14 +1,27 @@
# - Functions to analyze and list executable file prerequisites. #.rst:
# This module provides functions to list the .dll, .dylib or .so # GetPrerequisites
# files that an executable or shared library file depends on. (Its # ----------------
#
# Functions to analyze and list executable file prerequisites.
#
# This module provides functions to list the .dll, .dylib or .so files
# that an executable or shared library file depends on. (Its
# prerequisites.) # prerequisites.)
# #
# It uses various tools to obtain the list of required shared library files: # It uses various tools to obtain the list of required shared library
# files:
#
# ::
#
# dumpbin (Windows) # dumpbin (Windows)
# objdump (MinGW on Windows) # objdump (MinGW on Windows)
# ldd (Linux/Unix) # ldd (Linux/Unix)
# otool (Mac OSX) # otool (Mac OSX)
#
# The following functions are provided by this module: # The following functions are provided by this module:
#
# ::
#
# get_prerequisites # get_prerequisites
# list_prerequisites # list_prerequisites
# list_prerequisites_by_glob # list_prerequisites_by_glob
@ -21,87 +34,129 @@
# gp_resolved_file_type # gp_resolved_file_type
# (projects can override with gp_resolved_file_type_override) # (projects can override with gp_resolved_file_type_override)
# gp_file_type # gp_file_type
# Requires CMake 2.6 or greater because it uses function, break, return and #
# PARENT_SCOPE. # Requires CMake 2.6 or greater because it uses function, break, return
# and PARENT_SCOPE.
#
# ::
# #
# GET_PREREQUISITES(<target> <prerequisites_var> <exclude_system> <recurse> # GET_PREREQUISITES(<target> <prerequisites_var> <exclude_system> <recurse>
# <exepath> <dirs>) # <exepath> <dirs> [<rpaths>])
# Get the list of shared library files required by <target>. The list in
# the variable named <prerequisites_var> should be empty on first entry to
# this function. On exit, <prerequisites_var> will contain the list of
# required shared library files.
# #
# <target> is the full path to an executable file. <prerequisites_var> is the # Get the list of shared library files required by <target>. The list
# name of a CMake variable to contain the results. <exclude_system> must be 0 # in the variable named <prerequisites_var> should be empty on first
# or 1 indicating whether to include or exclude "system" prerequisites. If # entry to this function. On exit, <prerequisites_var> will contain the
# <recurse> is set to 1 all prerequisites will be found recursively, if set to # list of required shared library files.
# 0 only direct prerequisites are listed. <exepath> is the path to the top #
# level executable used for @executable_path replacment on the Mac. <dirs> is # <target> is the full path to an executable file. <prerequisites_var>
# a list of paths where libraries might be found: these paths are searched # is the name of a CMake variable to contain the results.
# first when a target without any path info is given. Then standard system # <exclude_system> must be 0 or 1 indicating whether to include or
# locations are also searched: PATH, Framework locations, /usr/lib... # exclude "system" prerequisites. If <recurse> is set to 1 all
# prerequisites will be found recursively, if set to 0 only direct
# prerequisites are listed. <exepath> is the path to the top level
# executable used for @executable_path replacment on the Mac. <dirs> is
# a list of paths where libraries might be found: these paths are
# searched first when a target without any path info is given. Then
# standard system locations are also searched: PATH, Framework
# locations, /usr/lib...
#
# ::
# #
# LIST_PREREQUISITES(<target> [<recurse> [<exclude_system> [<verbose>]]]) # LIST_PREREQUISITES(<target> [<recurse> [<exclude_system> [<verbose>]]])
#
# Print a message listing the prerequisites of <target>. # Print a message listing the prerequisites of <target>.
# #
# <target> is the name of a shared library or executable target or the full # <target> is the name of a shared library or executable target or the
# path to a shared library or executable file. If <recurse> is set to 1 all # full path to a shared library or executable file. If <recurse> is set
# prerequisites will be found recursively, if set to 0 only direct # to 1 all prerequisites will be found recursively, if set to 0 only
# prerequisites are listed. <exclude_system> must be 0 or 1 indicating whether # direct prerequisites are listed. <exclude_system> must be 0 or 1
# to include or exclude "system" prerequisites. With <verbose> set to 0 only # indicating whether to include or exclude "system" prerequisites. With
# the full path names of the prerequisites are printed, set to 1 extra # <verbose> set to 0 only the full path names of the prerequisites are
# informatin will be displayed. # printed, set to 1 extra informatin will be displayed.
#
# ::
# #
# LIST_PREREQUISITES_BY_GLOB(<glob_arg> <glob_exp>) # LIST_PREREQUISITES_BY_GLOB(<glob_arg> <glob_exp>)
# Print the prerequisites of shared library and executable files matching a #
# globbing pattern. <glob_arg> is GLOB or GLOB_RECURSE and <glob_exp> is a # Print the prerequisites of shared library and executable files
# globbing expression used with "file(GLOB" or "file(GLOB_RECURSE" to retrieve # matching a globbing pattern. <glob_arg> is GLOB or GLOB_RECURSE and
# a list of matching files. If a matching file is executable, its prerequisites # <glob_exp> is a globbing expression used with "file(GLOB" or
# are listed. # "file(GLOB_RECURSE" to retrieve a list of matching files. If a
# matching file is executable, its prerequisites are listed.
# #
# Any additional (optional) arguments provided are passed along as the # Any additional (optional) arguments provided are passed along as the
# optional arguments to the list_prerequisites calls. # optional arguments to the list_prerequisites calls.
# #
# ::
#
# GP_APPEND_UNIQUE(<list_var> <value>) # GP_APPEND_UNIQUE(<list_var> <value>)
# Append <value> to the list variable <list_var> only if the value is not #
# already in the list. # Append <value> to the list variable <list_var> only if the value is
# not already in the list.
#
# ::
# #
# IS_FILE_EXECUTABLE(<file> <result_var>) # IS_FILE_EXECUTABLE(<file> <result_var>)
# Return 1 in <result_var> if <file> is a binary executable, 0 otherwise. #
# Return 1 in <result_var> if <file> is a binary executable, 0
# otherwise.
#
# ::
# #
# GP_ITEM_DEFAULT_EMBEDDED_PATH(<item> <default_embedded_path_var>) # GP_ITEM_DEFAULT_EMBEDDED_PATH(<item> <default_embedded_path_var>)
#
# Return the path that others should refer to the item by when the item # Return the path that others should refer to the item by when the item
# is embedded inside a bundle. # is embedded inside a bundle.
# #
# Override on a per-project basis by providing a project-specific # Override on a per-project basis by providing a project-specific
# gp_item_default_embedded_path_override function. # gp_item_default_embedded_path_override function.
# #
# GP_RESOLVE_ITEM(<context> <item> <exepath> <dirs> <resolved_item_var>) # ::
#
# GP_RESOLVE_ITEM(<context> <item> <exepath> <dirs> <resolved_item_var>
# [<rpaths>])
#
# Resolve an item into an existing full path file. # Resolve an item into an existing full path file.
# #
# Override on a per-project basis by providing a project-specific # Override on a per-project basis by providing a project-specific
# gp_resolve_item_override function. # gp_resolve_item_override function.
# #
# GP_RESOLVED_FILE_TYPE(<original_file> <file> <exepath> <dirs> <type_var>) # ::
#
# GP_RESOLVED_FILE_TYPE(<original_file> <file> <exepath> <dirs> <type_var>
# [<rpaths>])
#
# Return the type of <file> with respect to <original_file>. String # Return the type of <file> with respect to <original_file>. String
# describing type of prerequisite is returned in variable named <type_var>. # describing type of prerequisite is returned in variable named
# <type_var>.
# #
# Use <exepath> and <dirs> if necessary to resolve non-absolute <file> # Use <exepath> and <dirs> if necessary to resolve non-absolute <file>
# values -- but only for non-embedded items. # values -- but only for non-embedded items.
# #
# Possible types are: # Possible types are:
#
# ::
#
# system # system
# local # local
# embedded # embedded
# other # other
#
# Override on a per-project basis by providing a project-specific # Override on a per-project basis by providing a project-specific
# gp_resolved_file_type_override function. # gp_resolved_file_type_override function.
# #
# ::
#
# GP_FILE_TYPE(<original_file> <file> <type_var>) # GP_FILE_TYPE(<original_file> <file> <type_var>)
#
# Return the type of <file> with respect to <original_file>. String # Return the type of <file> with respect to <original_file>. String
# describing type of prerequisite is returned in variable named <type_var>. # describing type of prerequisite is returned in variable named
# <type_var>.
# #
# Possible types are: # Possible types are:
#
# ::
#
# system # system
# local # local
# embedded # embedded
@ -124,7 +179,7 @@ function(gp_append_unique list_var value)
set(contains 0) set(contains 0)
foreach(item ${${list_var}}) foreach(item ${${list_var}})
if("${item}" STREQUAL "${value}") if(item STREQUAL "${value}")
set(contains 1) set(contains 1)
break() break()
endif() endif()
@ -174,9 +229,14 @@ function(is_file_executable file result_var)
if(file_cmd) if(file_cmd)
execute_process(COMMAND "${file_cmd}" "${file_full}" execute_process(COMMAND "${file_cmd}" "${file_full}"
RESULT_VARIABLE file_rv
OUTPUT_VARIABLE file_ov OUTPUT_VARIABLE file_ov
ERROR_VARIABLE file_ev
OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_STRIP_TRAILING_WHITESPACE
) )
if(NOT file_rv STREQUAL "0")
message(FATAL_ERROR "${file_cmd} failed: ${file_rv}\n${file_ev}")
endif()
# Replace the name of the file in the output with a placeholder token # Replace the name of the file in the output with a placeholder token
# (the string " _file_full_ ") so that just in case the path name of # (the string " _file_full_ ") so that just in case the path name of
@ -205,6 +265,13 @@ function(is_file_executable file result_var)
return() return()
endif() endif()
# "file" version 5.22 does not print "(used shared libraries)"
# but uses "interpreter"
if("${file_ov}" MATCHES "shared object.*interpreter")
set(${result_var} 1 PARENT_SCOPE)
return()
endif()
else() else()
message(STATUS "warning: No 'file' command, skipping execute_process...") message(STATUS "warning: No 'file' command, skipping execute_process...")
endif() endif()
@ -268,6 +335,11 @@ endfunction()
function(gp_resolve_item context item exepath dirs resolved_item_var) function(gp_resolve_item context item exepath dirs resolved_item_var)
set(resolved 0) set(resolved 0)
set(resolved_item "${item}") set(resolved_item "${item}")
if(ARGC GREATER 5)
set(rpaths "${ARGV5}")
else()
set(rpaths "")
endif()
# Is it already resolved? # Is it already resolved?
# #
@ -276,7 +348,7 @@ function(gp_resolve_item context item exepath dirs resolved_item_var)
endif() endif()
if(NOT resolved) if(NOT resolved)
if(item MATCHES "@executable_path") if(item MATCHES "^@executable_path")
# #
# @executable_path references are assumed relative to exepath # @executable_path references are assumed relative to exepath
# #
@ -294,7 +366,7 @@ function(gp_resolve_item context item exepath dirs resolved_item_var)
endif() endif()
if(NOT resolved) if(NOT resolved)
if(item MATCHES "@loader_path") if(item MATCHES "^@loader_path")
# #
# @loader_path references are assumed relative to the # @loader_path references are assumed relative to the
# PATH of the given "context" (presumably another library) # PATH of the given "context" (presumably another library)
@ -314,7 +386,7 @@ function(gp_resolve_item context item exepath dirs resolved_item_var)
endif() endif()
if(NOT resolved) if(NOT resolved)
if(item MATCHES "@rpath") if(item MATCHES "^@rpath")
# #
# @rpath references are relative to the paths built into the binaries with -rpath # @rpath references are relative to the paths built into the binaries with -rpath
# We handle this case like we do for other Unixes # We handle this case like we do for other Unixes
@ -322,9 +394,9 @@ function(gp_resolve_item context item exepath dirs resolved_item_var)
string(REPLACE "@rpath/" "" norpath_item "${item}") string(REPLACE "@rpath/" "" norpath_item "${item}")
set(ri "ri-NOTFOUND") 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) 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 1)
set(resolved_item "${ri}") set(resolved_item "${ri}")
set(ri "ri-NOTFOUND") set(ri "ri-NOTFOUND")
@ -418,6 +490,11 @@ endfunction()
function(gp_resolved_file_type original_file file exepath dirs type_var) function(gp_resolved_file_type original_file file exepath dirs type_var)
if(ARGC GREATER 5)
set(rpaths "${ARGV5}")
else()
set(rpaths "")
endif()
#message(STATUS "**") #message(STATUS "**")
if(NOT IS_ABSOLUTE "${original_file}") if(NOT IS_ABSOLUTE "${original_file}")
@ -436,7 +513,7 @@ function(gp_resolved_file_type original_file file exepath dirs type_var)
if(NOT is_embedded) if(NOT is_embedded)
if(NOT IS_ABSOLUTE "${file}") 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() endif()
string(TOLOWER "${original_file}" original_lower) string(TOLOWER "${original_file}" original_lower)
@ -456,10 +533,10 @@ function(gp_resolved_file_type original_file file exepath dirs type_var)
if(WIN32) if(WIN32)
string(TOLOWER "$ENV{SystemRoot}" sysroot) string(TOLOWER "$ENV{SystemRoot}" sysroot)
string(REGEX REPLACE "\\\\" "/" sysroot "${sysroot}") file(TO_CMAKE_PATH "${sysroot}" sysroot)
string(TOLOWER "$ENV{windir}" windir) string(TOLOWER "$ENV{windir}" windir)
string(REGEX REPLACE "\\\\" "/" windir "${windir}") file(TO_CMAKE_PATH "${windir}" windir)
if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*msvc[^/]+dll)") if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*msvc[^/]+dll)")
set(is_system 1) set(is_system 1)
@ -471,11 +548,21 @@ function(gp_resolved_file_type original_file file exepath dirs type_var)
if(CYGPATH_EXECUTABLE) if(CYGPATH_EXECUTABLE)
execute_process(COMMAND ${CYGPATH_EXECUTABLE} -W execute_process(COMMAND ${CYGPATH_EXECUTABLE} -W
RESULT_VARIABLE env_rv
OUTPUT_VARIABLE env_windir OUTPUT_VARIABLE env_windir
ERROR_VARIABLE env_ev
OUTPUT_STRIP_TRAILING_WHITESPACE) OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT env_rv STREQUAL "0")
message(FATAL_ERROR "${CYGPATH_EXECUTABLE} -W failed: ${env_rv}\n${env_ev}")
endif()
execute_process(COMMAND ${CYGPATH_EXECUTABLE} -S execute_process(COMMAND ${CYGPATH_EXECUTABLE} -S
RESULT_VARIABLE env_rv
OUTPUT_VARIABLE env_sysdir OUTPUT_VARIABLE env_sysdir
ERROR_VARIABLE env_ev
OUTPUT_STRIP_TRAILING_WHITESPACE) OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT env_rv STREQUAL "0")
message(FATAL_ERROR "${CYGPATH_EXECUTABLE} -S failed: ${env_rv}\n${env_ev}")
endif()
string(TOLOWER "${env_windir}" windir) string(TOLOWER "${env_windir}" windir)
string(TOLOWER "${env_sysdir}" sysroot) string(TOLOWER "${env_sysdir}" sysroot)
@ -489,14 +576,14 @@ function(gp_resolved_file_type original_file file exepath dirs type_var)
if(NOT is_system) if(NOT is_system)
get_filename_component(original_path "${original_lower}" PATH) get_filename_component(original_path "${original_lower}" PATH)
get_filename_component(path "${lower}" PATH) get_filename_component(path "${lower}" PATH)
if("${original_path}" STREQUAL "${path}") if(original_path STREQUAL path)
set(is_local 1) set(is_local 1)
else() else()
string(LENGTH "${original_path}/" original_length) string(LENGTH "${original_path}/" original_length)
string(LENGTH "${lower}" path_length) string(LENGTH "${lower}" path_length)
if(${path_length} GREATER ${original_length}) if(${path_length} GREATER ${original_length})
string(SUBSTRING "${lower}" 0 ${original_length} path) string(SUBSTRING "${lower}" 0 ${original_length} path)
if("${original_path}/" STREQUAL "${path}") if("${original_path}/" STREQUAL path)
set(is_embedded 1) set(is_embedded 1)
endif() endif()
endif() endif()
@ -559,6 +646,11 @@ endfunction()
function(get_prerequisites target prerequisites_var exclude_system recurse exepath dirs) function(get_prerequisites target prerequisites_var exclude_system recurse exepath dirs)
set(verbose 0) set(verbose 0)
set(eol_char "E") set(eol_char "E")
if(ARGC GREATER 6)
set(rpaths "${ARGV6}")
else()
set(rpaths "")
endif()
if(NOT IS_ABSOLUTE "${target}") if(NOT IS_ABSOLUTE "${target}")
message("warning: target '${target}' is not absolute...") message("warning: target '${target}' is not absolute...")
@ -584,7 +676,7 @@ function(get_prerequisites target prerequisites_var exclude_system recurse exepa
# Try to choose the right tool by default. Caller can set gp_tool prior to # Try to choose the right tool by default. Caller can set gp_tool prior to
# calling this function to force using a different tool. # calling this function to force using a different tool.
# #
if("${gp_tool}" STREQUAL "") if(NOT gp_tool)
set(gp_tool "ldd") set(gp_tool "ldd")
if(APPLE) if(APPLE)
@ -608,52 +700,38 @@ function(get_prerequisites target prerequisites_var exclude_system recurse exepa
return() return()
endif() endif()
find_program(gp_grep_cmd grep) set(gp_cmd_maybe_filter) # optional command to pre-filter gp_tool results
set(gp_tool_known 0) if(gp_tool STREQUAL "ldd")
set(gp_use_filter 0)
if("${gp_tool}" STREQUAL "ldd")
set(gp_cmd_args "") set(gp_cmd_args "")
set(gp_regex "^[\t ]*[^\t ]+ => ([^\t\(]+) .*${eol_char}$") set(gp_regex "^[\t ]*[^\t ]+ => ([^\t\(]+) .*${eol_char}$")
set(gp_regex_error "not found${eol_char}$") set(gp_regex_error "not found${eol_char}$")
set(gp_regex_fallback "^[\t ]*([^\t ]+) => ([^\t ]+).*${eol_char}$") set(gp_regex_fallback "^[\t ]*([^\t ]+) => ([^\t ]+).*${eol_char}$")
set(gp_regex_cmp_count 1) set(gp_regex_cmp_count 1)
set(gp_tool_known 1) elseif(gp_tool STREQUAL "otool")
endif()
if("${gp_tool}" STREQUAL "otool")
set(gp_cmd_args "-L") set(gp_cmd_args "-L")
set(gp_regex "^\t([^\t]+) \\(compatibility version ([0-9]+.[0-9]+.[0-9]+), current version ([0-9]+.[0-9]+.[0-9]+)\\)${eol_char}$") set(gp_regex "^\t([^\t]+) \\(compatibility version ([0-9]+.[0-9]+.[0-9]+), current version ([0-9]+.[0-9]+.[0-9]+)\\)${eol_char}$")
set(gp_regex_error "") set(gp_regex_error "")
set(gp_regex_fallback "") set(gp_regex_fallback "")
set(gp_regex_cmp_count 3) set(gp_regex_cmp_count 3)
set(gp_tool_known 1) elseif(gp_tool STREQUAL "dumpbin")
endif()
if("${gp_tool}" STREQUAL "dumpbin")
set(gp_cmd_args "/dependents") set(gp_cmd_args "/dependents")
set(gp_regex "^ ([^ ].*[Dd][Ll][Ll])${eol_char}$") set(gp_regex "^ ([^ ].*[Dd][Ll][Ll])${eol_char}$")
set(gp_regex_error "") set(gp_regex_error "")
set(gp_regex_fallback "") set(gp_regex_fallback "")
set(gp_regex_cmp_count 1) set(gp_regex_cmp_count 1)
set(gp_tool_known 1) elseif(gp_tool STREQUAL "objdump")
endif()
if("${gp_tool}" STREQUAL "objdump")
set(gp_cmd_args "-p") set(gp_cmd_args "-p")
set(gp_regex "^\t*DLL Name: (.*\\.[Dd][Ll][Ll])${eol_char}$") set(gp_regex "^\t*DLL Name: (.*\\.[Dd][Ll][Ll])${eol_char}$")
set(gp_regex_error "") set(gp_regex_error "")
set(gp_regex_fallback "") set(gp_regex_fallback "")
set(gp_regex_cmp_count 1) set(gp_regex_cmp_count 1)
set(gp_tool_known 1) # objdump generaates copious output so we create a grep filter to pre-filter results
find_program(gp_grep_cmd grep)
if(gp_grep_cmd) if(gp_grep_cmd)
set(gp_grep_args "^[[:blank:]]*DLL Name: ") set(gp_cmd_maybe_filter COMMAND ${gp_grep_cmd} "^[[:blank:]]*DLL Name: ")
set(gp_use_filter 1)
endif() endif()
endif() else()
if(NOT gp_tool_known)
message(STATUS "warning: gp_tool='${gp_tool}' is an unknown tool...") message(STATUS "warning: gp_tool='${gp_tool}' is an unknown tool...")
message(STATUS "CMake function get_prerequisites needs more code to handle '${gp_tool}'") message(STATUS "CMake function get_prerequisites needs more code to handle '${gp_tool}'")
message(STATUS "Valid gp_tool values are dumpbin, ldd, objdump and otool.") message(STATUS "Valid gp_tool values are dumpbin, ldd, objdump and otool.")
@ -661,7 +739,7 @@ function(get_prerequisites target prerequisites_var exclude_system recurse exepa
endif() endif()
if("${gp_tool}" STREQUAL "dumpbin") if(gp_tool STREQUAL "dumpbin")
# When running dumpbin, it also needs the "Common7/IDE" directory in the # When running dumpbin, it also needs the "Common7/IDE" directory in the
# PATH. It will already be in the PATH if being run from a Visual Studio # PATH. It will already be in the PATH if being run from a Visual Studio
# command prompt. Add it to the PATH here in case we are running from a # command prompt. Add it to the PATH here in case we are running from a
@ -676,7 +754,7 @@ function(get_prerequisites target prerequisites_var exclude_system recurse exepa
set(gp_found_cmd_dlls_dir 0) set(gp_found_cmd_dlls_dir 0)
file(TO_CMAKE_PATH "$ENV{PATH}" env_path) file(TO_CMAKE_PATH "$ENV{PATH}" env_path)
foreach(gp_env_path_element ${env_path}) foreach(gp_env_path_element ${env_path})
if("${gp_env_path_element}" STREQUAL "${gp_cmd_dlls_dir}") if(gp_env_path_element STREQUAL gp_cmd_dlls_dir)
set(gp_found_cmd_dlls_dir 1) set(gp_found_cmd_dlls_dir 1)
endif() endif()
endforeach() endforeach()
@ -690,11 +768,13 @@ function(get_prerequisites target prerequisites_var exclude_system recurse exepa
# #
# </setup-gp_tool-vars> # </setup-gp_tool-vars>
if("${gp_tool}" STREQUAL "ldd") if(gp_tool STREQUAL "ldd")
set(old_ld_env "$ENV{LD_LIBRARY_PATH}") set(old_ld_env "$ENV{LD_LIBRARY_PATH}")
foreach(dir ${exepath} ${dirs}) set(new_ld_env "${exepath}")
set(ENV{LD_LIBRARY_PATH} "${dir}:$ENV{LD_LIBRARY_PATH}") foreach(dir ${dirs})
set(new_ld_env "${new_ld_env}:${dir}")
endforeach() endforeach()
set(ENV{LD_LIBRARY_PATH} "${new_ld_env}:$ENV{LD_LIBRARY_PATH}")
endif() endif()
@ -705,28 +785,23 @@ function(get_prerequisites target prerequisites_var exclude_system recurse exepa
# Run gp_cmd on the target: # Run gp_cmd on the target:
# #
if(gp_use_filter)
execute_process( execute_process(
COMMAND ${gp_cmd} ${gp_cmd_args} ${target} COMMAND ${gp_cmd} ${gp_cmd_args} ${target}
COMMAND ${gp_grep_cmd} ${gp_grep_args} ${gp_cmd_maybe_filter}
RESULT_VARIABLE gp_cmd_rv RESULT_VARIABLE gp_rv
OUTPUT_VARIABLE gp_cmd_ov OUTPUT_VARIABLE gp_cmd_ov
ERROR_VARIABLE gp_cmd_ev ERROR_VARIABLE gp_ev
ERROR_STRIP_TRAILING_WHITESPACE
) )
if(NOT gp_rv STREQUAL "0")
if(gp_tool STREQUAL "dumpbin")
# dumpbin error messages seem to go to stdout
message(FATAL_ERROR "${gp_cmd} failed: ${gp_rv}\n${gp_ev}\n${gp_cmd_ov}")
else() else()
execute_process( message(FATAL_ERROR "${gp_cmd} failed: ${gp_rv}\n${gp_ev}")
COMMAND ${gp_cmd} ${gp_cmd_args} ${target}
RESULT_VARIABLE gp_cmd_rv
OUTPUT_VARIABLE gp_cmd_ov
ERROR_VARIABLE gp_cmd_ev
ERROR_STRIP_TRAILING_WHITESPACE
)
endif() endif()
if(NOT "${gp_cmd_rv}" STREQUAL "0")
message(FATAL_ERROR "Get prerequisites command failed: ${gp_cmd_rv}\n${gp_cmd_ev}\n${gp_cmd_ov}")
endif() endif()
if("${gp_tool}" STREQUAL "ldd")
if(gp_tool STREQUAL "ldd")
set(ENV{LD_LIBRARY_PATH} "${old_ld_env}") set(ENV{LD_LIBRARY_PATH} "${old_ld_env}")
endif() endif()
@ -740,17 +815,22 @@ function(get_prerequisites target prerequisites_var exclude_system recurse exepa
# Convert to a list of lines: # Convert to a list of lines:
# #
string(REGEX REPLACE ";" "\\\\;" candidates "${gp_cmd_ov}") string(REPLACE ";" "\\;" candidates "${gp_cmd_ov}")
string(REGEX REPLACE "\n" "${eol_char};" candidates "${candidates}") string(REPLACE "\n" "${eol_char};" candidates "${candidates}")
# check for install id and remove it from list, since otool -L can include a # check for install id and remove it from list, since otool -L can include a
# reference to itself # reference to itself
set(gp_install_id) set(gp_install_id)
if("${gp_tool}" STREQUAL "otool") if(gp_tool STREQUAL "otool")
execute_process( execute_process(
COMMAND otool -D ${target} COMMAND otool -D ${target}
RESULT_VARIABLE otool_rv
OUTPUT_VARIABLE gp_install_id_ov OUTPUT_VARIABLE gp_install_id_ov
ERROR_VARIABLE otool_ev
) )
if(NOT otool_rv STREQUAL "0")
message(FATAL_ERROR "otool -D failed: ${otool_rv}\n${otool_ev}")
endif()
# second line is install name # second line is install name
string(REGEX REPLACE ".*:\n" "" gp_install_id "${gp_install_id_ov}") string(REGEX REPLACE ".*:\n" "" gp_install_id "${gp_install_id_ov}")
if(gp_install_id) if(gp_install_id)
@ -796,15 +876,15 @@ function(get_prerequisites target prerequisites_var exclude_system recurse exepa
# #
set(add_item 1) set(add_item 1)
if("${item}" STREQUAL "${gp_install_id}") if(item STREQUAL gp_install_id)
set(add_item 0) set(add_item 0)
endif() endif()
if(add_item AND ${exclude_system}) if(add_item AND ${exclude_system})
set(type "") 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") if(type STREQUAL "system")
set(add_item 0) set(add_item 0)
endif() endif()
endif() endif()
@ -823,7 +903,7 @@ function(get_prerequisites target prerequisites_var exclude_system recurse exepa
# that the analysis tools can simply accept it as input. # that the analysis tools can simply accept it as input.
# #
if(NOT list_length_before_append EQUAL list_length_after_append) 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}") set(unseen_prereqs ${unseen_prereqs} "${resolved_item}")
endif() endif()
endif() endif()
@ -842,7 +922,7 @@ function(get_prerequisites target prerequisites_var exclude_system recurse exepa
if(${recurse}) if(${recurse})
set(more_inputs ${unseen_prereqs}) set(more_inputs ${unseen_prereqs})
foreach(input ${more_inputs}) 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() endforeach()
endif() endif()
@ -851,22 +931,22 @@ endfunction()
function(list_prerequisites target) function(list_prerequisites target)
if("${ARGV1}" STREQUAL "") if(ARGC GREATER 1 AND NOT "${ARGV1}" STREQUAL "")
set(all 1)
else()
set(all "${ARGV1}") set(all "${ARGV1}")
else()
set(all 1)
endif() endif()
if("${ARGV2}" STREQUAL "") if(ARGC GREATER 2 AND NOT "${ARGV2}" STREQUAL "")
set(exclude_system 0)
else()
set(exclude_system "${ARGV2}") set(exclude_system "${ARGV2}")
else()
set(exclude_system 0)
endif() endif()
if("${ARGV3}" STREQUAL "") if(ARGC GREATER 3 AND NOT "${ARGV3}" STREQUAL "")
set(verbose 0)
else()
set(verbose "${ARGV3}") set(verbose "${ARGV3}")
else()
set(verbose 0)
endif() endif()
set(count 0) set(count 0)

View File

@ -1235,7 +1235,6 @@ file (APPEND \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${WSJT_QT_CONF_DESTINATION
set (gp_tool ${gp_tool}) set (gp_tool ${gp_tool})
# canonicalize path in install context # canonicalize path in install context
get_filename_component (the_exe ${fixup_exe} REALPATH) get_filename_component (the_exe ${fixup_exe} REALPATH)
message (STATUS \"fixup_exe: \${the_exe}\")
fixup_bundle (\"\${the_exe}\" \"\${QTPLUGINS}\" \"${fixup_library_dirs}\") fixup_bundle (\"\${the_exe}\" \"\${QTPLUGINS}\" \"${fixup_library_dirs}\")
" "
#COMPONENT runtime #COMPONENT runtime