1 # Special version of BundleUtilities that calls to a local GetPrerequisites which implements a caching mechanism. 2 # Thank you to Daniel Maleike for the contribution 4 message(
"Using MITK version of BundleUtilities.cmake")
6 # Distributed under the OSI-approved BSD 3-Clause License. See accompanying 7 # file Copyright.txt or https://cmake.org/licensing for details. 13 # Functions to help assemble a standalone bundle application. 15 # A collection of CMake utility functions useful for dealing with .app 16 # bundles on the Mac and bundle-like directories on any OS. 18 # The following functions are provided by this module: 23 # copy_and_fixup_bundle 25 # get_bundle_main_executable 27 # get_bundle_and_executable 28 # get_bundle_all_executables 32 # set_bundle_key_values 34 # copy_resolved_item_into_bundle 35 # copy_resolved_framework_into_bundle 37 # verify_bundle_prerequisites 38 # verify_bundle_symlinks 40 # Requires CMake 2.6 or greater because it uses function, break and 41 # PARENT_SCOPE. Also depends on GetPrerequisites.cmake. 45 # FIXUP_BUNDLE(<app> <libs> <dirs>) 47 # Fix up a bundle in-place and make it standalone, such that it can be 48 # drag-n-drop copied to another machine and run on that machine as long 49 # as all of the system libraries are compatible. 51 # If you pass plugins to fixup_bundle as the libs parameter, you should 52 # install them or copy them into the bundle before calling fixup_bundle. 53 # The "libs" parameter is a list of libraries that must be fixed up, but 54 # that cannot be determined by otool output analysis. (i.e., plugins) 56 # Gather all the keys for all the executables and libraries in a bundle, 57 # and then, for each key, copy each prerequisite into the bundle. Then 58 # fix each one up according to its own list of prerequisites. 60 # Then clear all the keys and call verify_app on the final bundle to 61 # ensure that it is truly standalone. 63 # As an optional parameter (IGNORE_ITEM) a list of file names can be passed, 64 # which are then ignored (e.g. IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe") 68 # COPY_AND_FIXUP_BUNDLE(<src> <dst> <libs> <dirs>) 70 # Makes a copy of the bundle <src> at location <dst> and then fixes up 71 # the new copied bundle in-place at <dst>... 77 # Verifies that an application <app> appears valid based on running 78 # analysis tools on it. Calls "message(FATAL_ERROR" if the application 81 # As an optional parameter (IGNORE_ITEM) a list of file names can be passed, 82 # which are then ignored (e.g. IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe") 86 # GET_BUNDLE_MAIN_EXECUTABLE(<bundle> <result_var>) 88 # The result will be the full path name of the bundle's main executable 89 # file or an "error:" prefixed string if it could not be determined. 93 # GET_DOTAPP_DIR(<exe> <dotapp_dir_var>) 95 # Returns the nearest parent dir whose name ends with ".app" given the 96 # full path to an executable. If there is no such parent dir, then 97 # simply return the dir containing the executable. 99 # The returned directory may or may not exist. 103 # GET_BUNDLE_AND_EXECUTABLE(<app> <bundle_var> <executable_var> <valid_var>) 105 # Takes either a ".app" directory name or the name of an executable 106 # nested inside a ".app" directory and returns the path to the ".app" 107 # directory in <bundle_var> and the path to its main executable in 112 # GET_BUNDLE_ALL_EXECUTABLES(<bundle> <exes_var>) 114 # Scans the given bundle recursively for all executable files and 115 # accumulates them into a variable. 119 # GET_ITEM_KEY(<item> <key_var>) 121 # Given a file (item) name, generate a key that should be unique 122 # considering the set of libraries that need copying or fixing up to 123 # make a bundle standalone. This is essentially the file name including 124 # extension with "." replaced by "_" 126 # This key is used as a prefix for CMake variables so that we can 127 # associate a set of variables with a given item based on its key. 131 # CLEAR_BUNDLE_KEYS(<keys_var>) 133 # Loop over the list of keys, clearing all the variables associated with 134 # each key. After the loop, clear the list of keys itself. 136 # Caller of get_bundle_keys should call clear_bundle_keys when done with 141 # SET_BUNDLE_KEY_VALUES(<keys_var> <context> <item> <exepath> <dirs> 142 # <copyflag> [<rpaths>]) 144 # Add a key to the list (if necessary) for the given item. If added, 145 # also set all the variables associated with that key. 149 # GET_BUNDLE_KEYS(<app> <libs> <dirs> <keys_var>) 151 # Loop over all the executable and library files within the bundle (and 152 # given as extra <libs>) and accumulate a list of keys representing 153 # them. Set values associated with each key such that we can loop over 154 # all of them and copy prerequisite libs into the bundle and then do 155 # appropriate install_name_tool fixups. 157 # As an optional parameter (IGNORE_ITEM) a list of file names can be passed, 158 # which are then ignored (e.g. IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe") 162 # COPY_RESOLVED_ITEM_INTO_BUNDLE(<resolved_item> <resolved_embedded_item>) 164 # Copy a resolved item into the bundle if necessary. Copy is not 165 # necessary if the resolved_item is "the same as" the 166 # resolved_embedded_item. 170 # COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE(<resolved_item> <resolved_embedded_item>) 172 # Copy a resolved framework into the bundle if necessary. Copy is not 173 # necessary if the resolved_item is "the same as" the 174 # resolved_embedded_item. 176 # By default, BU_COPY_FULL_FRAMEWORK_CONTENTS is not set. If you want 177 # full frameworks embedded in your bundles, set 178 # BU_COPY_FULL_FRAMEWORK_CONTENTS to ON before calling fixup_bundle. By 179 # default, COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE copies the framework 180 # dylib itself plus the framework Resources directory. 184 # FIXUP_BUNDLE_ITEM(<resolved_embedded_item> <exepath> <dirs>) 186 # Get the direct/non-system prerequisites of the resolved embedded item. 187 # For each prerequisite, change the way it is referenced to the value of 188 # the _EMBEDDED_ITEM keyed variable for that prerequisite. (Most likely 189 # changing to an "@executable_path" style reference.) 191 # This function requires that the resolved_embedded_item be "inside" the 192 # bundle already. In other words, if you pass plugins to fixup_bundle 193 # as the libs parameter, you should install them or copy them into the 194 # bundle before calling fixup_bundle. The "libs" parameter is a list of 195 # libraries that must be fixed up, but that cannot be determined by 196 # otool output analysis. (i.e., plugins) 198 # Also, change the id of the item being fixed up to its own 199 # _EMBEDDED_ITEM value. 201 # Accumulate changes in a local variable and make *one* call to 202 # install_name_tool at the end of the function with all the changes at 205 # If the BU_CHMOD_BUNDLE_ITEMS variable is set then bundle items will be 206 # marked writable before install_name_tool tries to change them. 210 # VERIFY_BUNDLE_PREREQUISITES(<bundle> <result_var> <info_var>) 212 # Verifies that the sum of all prerequisites of all files inside the 213 # bundle are contained within the bundle or are "system" libraries, 214 # presumed to exist everywhere. 216 # As an optional parameter (IGNORE_ITEM) a list of file names can be passed, 217 # which are then ignored (e.g. IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe") 221 # VERIFY_BUNDLE_SYMLINKS(<bundle> <result_var> <info_var>) 223 # Verifies that any symlinks found in the bundle point to other files 224 # that are already also in the bundle... Anything that points to an 225 # external file causes this function to fail the verification. 227 # The functions defined in this file depend on the get_prerequisites function 228 # (and possibly others) found in: 230 get_filename_component(BundleUtilities_cmake_dir
"${CMAKE_CURRENT_LIST_FILE}" PATH)
231 include(
"${BundleUtilities_cmake_dir}/GetPrerequisites.cmake")
235 set(result "error: '${bundle}/Contents/
Info.plist
' file does not exist") 237 if(EXISTS "${bundle}/Contents/Info.plist") 238 set(result "error: no CFBundleExecutable in '${bundle}/Contents/
Info.plist
' file") 239 set(line_is_main_executable 0) 240 set(bundle_executable "") 242 # Read Info.plist as a list of lines: 245 file(READ "${bundle}/Contents/Info.plist" info_plist) 246 string(REPLACE ";" "\\;" info_plist "${info_plist}") 247 string(REPLACE "\n" "${eol_char};" info_plist "${info_plist}") 248 string(REPLACE "\r" "${eol_char};" info_plist "${info_plist}") 250 # Scan the lines for "<key>CFBundleExecutable</key>" - the line after that 251 # is the name of the main executable. 253 foreach(line ${info_plist}) 254 if(line_is_main_executable) 255 string(REGEX REPLACE "^.*<string>(.*)</string>.*$" "\\1" bundle_executable "${line}") 259 if(line MATCHES "<key>CFBundleExecutable</key>") 260 set(line_is_main_executable 1) 264 if(NOT "${bundle_executable}" STREQUAL "") 265 if(EXISTS "${bundle}/Contents/MacOS/${bundle_executable}") 266 set(result "${bundle}/Contents/MacOS/${bundle_executable}") 270 # If not in "Contents/MacOS" then scan the bundle for matching files. If 271 # there is only one executable file that matches, then use it, otherwise 274 #file(GLOB_RECURSE file_list "${bundle}/${bundle_executable}") 276 # But for now, pragmatically, it's an error. Expect the main executable 277 # for the bundle to be in Contents/MacOS, it's an error if it's not: 279 set(result
"error: '${bundle}/Contents/MacOS/${bundle_executable}' does not exist")
284 # More inclusive technique... (This one would work on Windows and Linux 285 # too, if a developer followed the typical Mac bundle naming convention...) 287 # If there is no Info.plist file, try to find an executable with the same 288 # base name as the .app directory: 292 set(${result_var}
"${result}" PARENT_SCOPE)
299 if(s MATCHES "/.*\\.app/
") 300 # If there is a ".app
" parent directory, 301 # ascend until we hit it: 302 # (typical of a Mac bundle executable) 306 get_filename_component(snamewe "${s}
" NAME_WE) 307 get_filename_component(sname "${s}
" NAME) 308 get_filename_component(sdir "${s}
" PATH) 310 if(sname MATCHES "\\.app$
") 312 set(dotapp_dir "${sdir}/${sname}
") 316 # Otherwise use a directory containing the exe 317 # (typical of a non-bundle executable on Mac, Windows or Linux) 319 is_file_executable("${s}
" is_executable) 321 get_filename_component(sdir "${s}
" PATH) 322 set(dotapp_dir "${sdir}
") 324 set(dotapp_dir "${s}
") 329 set(${dotapp_dir_var} "${dotapp_dir}
" PARENT_SCOPE) 333 function(get_bundle_and_executable app bundle_var executable_var valid_var) 337 # Is it a directory ending in .app? 338 if(IS_DIRECTORY "${app}
") 339 if(app MATCHES "\\.app$
") 340 get_bundle_main_executable("${app}
" executable) 341 if(EXISTS "${app}
" AND EXISTS "${executable}
") 342 set(${bundle_var} "${app}
" PARENT_SCOPE) 343 set(${executable_var} "${executable}
" PARENT_SCOPE) 345 #message("info: handled .app directory
case...
") 347 message("warning: *NOT* handled - .app directory
case...
") 350 message("warning: *NOT* handled - directory but not .app
case...
") 353 # Is it an executable file? 354 is_file_executable("${app}
" is_executable) 356 get_dotapp_dir("${app}
" dotapp_dir) 357 if(EXISTS "${dotapp_dir}
") 358 set(${bundle_var} "${dotapp_dir}
" PARENT_SCOPE) 359 set(${executable_var} "${app}
" PARENT_SCOPE) 361 #message("info: handled executable file
in .app dir
case...
") 363 get_filename_component(app_dir "${app}
" PATH) 364 set(${bundle_var} "${app_dir}
" PARENT_SCOPE) 365 set(${executable_var} "${app}
" PARENT_SCOPE) 367 #message("info: handled executable file
in any dir
case...
") 370 message("warning: *NOT* handled - not .app dir, not executable file...
") 374 message("warning: *NOT* handled - directory/file does not exist...
") 378 set(${bundle_var} "error: not a bundle
" PARENT_SCOPE) 379 set(${executable_var} "error: not a bundle
" PARENT_SCOPE) 382 set(${valid_var} ${valid} PARENT_SCOPE) 386 function(get_bundle_all_executables bundle exes_var) 390 find_program(find_cmd "find
") 391 mark_as_advanced(find_cmd) 394 # find command is much quicker than checking every file one by one on Unix 395 # which can take long time for large bundles, and since anyway we expect 396 # executable to have execute flag set we can narrow the list much quicker. 398 execute_process(COMMAND "${find_cmd}
" "${bundle}
" 399 -type f \( -perm -0100 -o -perm -0010 -o -perm -0001 \) 400 OUTPUT_VARIABLE file_list 401 OUTPUT_STRIP_TRAILING_WHITESPACE 403 string(REPLACE "\n
" ";
" file_list "${file_list}
") 405 file(GLOB_RECURSE file_list "${bundle}
503 ?${item_name}).*$
" "${default_embedded_path}/\\1
" embedded_item "${item}
") 505 # For other items, just use the same name as the original, but in the 508 set(embedded_item "${default_embedded_path}/${item_name}
") 511 # Replace @executable_path and resolve "..
" references: 513 string(REPLACE "@executable_path
" "${exepath}
" resolved_embedded_item "${embedded_item}
") 514 get_filename_component(resolved_embedded_item "${resolved_embedded_item}
" ABSOLUTE) 516 # *But* -- if we are not copying, then force resolved_embedded_item to be 517 # the same as resolved_item. In the case of multiple executables in the 518 # original bundle, using the default_embedded_path results in looking for 519 # the resolved executable next to the main bundle executable. This is here 520 # so that exes in the other sibling directories (like "bin
") get fixed up 524 set(resolved_embedded_item "${resolved_item}
") 527 set(${keys_var} ${${keys_var}} PARENT_SCOPE) 528 set(${key}_ITEM "${item}
" PARENT_SCOPE) 529 set(${key}_RESOLVED_ITEM "${resolved_item}
" PARENT_SCOPE) 530 set(${key}_DEFAULT_EMBEDDED_PATH "${default_embedded_path}
" PARENT_SCOPE) 531 set(${key}_EMBEDDED_ITEM "${embedded_item}
" PARENT_SCOPE) 532 set(${key}_RESOLVED_EMBEDDED_ITEM "${resolved_embedded_item}
" PARENT_SCOPE) 533 set(${key}_COPYFLAG "${copyflag}
" PARENT_SCOPE) 534 set(${key}_RPATHS "${item_rpaths}
" PARENT_SCOPE) 535 set(${key}_RDEP_RPATHS "${rpaths}
" PARENT_SCOPE) 537 #message("warning: item key
'${key}' already
in the list, subsequent references assumed identical to first
") 542 function(get_bundle_keys app libs dirs keys_var) 543 set(${keys_var} PARENT_SCOPE) 547 set(multiValueArgs IGNORE_ITEM) 548 cmake_parse_arguments(CFG "${options}
" "${oneValueArgs}
" "${multiValueArgs}
" ${ARGN} ) 549 get_bundle_and_executable("${app}
" bundle executable valid) 551 # Always use the exepath of the main bundle executable for @executable_path 554 get_filename_component(exepath "${executable}
" PATH) 556 # But do fixups on all executables in the bundle: 558 get_bundle_all_executables("${bundle}
" exes) 560 # Set keys for main executable first: 562 set_bundle_key_values(${keys_var} "${executable}
" "${executable}
" "${exepath}
" "${dirs}
" 0) 564 # Get rpaths specified by main executable: 566 get_item_key("${executable}
" executable_key) 567 set(main_rpaths "${${executable_key}_RPATHS}
") 569 # For each extra lib, accumulate a key as well and then also accumulate 570 # any of its prerequisites. (Extra libs are typically dynamically loaded 571 # plugins: libraries that are prerequisites for full runtime functionality 572 # but that do not show up in otool -L output...) 575 set_bundle_key_values(${keys_var} "${lib}
" "${lib}
" "${exepath}
" "${dirs}
" 0 "${main_rpaths}
") 578 set(ignoreFile FALSE) 579 get_filename_component(prereq_filename ${lib} NAME) 580 if(NOT "${CFG_IGNORE_ITEM}
" STREQUAL "" ) 581 foreach(item ${CFG_IGNORE_ITEM}) 582 if("${item}
" STREQUAL "${prereq_filename}
") 589 get_prerequisites("${lib}
" prereqs 1 1 "${exepath}
" "${dirs}
" "${main_rpaths}
") 590 foreach(pr ${prereqs}) 591 set_bundle_key_values(${keys_var} "${lib}
" "${pr}
" "${exepath}
" "${dirs}
" 1 "${main_rpaths}
") 594 message("Ignoring file: ${prereq_filename}
") 598 # For each executable found in the bundle, accumulate keys as we go. 599 # The list of keys should be complete when all prerequisites of all 600 # binaries in the bundle have been analyzed. 603 # Main executable is scanned first above: 605 if(NOT "${exe}
" STREQUAL "${executable}
") 606 # Add the exe itself to the keys: 608 set_bundle_key_values(${keys_var} "${exe}
" "${exe}
" "${exepath}
" "${dirs}
" 0 "${main_rpaths}
") 610 # Get rpaths specified by executable: 612 get_item_key("${exe}
" exe_key) 613 set(exe_rpaths "${main_rpaths}
" "${${exe_key}_RPATHS}
") 615 set(exe_rpaths "${main_rpaths}
") 618 # Add each prerequisite to the keys: 621 set(ignoreFile FALSE) 622 get_filename_component(prereq_filename ${exe} NAME) 623 if(NOT "${CFG_IGNORE_ITEM}
" STREQUAL "" ) 624 foreach(item ${CFG_IGNORE_ITEM}) 625 if("${item}
" STREQUAL "${prereq_filename}
") 632 get_prerequisites("${exe}
" prereqs 1 1 "${exepath}
" "${dirs}
" "${exe_rpaths}
") 633 foreach(pr ${prereqs}) 634 set_bundle_key_values(${keys_var} "${exe}
" "${pr}
" "${exepath}
" "${dirs}
" 1 "${exe_rpaths}
") 637 message("Ignoring file: ${prereq_filename}
") 641 # preserve library symlink structure 642 foreach(key ${${keys_var}}) 643 if("${${key}_COPYFLAG}
" STREQUAL 1) 644 if(IS_SYMLINK "${${key}_RESOLVED_ITEM}
") 645 get_filename_component(target "${${key}_RESOLVED_ITEM}
" REALPATH) 646 set_bundle_key_values(${keys_var} "${exe}
" "${target}
" "${exepath}
" "${dirs}
" 1 "${exe_rpaths}
") 647 get_item_key("${target}
" targetkey) 650 # ignore case on Windows 651 string(TOLOWER "${${key}_RESOLVED_ITEM}
" resolved_item_compare) 652 string(TOLOWER "${${targetkey}_RESOLVED_EMBEDDED_ITEM}
" resolved_embedded_item_compare) 654 set(resolved_item_compare "${${key}_RESOLVED_ITEM}
") 655 set(resolved_embedded_item_compare "${${targetkey}_RESOLVED_EMBEDDED_ITEM}
") 657 get_filename_component(resolved_item_compare "${resolved_item_compare}
" NAME) 658 get_filename_component(resolved_embedded_item_compare "${resolved_embedded_item_compare}
" NAME) 660 if(NOT "${resolved_item_compare}
" STREQUAL "${resolved_embedded_item_compare}
") 661 set(${key}_COPYFLAG "2
") 662 set(${key}_RESOLVED_ITEM "${${targetkey}_RESOLVED_EMBEDDED_ITEM}
") 668 # Propagate values to caller's scope: 670 set(${keys_var} ${${keys_var}} PARENT_SCOPE) 671 foreach(key ${${keys_var}}) 672 set(${key}_ITEM "${${key}_ITEM}
" PARENT_SCOPE) 673 set(${key}_RESOLVED_ITEM "${${key}_RESOLVED_ITEM}
" PARENT_SCOPE) 674 set(${key}_DEFAULT_EMBEDDED_PATH "${${key}_DEFAULT_EMBEDDED_PATH}
" PARENT_SCOPE) 675 set(${key}_EMBEDDED_ITEM "${${key}_EMBEDDED_ITEM}
" PARENT_SCOPE) 676 set(${key}_RESOLVED_EMBEDDED_ITEM "${${key}_RESOLVED_EMBEDDED_ITEM}
" PARENT_SCOPE) 677 set(${key}_COPYFLAG "${${key}_COPYFLAG}
" PARENT_SCOPE) 678 set(${key}_RPATHS "${${key}_RPATHS}
" PARENT_SCOPE) 679 set(${key}_RDEP_RPATHS "${${key}_RDEP_RPATHS}
" PARENT_SCOPE) 684 function(link_resolved_item_into_bundle resolved_item resolved_embedded_item) 686 # ignore case on Windows 687 string(TOLOWER "${resolved_item}
" resolved_item_compare) 688 string(TOLOWER "${resolved_embedded_item}
" resolved_embedded_item_compare) 690 set(resolved_item_compare "${resolved_item}
") 691 set(resolved_embedded_item_compare "${resolved_embedded_item}
") 694 if("${resolved_item_compare}
" STREQUAL "${resolved_embedded_item_compare}
") 695 message("warning: resolved_item == resolved_embedded_item - not linking...
") 697 get_filename_component(target_dir "${resolved_embedded_item}
" DIRECTORY) 698 file(RELATIVE_PATH symlink_target "${target_dir}
" "${resolved_item}
") 699 execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "${symlink_target}
" "${resolved_embedded_item}
") 703 function(copy_resolved_item_into_bundle resolved_item resolved_embedded_item) 705 # ignore case on Windows 706 string(TOLOWER "${resolved_item}
" resolved_item_compare) 707 string(TOLOWER "${resolved_embedded_item}
" resolved_embedded_item_compare) 709 set(resolved_item_compare "${resolved_item}
") 710 set(resolved_embedded_item_compare "${resolved_embedded_item}
") 713 if("${resolved_item_compare}
" STREQUAL "${resolved_embedded_item_compare}
") 714 message("warning: resolved_item == resolved_embedded_item - not copying...
") 716 #message("copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}
") 717 execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}
" "${resolved_embedded_item}
") 718 if(UNIX AND NOT APPLE) 719 file(RPATH_REMOVE FILE "${resolved_embedded_item}
") 726 function(copy_resolved_framework_into_bundle resolved_item resolved_embedded_item) 728 # ignore case on Windows 729 string(TOLOWER "${resolved_item}
" resolved_item_compare) 730 string(TOLOWER "${resolved_embedded_item}
" resolved_embedded_item_compare) 732 set(resolved_item_compare "${resolved_item}
") 733 set(resolved_embedded_item_compare "${resolved_embedded_item}
") 736 if("${resolved_item_compare}
" STREQUAL "${resolved_embedded_item_compare}
") 737 message("warning: resolved_item == resolved_embedded_item - not copying...
") 739 if(BU_COPY_FULL_FRAMEWORK_CONTENTS) 740 # Full Framework (everything): 741 get_filename_component(resolved_dir "${resolved_item}
" PATH) 742 get_filename_component(resolved_dir "${resolved_dir}/../..
" ABSOLUTE) 743 get_filename_component(resolved_embedded_dir "${resolved_embedded_item}
" PATH) 744 get_filename_component(resolved_embedded_dir "${resolved_embedded_dir}/../..
" ABSOLUTE) 745 #message("copying COMMAND ${CMAKE_COMMAND} -E copy_directory
'${resolved_dir}' '${resolved_embedded_dir}'") 746 execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${resolved_dir}
" "${resolved_embedded_dir}
") 748 # Framework lib itself: 749 #message("copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}
") 750 execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}
" "${resolved_embedded_item}
") 752 # Plus Resources, if they exist: 753 string(REGEX REPLACE "^(.*)/[^/]+$
" "\\1/Resources
" resolved_resources "${resolved_item}
") 754 string(REGEX REPLACE "^(.*)/[^/]+$
" "\\1/Resources
" resolved_embedded_resources "${resolved_embedded_item}
") 755 if(EXISTS "${resolved_resources}
") 756 #message("copying COMMAND ${CMAKE_COMMAND} -E copy_directory
'${resolved_resources}' '${resolved_embedded_resources}'") 757 execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${resolved_resources}
" "${resolved_embedded_resources}
") 760 # Some frameworks e.g. Qt put Info.plist in wrong place, so when it is 761 # missing in resources, copy it from other well known incorrect locations: 762 if(NOT EXISTS "${resolved_resources}/
Info.plist
") 763 # Check for Contents/Info.plist in framework root (older Qt SDK): 764 string(REGEX REPLACE "^(.*)/[^/]+/[^/]+/[^/]+$
" "\\1/Contents/
Info.plist
" resolved_info_plist "${resolved_item}
") 765 string(REGEX REPLACE "^(.*)/[^/]+$
" "\\1/Resources/
Info.plist
" resolved_embedded_info_plist "${resolved_embedded_item}
") 766 if(EXISTS "${resolved_info_plist}
") 767 #message("copying COMMAND ${CMAKE_COMMAND} -E copy_directory
'${resolved_info_plist}' '${resolved_embedded_info_plist}'") 768 execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_info_plist}
" "${resolved_embedded_info_plist}
") 772 # Check if framework is versioned and fix it layout 773 string(REGEX REPLACE "^.*/([^/]+)/[^/]+$
" "\\1
" resolved_embedded_version "${resolved_embedded_item}
") 774 string(REGEX REPLACE "^(.*)/[^/]+/[^/]+$
" "\\1
" resolved_embedded_versions "${resolved_embedded_item}
") 775 string(REGEX REPLACE "^.*/([^/]+)/[^/]+/[^/]+$
" "\\1
" resolved_embedded_versions_basename "${resolved_embedded_item}
") 776 if(resolved_embedded_versions_basename STREQUAL "Versions
") 777 # Ensure Current symlink points to the framework version 778 if(NOT EXISTS "${resolved_embedded_versions}/Current
") 779 execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "${resolved_embedded_version}
" "${resolved_embedded_versions}/Current
") 781 # Restore symlinks in framework root pointing to current framework 782 # binary and resources: 783 string(REGEX REPLACE "^(.*)/[^/]+/[^/]+/[^/]+$
" "\\1
" resolved_embedded_root "${resolved_embedded_item}
") 784 string(REGEX REPLACE "^.*/([^/]+)$
" "\\1
" resolved_embedded_item_basename "${resolved_embedded_item}
") 785 if(NOT EXISTS "${resolved_embedded_root}/${resolved_embedded_item_basename}
") 786 execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "Versions/Current/${resolved_embedded_item_basename}
" "${resolved_embedded_root}/${resolved_embedded_item_basename}
") 788 if(NOT EXISTS "${resolved_embedded_root}/Resources
") 789 execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "Versions/Current/Resources
" "${resolved_embedded_root}/Resources
") 793 if(UNIX AND NOT APPLE) 794 file(RPATH_REMOVE FILE "${resolved_embedded_item}
") 801 function(fixup_bundle_item resolved_embedded_item exepath dirs) 802 # This item's key is "ikey
": 804 get_item_key("${resolved_embedded_item}
" ikey) 806 # Ensure the item is "inside the .app bundle
" -- it should not be fixed up if 807 # it is not in the .app bundle... Otherwise, we'll modify files in the build 808 # tree, or in other varied locations around the file system, with our call to 809 # install_name_tool. Make sure that doesn't happen here: 811 get_dotapp_dir("${exepath}
" exe_dotapp_dir) 812 string(LENGTH "${exe_dotapp_dir}/
" exe_dotapp_dir_length) 813 string(LENGTH "${resolved_embedded_item}
" resolved_embedded_item_length) 814 set(path_too_short 0) 816 if(${resolved_embedded_item_length} LESS ${exe_dotapp_dir_length}) 817 set(path_too_short 1) 819 if(NOT path_too_short) 820 string(SUBSTRING "${resolved_embedded_item}
" 0 ${exe_dotapp_dir_length} item_substring) 821 if("${exe_dotapp_dir}/
" STREQUAL "${item_substring}
") 826 message(" exe_dotapp_dir/=
'${exe_dotapp_dir}/'") 827 message(" item_substring=
'${item_substring}'") 828 message(" resolved_embedded_item=
'${resolved_embedded_item}'") 830 message("Install or copy the item into the bundle before calling
fixup_bundle.
") 831 message("Or maybe there
's a typo or incorrect path in one of the args to fixup_bundle?") 833 message(FATAL_ERROR "cannot fixup an item that is not in the bundle...") 836 set(rpaths "${${ikey}_RPATHS}" "${${ikey}_RDEP_RPATHS}") 839 get_prerequisites("${resolved_embedded_item}" prereqs 1 0 "${exepath}" "${dirs}" "${rpaths}") 843 foreach(pr ${prereqs}) 844 # Each referenced item's key is
"rkey" in the loop:
848 if(NOT
"${${rkey}_EMBEDDED_ITEM}" STREQUAL
"")
849 set(changes ${changes}
"-change" "${pr}" "${${rkey}_EMBEDDED_ITEM}")
851 message(
"warning: unexpected reference to '${pr}'")
855 if(BU_CHMOD_BUNDLE_ITEMS)
856 execute_process(COMMAND chmod u+w "${resolved_embedded_item}
") 859 # Only if install_name_tool supports -delete_rpath: 861 execute_process(COMMAND install_name_tool 862 OUTPUT_VARIABLE install_name_tool_usage 863 ERROR_VARIABLE install_name_tool_usage 865 if(install_name_tool_usage MATCHES ".*-delete_rpath.*
") 866 foreach(rpath ${${ikey}_RPATHS}) 867 set(changes ${changes} -delete_rpath "${rpath}
") 871 if(${ikey}_EMBEDDED_ITEM) 872 set(changes ${changes} -id "${${ikey}_EMBEDDED_ITEM}
") 875 # Change this item's id and all of its references in one call 876 # to install_name_tool: 879 set(cmd install_name_tool ${changes} "${resolved_embedded_item}
") 880 execute_process(COMMAND ${cmd} RESULT_VARIABLE install_name_tool_result) 881 if(NOT install_name_tool_result EQUAL 0) 882 string(REPLACE ";
" "' '" msg "'${cmd}'") 883 message(FATAL_ERROR "Command failed:\n ${msg}
") 890 function(fixup_bundle app libs dirs) 891 #get_prerequisites_clear_cache() 894 message(" app=
'${app}'") 895 message(" libs=
'${libs}'") 896 message(" dirs=
'${dirs}'") 897 #get_property(current_cache GLOBAL PROPERTY prerequisites_cachevariables) 898 #message(" current cache=
'${current_cache}'") 902 set(multiValueArgs IGNORE_ITEM) 903 cmake_parse_arguments(CFG "${options}
" "${oneValueArgs}
" "${multiValueArgs}
" ${ARGN} ) 905 message(" ignoreItems=
'${CFG_IGNORE_ITEM}'") 907 get_bundle_and_executable("${app}
" bundle executable valid) 909 get_filename_component(exepath "${executable}
" PATH) 912 get_bundle_keys("${app}
" "${libs}
" "${dirs}
" keys IGNORE_ITEM "${CFG_IGNORE_ITEM}
") 921 if("${${key}_COPYFLAG}
" STREQUAL "2
") 922 message("${i}/${n}: linking
'${${key}_RESOLVED_ITEM}' ->
'${${key}_RESOLVED_EMBEDDED_ITEM}'") 923 elseif(${${key}_COPYFLAG}) 924 message("${i}/${n}: copying
'${${key}_RESOLVED_ITEM}'") 926 message("${i}/${n}: *NOT* copying
'${${key}_RESOLVED_ITEM}'") 931 message("key=
'${key}'") 932 message("item=
'${${key}_ITEM}'") 933 message("resolved_item=
'${${key}_RESOLVED_ITEM}'") 934 message("default_embedded_path=
'${${key}_DEFAULT_EMBEDDED_PATH}'") 935 message("embedded_item=
'${${key}_EMBEDDED_ITEM}'") 936 message("resolved_embedded_item=
'${${key}_RESOLVED_EMBEDDED_ITEM}'") 937 message("copyflag=
'${${key}_COPYFLAG}'") 941 if("${${key}_COPYFLAG}
" STREQUAL "2
") 942 link_resolved_item_into_bundle("${${key}_RESOLVED_ITEM}
" 943 "${${key}_RESOLVED_EMBEDDED_ITEM}
") 944 elseif(${${key}_COPYFLAG}) 945 set(item "${${key}_ITEM}
") 946 if(item MATCHES "[^/]+\\.framework/
") 947 copy_resolved_framework_into_bundle("${${key}_RESOLVED_ITEM}
" 948 "${${key}_RESOLVED_EMBEDDED_ITEM}
") 950 copy_resolved_item_into_bundle("${${key}_RESOLVED_ITEM}
" 951 "${${key}_RESOLVED_EMBEDDED_ITEM}
") 960 message("${i}/${n}: fixing up
'${${key}_RESOLVED_EMBEDDED_ITEM}'") 961 if(NOT "${${key}_COPYFLAG}
" STREQUAL "2
") 962 fixup_bundle_item("${${key}_RESOLVED_EMBEDDED_ITEM}
" "${exepath}
" "${dirs}
") 965 message("${i}/${n}: fix-up not required on
this platform
'${${key}_RESOLVED_EMBEDDED_ITEM}'") 970 clear_bundle_keys(keys) 972 message("fixup_bundle: verifying...
") 973 verify_app("${app}
" IGNORE_ITEM "${CFG_IGNORE_ITEM}
") 975 message(SEND_ERROR "error:
fixup_bundle: not a valid bundle
") 982 function(copy_and_fixup_bundle src dst libs dirs) 983 execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${src}
" "${dst}
") 984 fixup_bundle("${dst}
" "${libs}
" "${dirs}
") 988 function(verify_bundle_prerequisites bundle result_var info_var) 995 set(multiValueArgs IGNORE_ITEM) 996 cmake_parse_arguments(CFG "${options}
" "${oneValueArgs}
" "${multiValueArgs}
" ${ARGN} ) 998 get_bundle_main_executable("${bundle}
" main_bundle_exe) 1000 get_bundle_all_executables("${bundle}
" file_list) 1001 foreach(f ${file_list}) 1002 get_filename_component(exepath "${f}
" PATH) 1003 math(EXPR count "${count} + 1
") 1005 message("executable file ${count}: ${f}
") 1008 set(ignoreFile FALSE) 1009 get_filename_component(prereq_filename ${f} NAME) 1011 if(NOT "${CFG_IGNORE_ITEM}
" STREQUAL "" ) 1012 foreach(item ${CFG_IGNORE_ITEM}) 1013 if("${item}
" STREQUAL "${prereq_filename}
") 1014 set(ignoreFile TRUE) 1020 get_item_rpaths(${f} _main_exe_rpaths) 1021 get_prerequisites("${f}
" prereqs 1 1 "${exepath}
" "${_main_exe_rpaths}
") 1024 # "embedded
" and "system
" prerequisites are fine... anything else means 1025 # the bundle's prerequisites are not verified (i.e., the bundle is not 1026 # really "standalone
") 1028 # On Windows (and others? Linux/Unix/...?) 1029 # "local
" and "system
" prereqs are fine... 1032 set(external_prereqs "") 1034 foreach(p ${prereqs}) 1036 gp_file_type("${f}
" "${p}
" p_type) 1039 if(NOT "${p_type}
" STREQUAL "embedded
" AND NOT "${p_type}
" STREQUAL "system
") 1040 set(external_prereqs ${external_prereqs} "${p}
") 1043 if(NOT "${p_type}
" STREQUAL "local
" AND NOT "${p_type}
" STREQUAL "system
") 1044 set(external_prereqs ${external_prereqs} "${p}
") 1049 if(external_prereqs) 1050 # Found non-system/somehow-unacceptable prerequisites: 1052 set(info ${info} "external prerequisites found:\nf=
'${f}'\nexternal_prereqs=
'${external_prereqs}'\n
") 1055 message("Ignoring file: ${prereq_filename}
") 1060 set(info "Verified ${count} executable files
in '${bundle}'") 1063 set(${result_var} "${result}
" PARENT_SCOPE) 1064 set(${info_var} "${
info}
" PARENT_SCOPE) 1068 function(verify_bundle_symlinks bundle result_var info_var) 1073 # TODO: implement this function for real... 1074 # Right now, it is just a stub that verifies unconditionally... 1076 set(${result_var} "${result}
" PARENT_SCOPE) 1077 set(${info_var} "${
info}
" PARENT_SCOPE) 1081 function(verify_app app) 1087 set(multiValueArgs IGNORE_ITEM) 1088 cmake_parse_arguments(CFG "${options}
" "${oneValueArgs}
" "${multiValueArgs}
" ${ARGN} ) 1090 get_bundle_and_executable("${app}
" bundle executable valid) 1092 message("===========================================================================
") 1093 message("Analyzing app=
'${app}'") 1094 message("bundle=
'${bundle}'") 1095 message("executable=
'${executable}'") 1096 message("valid=
'${valid}'") 1098 # Verify that the bundle does not have any "external
" prerequisites: 1100 verify_bundle_prerequisites("${bundle}
" verified info IGNORE_ITEM "${CFG_IGNORE_ITEM}
") 1101 message("verified=
'${verified}'") 1102 message("info=
'${info}'") 1106 # Verify that the bundle does not have any symlinks to external files: 1108 verify_bundle_symlinks("${bundle}
" verified info) 1109 message("verified=
'${verified}'") 1110 message("info=
'${info}'") 1115 message(FATAL_ERROR "error:
verify_app failed
") get_bundle_main_executable(bundle, result_var)
fixup_bundle(app, libs, dirs)
get_dotapp_dir(exe, dotapp_dir_var)
static void info(const char *fmt,...)
static bool in(Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4)
get_item_key(item, key_var)