Remove usage of macdeployqt in favor of CMake BundleUtilities. BundleUtilities properly finds all dependencies and adds them to the .app automatically. It also fixes rpath and install_name issues for any of the binaries or dependencies
authorraptor <buckyballreaction@gmail.com>
Tue, 13 Aug 2019 13:20:28 -0600
changeset 15313 7e3bd4030aa5
parent 15312 5b2dec63f4cf
child 15314 fe705efbfc52
Remove usage of macdeployqt in favor of CMake BundleUtilities. BundleUtilities properly finds all dependencies and adds them to the .app automatically. It also fixes rpath and install_name issues for any of the binaries or dependencies
cmake_modules/paths.cmake
tools/CMakeLists.txt
tools/CreateMacBundle.cmake.in
--- a/cmake_modules/paths.cmake	Tue Aug 13 13:10:12 2019 -0600
+++ b/cmake_modules/paths.cmake	Tue Aug 13 13:20:28 2019 -0600
@@ -59,6 +59,7 @@
     #@rpath mangling
     set(CMAKE_INSTALL_RPATH "@executable_path/../Frameworks")
     #install_name_tool for libraries
+    set(CMAKE_BUILD_WITH_INSTALL_NAME_DIR TRUE)
     set(CMAKE_INSTALL_NAME_DIR "@executable_path/../Frameworks")
 else(APPLE AND NOT (${CMAKE_INSTALL_PREFIX} MATCHES "/usr"))
     #paths where to find libraries (final slash not optional):
--- a/tools/CMakeLists.txt	Tue Aug 13 13:10:12 2019 -0600
+++ b/tools/CMakeLists.txt	Tue Aug 13 13:20:28 2019 -0600
@@ -26,9 +26,6 @@
         endif()
     endif()
 
-    get_target_property(qmake_executable Qt5::qmake IMPORTED_LOCATION)
-    get_filename_component(qt_bin_dir "${qmake_executable}" DIRECTORY)
-
     #remove the ";-framework Cocoa" from the SDL2_LIBRARY variable
     string(REGEX REPLACE "(.*);-.*" "\\1" sdl_library_only "${SDL2_LIBRARY}")
     #remove the "libSDLmain.a" from the SDL2_LIBRARY variable
@@ -39,22 +36,75 @@
     string(REGEX REPLACE ".*/(.*)$" "\\1" ZLIB_LIBNAME "${ZLIB_LIBRARY}")
 
     set(frameworks_dir ${CMAKE_INSTALL_PREFIX}/${target_library_install_dir})
+    
     if(${BUILD_ENGINE_LIBRARY})
         set(engine_full_path "${frameworks_dir}/${CMAKE_SHARED_LIBRARY_PREFIX}hwengine${CMAKE_SHARED_LIBRARY_SUFFIX}")
     else()
         set(engine_full_path "${CMAKE_INSTALL_PREFIX}/hwengine${CMAKE_EXECUTABLE_SUFFIX}")
     endif()
 
-    find_program(macdeployqt_executable NAMES macdeployqt PATHS ${qt_bin_dir})
-    if(NOT macdeployqt_executable)
-        message(FATAL_ERROR "The utility macdeployqt is required to create the bundle (searched: ${qt_bin_dir})")
-    endif()
+
+    #create the .app bundle using BundleUtilities instead of old macdeployqt
+    set(APP_DIR "Hedgewars.app")
+    set(APP_BASE_DIR "${CMAKE_INSTALL_PREFIX}/../")  # should be, Hedgewars.app/Contents/MacOS/../
+
+    # macro to install qt5 plugins 
+    # modified from https://github.com/Kitware/CMake/blob/master/Source/QtDialog/CMakeLists.txt
+    macro(install_qt5_plugin _qt_plugin_name _qt_plugins_var)
+      get_target_property(_qt_plugin_path "${_qt_plugin_name}" LOCATION)
+      if(EXISTS "${_qt_plugin_path}")
+        get_filename_component(_qt_plugin_file "${_qt_plugin_path}" NAME)
+        get_filename_component(_qt_plugin_type "${_qt_plugin_path}" PATH)
+        get_filename_component(_qt_plugin_type "${_qt_plugin_type}" NAME)
+        set(_qt_plugin_dir "PlugIns")
+        set(_qt_plugin_dest "${_qt_plugin_dir}/${_qt_plugin_type}")
+        install(FILES "${_qt_plugin_path}"
+          DESTINATION "../${_qt_plugin_dest}" # relative to install dir
+          ${COMPONENT})
+        list(APPEND ${_qt_plugins_var}
+          "\${CMAKE_BINARY_DIR}/${APP_BASE_DIR}/${_qt_plugin_dest}/${_qt_plugin_file}")
+      else()
+        message(FATAL_ERROR "QT plugin ${_qt_plugin_name} not found")
+      endif()
+    endmacro()
 
