# # Copyright (c) Contributors to the Open 3D Engine Project. # For complete copyright and license terms please see the LICENSE at the root of this distribution. # # SPDX-License-Identifier: Apache-2.0 OR MIT # # function(gp_resolve_item_override context item exepath dirs resolved_item_var resolved_var) # Qt frameworks could resolve the binary to eg qt/lib/QtCore.framework/Headers/QtCore instead of qt/lib/QtCore.framework/Versions/5/QtCore # This is because GetPrerequisites.cmake gp_resolve_item function searches for the first file that matches the "frameworks name" if(${${resolved_var}} AND ${item} MATCHES "/(Qt[^\\.]+\\.framework)/(.*)") set(qt_framework ${CMAKE_MATCH_1}) set(qt_framework_subpath ${CMAKE_MATCH_2}) string(REGEX REPLACE "(.*)/(Qt[^\\.]+\\.framework)/(.*)" "\\1/\\2/${qt_framework_subpath}" new_resolved_item "${${resolved_item_var}}") set(${resolved_item_var} ${new_resolved_item} PARENT_SCOPE) endif() endfunction() include(BundleUtilities) cmake_policy(SET CMP0012 NEW) # new policy for the if that evaluates a boolean out of the LY_BUILD_FIXUP_BUNDLE expansion cmake_policy(SET CMP0009 NEW) # do not traverse symlinks on GLOB_RECURSE set(anything_new FALSE) set(plugin_libs) set(plugin_dirs) set(depends_on_python FALSE) find_program(LY_INSTALL_NAME_TOOL install_name_tool) if (NOT LY_INSTALL_NAME_TOOL) message(FATAL_ERROR "Unable to locate 'install_name_tool'") endif() function(ly_copy source_file target_directory) cmake_path(GET source_file FILENAME target_filename) # If target_directory is a bundle if("${target_directory}" MATCHES "\\.app/Contents/MacOS") set(target_is_bundle TRUE) if("${source_file}" MATCHES "\\.[Ff]ramework[^\\.]") if(NOT @LY_BUILD_FIXUP_BUNDLE@) return() endif() # fixup origin to copy the whole Framework folder and change destination to Contents/Frameworks string(REGEX REPLACE "(.*\\.[Ff]ramework).*" "\\1" source_file "${source_file}") get_filename_component(source_file_folder "${source_file}" DIRECTORY) # Python.framework produces a bug in BundleUtilities so it needs manual handling # https://gitlab.kitware.com/cmake/cmake/-/issues/20165 if("${source_file}" MATCHES "Python.framework") # fixup the destination so it ends up in Contents/Frameworks string(REGEX REPLACE "(.*\\.app/Contents)/MacOS" "\\1/Frameworks" target_directory "${target_directory}") set(local_plugin_dirs ${plugin_dirs}) list(APPEND local_plugin_dirs "${target_directory}/Python.framework") set(target_filename Python.framework) set(plugin_dirs ${local_plugin_dirs} PARENT_SCOPE) set(depends_on_python TRUE PARENT_SCOPE) else() set(local_plugin_dirs ${plugin_dirs}) list(APPEND local_plugin_dirs "${source_file_folder}") set(plugin_dirs ${local_plugin_dirs} PARENT_SCOPE) return() endif() elseif("${source_file}" MATCHES "qt/plugins") if(NOT @LY_BUILD_FIXUP_BUNDLE@) return() endif() # fixup the destination so it ends up in Contents/PlugIns string(REGEX REPLACE "(.*\\.app/Contents)/MacOS" "\\1/PlugIns" target_directory "${target_directory}") set(local_plugin_dirs ${plugin_dirs}) list(APPEND local_plugin_dirs "${target_directory}") set(plugin_dirs ${local_plugin_dirs} PARENT_SCOPE) set(local_plugin_libs ${plugin_libs}) list(APPEND local_plugin_libs "${target_directory}/${target_filename}") set(plugin_libs ${local_plugin_libs} PARENT_SCOPE) elseif("${source_file}" MATCHES "qt/translations") return() # skip, is this used? elseif("${source_file}" MATCHES ".dylib") set(local_plugin_dirs ${plugin_dirs}) list(APPEND local_plugin_dirs "${target_directory}") set(plugin_dirs ${local_plugin_dirs} PARENT_SCOPE) endif() else() # target is not a bundle set(target_is_bundle FALSE) if("${source_file}" MATCHES "\\.[Ff]ramework[^\\.]") # fixup origin to copy the whole Framework folder string(REGEX REPLACE "(.*\\.[Ff]ramework).*" "\\1" source_file "${source_file}") get_filename_component(target_filename "${source_file}" NAME) if("${source_file}" MATCHES "Python.framework") set(depends_on_python TRUE PARENT_SCOPE) endif() endif() endif() cmake_path(APPEND target_file "${target_directory}" "${target_filename}") cmake_path(COMPARE "${source_file}" EQUAL "${target_file}" same_location) if(NOT ${same_location}) if(NOT EXISTS "${target_directory}") file(MAKE_DIRECTORY "${target_directory}") endif() set(is_framework FALSE) if("${source_file}" MATCHES "\\.[Ff]ramework") set(is_framework TRUE) endif() if(NOT is_framework) # if it is a bundle, there is no contention about the files in the destination, each bundle target will copy everything # we dont want these files to invalidate the bundle and cause a new signature file(LOCK "${target_file}.lock" GUARD FUNCTION TIMEOUT 300) file(SIZE "${source_file}" source_file_size) if(EXISTS "${target_file}") file(SIZE "${target_file}" target_file_size) else() set(target_file_size 0) endif() else() set(source_file_size 0) set(target_file_size 0) endif() if((NOT source_file_size EQUAL target_file_size) OR "${source_file}" IS_NEWER_THAN "${target_file}") message(STATUS "Copying \"${source_file}\" to \"${target_directory}\"...") file(MAKE_DIRECTORY "${target_directory}") file(COPY "${source_file}" DESTINATION "${target_directory}" FILE_PERMISSIONS @LY_COPY_PERMISSIONS@ FOLLOW_SYMLINK_CHAIN) file(TOUCH_NOCREATE "${target_file}") set(anything_new TRUE PARENT_SCOPE) endif() endif() endfunction() @LY_COPY_COMMANDS@ if(NOT @LY_BUILD_FIXUP_BUNDLE@) return() endif() if(@target_file_dir@ MATCHES ".app/Contents/MacOS") string(REGEX REPLACE "(.*\\.app)/Contents/MacOS.*" "\\1" bundle_path "@target_file_dir@") set(fixup_timestamp_file "${bundle_path}.fixup.stamp") if(NOT anything_new) if(NOT EXISTS "${fixup_timestamp_file}" OR "${bundle_path}" IS_NEWER_THAN "${fixup_timestamp_file}") set(anything_new TRUE) endif() endif() if(anything_new) unset(fixup_bundle_ignore) # LYN-4505: Patch dxc, is configured in the wrong folder in 3p if(EXISTS ${bundle_path}/Contents/MacOS/Builders/DirectXShaderCompiler/bin/dxc-3.7) list(APPEND fixup_bundle_ignore dxc-3.7) endif() # LYN-4502: Patch python bundle, it contains some windows executables, some files that fixup_bundle doesnt like and has # other issues that produce signature problems if(depends_on_python) message(STATUS "Fixing ${bundle_path}/Contents/Frameworks/Python.framework...") list(APPEND fixup_bundle_ignore Python python3.7m python3.7) file(REMOVE_RECURSE "${bundle_path}/Contents/Frameworks/Python.framework/Versions/Current" "${bundle_path}/Contents/Frameworks/Python.framework/Versions/3.7/Headers" "${bundle_path}/Contents/Frameworks/Python.framework/Versions/3.7/lib/Python" "${bundle_path}/Contents/Frameworks/Python.framework/Versions/3.7/lib/python3.7/test" "${bundle_path}/Contents/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/scipy/io/tests" "${bundle_path}/Contents/Frameworks/Python.framework/Python" "${bundle_path}/Contents/Frameworks/Python.framework/Resources" "${bundle_path}/Contents/Frameworks/Python.framework/Headers" ) file(GLOB_RECURSE exe_file_list "${bundle_path}/Contents/Frameworks/Python.framework/**/*.exe") if(exe_file_list) file(REMOVE_RECURSE ${exe_file_list}) endif() execute_process(COMMAND "${CMAKE_COMMAND}" -E create_symlink include/python3.7m Headers WORKING_DIRECTORY "${bundle_path}/Contents/Frameworks/Python.framework/Versions/3.7" ) execute_process(COMMAND "${CMAKE_COMMAND}" -E create_symlink 3.7 Current WORKING_DIRECTORY "${bundle_path}/Contents/Frameworks/Python.framework/Versions/" ) execute_process(COMMAND "${CMAKE_COMMAND}" -E create_symlink Versions/Current/Python Python WORKING_DIRECTORY "${bundle_path}/Contents/Frameworks/Python.framework" ) execute_process(COMMAND "${CMAKE_COMMAND}" -E create_symlink Versions/Current/Headers Headers WORKING_DIRECTORY "${bundle_path}/Contents/Frameworks/Python.framework" ) execute_process(COMMAND "${CMAKE_COMMAND}" -E create_symlink Versions/Current/Resources Resources WORKING_DIRECTORY "${bundle_path}/Contents/Frameworks/Python.framework" ) file(CHMOD "${bundle_path}/Contents/Frameworks/Python.framework/Versions/Current/Python" PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_WRITE GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) endif() list(REMOVE_DUPLICATES plugin_libs) list(REMOVE_DUPLICATES plugin_dirs) fixup_bundle("${bundle_path}" "${plugin_libs}" "${plugin_dirs}" IGNORE_ITEM ${fixup_bundle_ignore}) file(TOUCH "${bundle_path}") file(TOUCH "${fixup_timestamp_file}") # fixup bundle ends up removing the rpath of dxc (despite we exclude it) if(EXISTS "${bundle_path}/Contents/MacOS/Builders/DirectXShaderCompiler/bin/dxc-3.7") execute_process(COMMAND "${LY_INSTALL_NAME_TOOL}" -add_rpath @executable_path/../lib ${bundle_path}/Contents/MacOS/Builders/DirectXShaderCompiler/bin/dxc-3.7) endif() # misplaced .DS_Store files can cause signing to fail # Interrupted signatures can leave cstemp files behind that fail next signature file(GLOB_RECURSE remove_file_list "${bundle_path}/**/.DS_Store" "${bundle_path/}**/*.cstemp" ) if(remove_file_list) file(REMOVE_RECURSE "${remove_file_list}") endif() endif() else() # Non-bundle case if(depends_on_python) # RPATH fix python execute_process(COMMAND "${LY_INSTALL_NAME_TOOL}" -change @rpath/Python @rpath/Python.framework/Versions/Current/Python "@target_file@") endif() endif()