CMake MacOS X bundle with BundleUtiliies for Qt application

CMake MacOS X bundle with BundleUtiliies for Qt application

本文关键字:for Qt application BundleUtiliies with MacOS bundle CMake      更新时间:2023-10-16

我是CMake初学者,在为MacOS X创建Qt应用程序包时遇到问题。让我们考虑一个简单的小部件"helloworld"应用程序,仅在一个main.cpp文件中。

// main.cpp
#include <QApplication>
#include <QLabel>
int main(int argc, char** argv)
{
    QApplication app(argc,argv);
    QLabel lbl("Hello");
    lbl.show();
    return app.exec();
}

CMakeLists.txt文件也很简单。

# CMakeLists.txt
cmake_minimum_required( VERSION 3.0 )
project( QtBundle )    
set( CMAKE_INCLUDE_CURRENT_DIR ON )
set( CMAKE_AUTOMOC ON )
set( SOURCES main.cpp )    
find_package( Qt5Widgets REQUIRED )
add_executable( ${PROJECT_NAME} MACOSX_BUNDLE ${SOURCES} )    
qt5_use_modules( ${PROJECT_NAME} Widgets )

我运行cmake .. -DCMAKE_PREFIX_PATH=/path/to/Qt5.5.1/,它会在build目录中生成Makefile

然后我运行make并根据需要QtBundle.app目录,并QtBundle.app/Contents/MacOS/QtBundle可执行文件,好的。

但是当我启动它时,我得到:

This application failed to start because it could not find or load the Qt platform plugin "cocoa".
Reinstalling the application may fix this problem.
Abort trap: 6 

据我了解,发生错误是因为应用程序包没有任何Qt东西(框架库和插件),所以我运行macdeployqt,它用框架和插件文件夹中的大量文件填充捆绑包目录,应用程序能够运行并重新定位到另一个系统。

它部分解决了这个问题,但我想用CMake和BundleUtilities填充捆绑包,而没有macdeployqt工具。

不幸的是,我没有找到任何使用捆绑实用程序进行Qt5部署的良好而简单的示例。

有人可以帮助我修改我的"helloworld"示例,以便 CMake 自动创建可随时部署的捆绑包吗?

提前谢谢。

主要问题:如何使用CMake BundleUtilities来获取可重定位的应用程序?

将下面的代码添加到CMakeLists.txt .最具挑战性的事情是弄清楚您需要哪些插件,找到它们的名称,然后正确指定 BundleUtilities fixup_bundle()的路径。

install_qt5_plugin()宏按名称查找插件。它只会找到已经找到的Qt模块的插件。在这种情况下,Qt5::QCocoaIntegrationPlugin 是 Qt5Gui 模块中的插件,它被 find_package(Qt5 COMPONENTS Widgets REQUIRED) 找到为 Qt5Widgets 的依赖项。宏为插件生成 install() 命令并计算已安装插件的完整路径。后者我们将传递给(请参阅QT_PLUGIN变量)fixup_bundle()

笔记:

  1. 我们创建并安装qt.conf文件,以便在应用程序启动时找到插件。
  2. APPS变量指定捆绑包的路径,而不是其中的可执行文件。
  3. 填充DIRS非常重要。请注意,它如何使用CMAKE_PREFIX_PATH。
  4. 打印APPSQT_PLUGINSDIRS是可选的,但非常有用。
  5. 应该只手动复制/安装那些不是从应用程序引用的动态库(包括插件)。 Qt平台插件就是这样的动态库。

依赖项查找和修复在安装时进行。要在必要的位置获取可重定位的捆绑包,可以使用指向该位置的CMAKE_INSTALL_PREFIX进行配置,然后构建install目标。

我更喜欢创建.dmg文件

mkdir build
cd build
cmake ..
cpack -G DragNDrop

要添加到CMakeList的内容.txt来自这里:

set(prefix "${PROJECT_NAME}.app/Contents")
set(INSTALL_RUNTIME_DIR "${prefix}/MacOS")
set(INSTALL_CMAKE_DIR "${prefix}/Resources")
# based on code from CMakes QtDialog/CMakeLists.txt
macro(install_qt5_plugin _qt_plugin_name _qt_plugins_var _prefix)
    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_dest "${_prefix}/PlugIns/${_qt_plugin_type}")
        install(FILES "${_qt_plugin_path}"
            DESTINATION "${_qt_plugin_dest}")
        set(${_qt_plugins_var}
            "${${_qt_plugins_var}};$ENV{DEST_DIR}${CMAKE_INSTALL_PREFIX}/${_qt_plugin_dest}/${_qt_plugin_file}")
    else()
        message(FATAL_ERROR "QT plugin ${_qt_plugin_name} not found")
    endif()
endmacro()
install_qt5_plugin("Qt5::QCocoaIntegrationPlugin" QT_PLUGINS ${prefix})
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/qt.conf"
    "[Paths]nPlugins = ${_qt_plugin_dir}n")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/qt.conf"
    DESTINATION "${INSTALL_CMAKE_DIR}")
# Destination paths below are relative to ${CMAKE_INSTALL_PREFIX}
install(TARGETS ${PROJECT_NAME}
    BUNDLE DESTINATION . COMPONENT Runtime
    RUNTIME DESTINATION ${INSTALL_RUNTIME_DIR} COMPONENT Runtime
    )
# Note Mac specific extension .app
set(APPS "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}.app")
# Directories to look for dependencies
set(DIRS "${CMAKE_BINARY_DIR}")
# Path used for searching by FIND_XXX(), with appropriate suffixes added
if(CMAKE_PREFIX_PATH)
    foreach(dir ${CMAKE_PREFIX_PATH})
        list(APPEND DIRS "${dir}/bin" "${dir}/lib")
    endforeach()
endif()
# Append Qt's lib folder which is two levels above Qt5Widgets_DIR
list(APPEND DIRS "${Qt5Widgets_DIR}/../..")
include(InstallRequiredSystemLibraries)
message(STATUS "APPS: ${APPS}")
message(STATUS "QT_PLUGINS: ${QT_PLUGINS}")
message(STATUS "DIRS: ${DIRS}")
install(CODE "include(BundleUtilities)
    fixup_bundle("${APPS}" "${QT_PLUGINS}" "${DIRS}")")
set(CPACK_GENERATOR "DRAGNDROP")
include(CPack)