From 8fbdcd54aa4102d65d3da7e09ae512b24a237d5b Mon Sep 17 00:00:00 2001 From: Mary Date: Tue, 29 Dec 2020 01:58:58 +0100 Subject: [PATCH] Make macOS bundle works! TODO: codesign --- CMakeLists.txt | 30 +++++++++------- cmake/modules/PostprocessBundle.cmake | 50 +++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 12 deletions(-) create mode 100644 cmake/modules/PostprocessBundle.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 298c0a910..b68479dbc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,9 +2,8 @@ cmake_minimum_required(VERSION 3.16) project(imhex VERSION 1.5.0) -if (APPLE) - option (CREATE_BUNDLE "Create a bundle on macOS" OFF) -endif() +set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules") + set(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL) set(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC) @@ -87,7 +86,6 @@ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DRELEASE -DIMHEX_VERSIO set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG -DIMHEX_VERSION=\"\\\"${PROJECT_VERSION}-Debug\"\\\"") set(install_dest RUNTIME) -set(destination_info "${CMAKE_INSTALL_BINDIR}") if (WIN32) set(application_type WIN32) @@ -104,16 +102,12 @@ elseif (APPLE) set(MACOSX_BUNDLE_LONG_VERSION_STRING ${CPACK_PACKAGE_VERSION}) set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}") set(MACOSX_BUNDLE_COPYRIGHT "Copyright © 2020 WerWolv. All rights reserved." ) - set(destination_info ".") set(install_dest BUNDLE) if ("${CMAKE_GENERATOR}" STREQUAL "Xcode") - set ( bundle_path "${destination_info}/${CMAKE_BUILD_TYPE}/imhex.app" ) + set ( bundle_path "${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/imhex.app" ) else () - set ( bundle_path "${destination_info}/imhex.app" ) + set ( bundle_path "${CMAKE_BINARY_DIR}/imhex.app" ) endif() - - # FIXME: Remove this once we move/integrate the plugins directory. - install(DIRECTORY DESTINATION "${bundle_path}/Contents/MacOS/plugins") endif() endif() @@ -155,7 +149,7 @@ add_executable(imhex ${application_type} set_target_properties(imhex PROPERTIES CXX_VISIBILITY_PRESET hidden) -target_link_directories(imhex PRIVATE ${CRYPTO_LIBRARY_DIRS} ${CAPSTONE_LIBRARY_DIRS} ${MAGIC_LIBRARY_DIRS}) +target_link_directories(imhex PRIVATE ${CRYPTO_LIBRARY_DIRS} ${CAPSTONE_LIBRARY_DIRS} ${MAGIC_LIBRARY_DIRS} ${GETTEXT_LIBRARY_DIRS}) if (WIN32) target_link_libraries(imhex libgcc.a libstdc++.a libmagic.a libgnurx.a libtre.a libintl.a libiconv.a shlwapi.lib libcrypto.a libwinpthread.a libcapstone.a LLVMDemangle imgui libimhex ${Python_LIBRARIES} nlohmann_json::nlohmann_json dl) @@ -163,4 +157,16 @@ elseif (UNIX) target_link_libraries(imhex magic crypto ${CMAKE_DL_LIBS} capstone LLVMDemangle imgui libimhex ${Python_LIBRARIES} nlohmann_json::nlohmann_json dl) endif() -install(TARGETS imhex ${install_dest} DESTINATION "${destination_info}") \ No newline at end of file +if (CREATE_BUNDLE) + # Update library references to make the bundle portable + include(PostprocessBundle) + postprocess_bundle(imhex) + + # Fix rpath + add_custom_command(TARGET imhex POST_BUILD COMMAND ${CMAKE_INSTALL_NAME_TOOL} -add_rpath "@executable_path/../Frameworks/" $) + + # FIXME: Remove this once we move/integrate the plugins directory. + add_custom_target(build-time-make-directory ALL COMMAND ${CMAKE_COMMAND} -E make_directory "${bundle_path}/Contents/MacOS/plugins") +else() + install(TARGETS imhex RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) +endif() diff --git a/cmake/modules/PostprocessBundle.cmake b/cmake/modules/PostprocessBundle.cmake new file mode 100644 index 000000000..1d79d1cb3 --- /dev/null +++ b/cmake/modules/PostprocessBundle.cmake @@ -0,0 +1,50 @@ +# Adapted from the Dolphin project: https://dolphin-emu.org/ +# This module can be used in two different ways. +# +# When invoked as `cmake -P PostprocessBundle.cmake`, it fixes up an +# application folder to be standalone. It bundles all required libraries from +# the system and fixes up library IDs. Any additional shared libraries, like +# plugins, that are found under Contents/MacOS/ will be made standalone as well. +# +# When called with `include(PostprocessBundle)`, it defines a helper +# function `postprocess_bundle` that sets up the command form of the +# module as a post-build step. + +if(CMAKE_GENERATOR) + # Being called as include(PostprocessBundle), so define a helper function. + set(_POSTPROCESS_BUNDLE_MODULE_LOCATION "${CMAKE_CURRENT_LIST_FILE}") + function(postprocess_bundle target) + add_custom_command(TARGET ${target} POST_BUILD + COMMAND ${CMAKE_COMMAND} -DBUNDLE_PATH="$/../.." + -P "${_POSTPROCESS_BUNDLE_MODULE_LOCATION}" + ) + endfunction() + return() +endif() + +get_filename_component(BUNDLE_PATH "${BUNDLE_PATH}" ABSOLUTE) +message(STATUS "Fixing up application bundle: ${BUNDLE_PATH}") + + +# Make sure to fix up any additional shared libraries (like plugins) that are +# needed. +file(GLOB_RECURSE extra_libs "${BUNDLE_PATH}/Contents/MacOS/*.dylib") + +message(STATUS "Fixing up application bundle: ${extra_dirs}") + +# BundleUtilities doesn't support DYLD_FALLBACK_LIBRARY_PATH behavior, which +# makes it sometimes break on libraries that do weird things with @rpath. Specify +# equivalent search directories until https://gitlab.kitware.com/cmake/cmake/issues/16625 +# is fixed and in our minimum CMake version. +set(extra_dirs "/usr/local/lib" "/lib" "/usr/lib") + +# BundleUtilities is overly verbose, so disable most of its messages +function(message) + if(NOT ARGV MATCHES "^STATUS;") + _message(${ARGV}) + endif() +endfunction() + +include(BundleUtilities) +set(BU_CHMOD_BUNDLE_ITEMS ON) +fixup_bundle("${BUNDLE_PATH}" "${extra_libs}" "${extra_dirs}" IGNORE_ITEM "Python")