-    #create the .app bundle
-    configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CreateMacBundle.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/CreateMacBundle.cmake)
-    install(SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/CreateMacBundle.cmake
-            CODE "message(STATUS \"Your app bundle is ready\")")
+    # install cocoa plugin and build list to send to fixup_bundle
+    install_qt5_plugin("Qt5::QCocoaIntegrationPlugin" QT_PLUGINS)
+    file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/qt.conf"
+        "[Paths]\nPlugins = ${_qt_plugin_dir}\n")
+    install(FILES "${CMAKE_CURRENT_BINARY_DIR}/qt.conf"
+        DESTINATION "../Resources"  # relative to install dir
+        ${COMPONENT})
 
+    # Build up search directories for fixup_bundle
+    set(DIRS "")
+    # Add QT bin and lib paths
+    if(CMAKE_PREFIX_PATH)
+        foreach(dir ${CMAKE_PREFIX_PATH})
+            list(APPEND DIRS "${dir}/bin" "${dir}/lib")
+        endforeach()
+    endif()
+    # Add other lib folder from around the system
+    list(APPEND DIRS 
+        ~/Library/Frameworks
+        /Library/Frameworks
+        /usr/local/lib
+        /opt/local/lib
+    )
+
+    # operate on the Hedgewars.app
+    set(APPS ${CMAKE_BINARY_DIR}/${APP_DIR})
+    
+    # debugging
+    message(STATUS "APPS: ${APPS}")
+    message(STATUS "QT_PLUGINS: ${QT_PLUGINS}")
+    message(STATUS "DIRS: ${DIRS}")
+
+    # properly fixup the .app to include all dependencies    
+    install(CODE "include(BundleUtilities)
+        fixup_bundle(\"${APPS}\" \"${QT_PLUGINS}\" \"${DIRS}\")")
+    
+    
     #create the .dmg for deployment
     #first make sure .app exists, then remove any old .dmg with same name, finally run the script
     add_custom_target(dmg COMMAND make install
@@ -68,7 +118,7 @@
                                   --app-drop-link 410 190
                                   --background "${CMAKE_CURRENT_SOURCE_DIR}/../misc/dmgBackground.png"
                                   ${CMAKE_BINARY_DIR}/Hedgewars-${HEDGEWARS_VERSION}.dmg
-                                  ${CMAKE_BINARY_DIR}/Hedgewars.app
+                                  ${CMAKE_BINARY_DIR}/${APP_DIR}
                           WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
 endif()
 
--- a/tools/CreateMacBundle.cmake.in	Tue Aug 13 13:10:12 2019 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-# check for a well known-framework
-execute_process(COMMAND stat ${frameworks_dir}/QtCore.framework RESULT_VARIABLE doBundle OUTPUT_QUIET ERROR_QUIET)
-# prepare Frameworks directory
-execute_process(COMMAND mkdir -p ${frameworks_dir})
-# macdeployqt will convert safely any absolute path library for 'hedgewars'
-execute_process(COMMAND ${macdeployqt_executable} ${CMAKE_BINARY_DIR}/Hedgewars.app OUTPUT_QUIET ERROR_QUIET)
-
-# but macdeployqt will not work for a second executable, so employ this series of ridiculous commands to work around it
-execute_process(COMMAND mv ${CMAKE_BINARY_DIR}/Hedgewars.app/Contents/MacOS/hedgewars ${CMAKE_BINARY_DIR}/Hedgewars.app/Contents/MacOS/tmp)
-execute_process(COMMAND mv ${CMAKE_BINARY_DIR}/Hedgewars.app/Contents/MacOS/hwengine ${CMAKE_BINARY_DIR}/Hedgewars.app/Contents/MacOS/hedgewars)
-execute_process(COMMAND ${macdeployqt_executable} ${CMAKE_BINARY_DIR}/Hedgewars.app OUTPUT_QUIET ERROR_QUIET)
-execute_process(COMMAND mv ${CMAKE_BINARY_DIR}/Hedgewars.app/Contents/MacOS/hedgewars ${CMAKE_BINARY_DIR}/Hedgewars.app/Contents/MacOS/hwengine)
-execute_process(COMMAND mv ${CMAKE_BINARY_DIR}/Hedgewars.app/Contents/MacOS/tmp ${CMAKE_BINARY_DIR}/Hedgewars.app/Contents/MacOS/hedgewars)
-
-if(doBundle EQUAL 1)
-    if(${SPARKLE_FOUND})
-        execute_process(COMMAND cp -pPR ${SPARKLE_LIBRARY} ${frameworks_dir})
-    endif()
-    message(STATUS "Frameworks and libraries successfully copied...")
-else()
-    message(STATUS "Frameworks already present, skipping...")
-endif()