CMake MacOS X 捆绑包与用于 Qt 应用程序的 BundleUtiliies

2024-02-21

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

// main.cpp
#include <QApplication>
#include <QLabel>

int main(int argc, char** argv)
{
    QApplication app(argc,argv);
    QLabel lbl("Hello");
    lbl.show();
    return app.exec();
}

The 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 )

I run cmake .. -DCMAKE_PREFIX_PATH=/path/to/Qt5.5.1/它产生Makefile in the build目录。

然后我跑make并有QtBundle.app我想要的目录和QtBundle.app/Contents/MacOS/QtBundle可执行,OK。

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

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它使用 Framework 和 PlugIns 文件夹中的大量文件填充包目录,并且应用程序是能够运行并重新定位到另一个系统。

它部分解决了问题,但是我想用 CMake 填充包并捆绑实用程序 https://cmake.org/cmake/help/v3.5/module/BundleUtilities.html并且没有 macdeployqt 工具。

不幸的是,我没有找到任何使用 BundleUtilities 部署 Qt5 的好的简单示例。

有人可以帮我吗修改我的“helloworld”示例,以便 CMake 自动创建准备部署包?

提前致谢。

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


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

install_qt5_plugin()宏按名称定位插件。它只会查找已找到的 Qt 模块的插件。在这种情况下,Qt5::QCocoaIntegrationPlugin 是 Qt5Gui 模块中的插件,通过以下方式找到它作为 Qt5Widgets 的依赖项find_package(Qt5 COMPONENTS Widgets REQUIRED)。宏为插件生成 install() 命令并计算已安装插件的完整路径。后者我们将通过(参见QT_PLUGIN变量)到fixup_bundle().

Notes:

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

依赖关系查找和修复发生在安装时。要在必要的位置获取可重定位的包,可以使用指向该位置的 CMAKE_INSTALL_PREFIX 进行配置,然后构建install target.

我更喜欢使用以下命令创建 .dmg 文件

mkdir build
cd build
cmake ..
cpack -G DragNDrop

添加到 CMakeLists.txt 的内容来自here https://github.com/ionyshch/cmake-qt5widgets-macos/blob/master/CMakeLists.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)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CMake MacOS X 捆绑包与用于 Qt 应用程序的 BundleUtiliies 的相关文章

随机推荐

  • FireFox 中的 Selenium OpenQA.Selenium.DriverServiceNotFoundException

    我正在尝试开始编写 Selenium 测试 我编写的第一个非常基本的测试失败了 但有例外OpenQA Selenium DriverServiceNotFoundException using OpenQA Selenium using O
  • 获取月份为 01,02 而不是 1,2

    我正在使用 Calendar 类 更具体地说 我需要以两个数字的形式返回所有 12 个月 如果我使用以下代码 int month myCalendar get Calendar MONTH 1 这是我在不同月份得到的结果 1 2 3 4 5
  • Linux 内核 2.6.18 中的 sys_call_table

    我试图通过以下方式将系统退出调用设置为变量 extern void sys call table real sys exit sys call table NR exit 但是 当我尝试制作时 控制台给出了错误 error NR exit
  • Groovy 的尾递归

    我编写了 3 个阶乘算法 我预计会因堆栈溢出而失败 没问题 我尝试尾递归调用 并将以前的算法从递归转换为迭代 它不起作用 但我不明白为什么 I use trampoline 方法 效果如我所料 def factorial factorial
  • “fork()”后 printf 异常

    操作系统 Linux 语言 纯C 我正在继续学习一般的 C 编程 以及特殊情况下 UNIX 下的 C 编程 我发现了一个奇怪的 对我来说 行为printf 使用后的功能fork call Code include
  • 如果 pandas 中包含子字符串,则替换整个字符串

    我想替换包含特定子字符串的所有字符串 例如 如果我有这个数据框 import pandas as pd df pd DataFrame name Bob Jane Alice sport tennis football basketball
  • 使用 MVVM 将窗口句柄传递给 WPF 中的视图模型

    我正在使用需要窗口句柄的外部库 我的应用程序架构是 MVVM 但外部库并不完全适合该架构 我认为视图模型是调用需要窗口句柄的初始化函数的最合适的地方 如何将窗口句柄从我的视图获取到我的视图模型 通常 您的视图模型不应该了解视图的实现细节 例
  • jquery定时器实现

    All 是否有一个 jQuery 计时器可以启动 20 分钟的计时器并显示经过的时间 请指出它的一个小代码 var austDay new getTime austDay new getSeconds austDay var duratio
  • 使用 GCC 的软件流水线示例

    我正在寻找软件管道的真实 源代码和生成代码 示例 http en wikipedia org wiki Software pipelined http en wikipedia org wiki Software pipelining 由海
  • Excel - 获取列的前 5 个数据及其匹配的标题,但会产生重复项

    我正在开发一个使用 PHP 以 CodeIgniter 作为框架 制作的 Web 应用程序 它应该生成一个 excel 文件报告作为数据摘要 我使用 PHPSpreadsheet 作为库来生成 xlsx 文件 一切都很成功 我能够在单元格的
  • 即使作业成功完成后,内存使用量也不会降低

    我在 apscheduler 中添加了一项作业 该作业会在内存中加载一些数据 并在作业完成后删除所有对象 现在 如果我使用 python 运行此作业 它会成功运行 并且在进程成功退出后内存会下降 但是在 apscheduler 的情况下 内
  • 为什么 React Router v6 似乎无法从 URL 中删除查询字符串参数?

    我有一个应用程序 有时会加载查询字符串参数t 一开始 我希望应用程序读取此参数 如果可用 并将其从 URL 中删除 在根组件上 我正在这样做 const searchParams setSearchParams useSearchParam
  • 使用 Rails 在 Net::HTTP::Get.new 中设置自定义超时

    我正在使用此代码来抓取外部 html 文件 link URI parse url request Net HTTP Get new link path response Net HTTP start link host link port
  • iPhone:无法让模拟器生成 .gcda 分析数据文件

    我正在尝试使用 iPhone 模拟器分析我的代码 我已启用生成测试覆盖率文件 and 仪器程序流程并添加了 lgcov到链接器标志 根据我读过的所有内容 这应该是我在设置方面需要做的全部事情 Update 生成测试覆盖率文件触发 f测试覆盖
  • 在 iOS 上录制、修改和播放音频

    EDIT 最后 我完全按照下面的解释 使用 AVRecorder 来录制语音 使用 openAL 来进行音调转换和播放 效果很好 我有一个关于录制 修改和播放音频的问题 我之前也问过类似的问题 在 iOS 上实时录制 修改音高和播放音频 h
  • NPAPI 插件未在 Chrome 上加载

    我有一个由 dll 和 manifest json 文件组成的 npapi 插件 此 npapi dll 被检测为 chrome 上的插件 即它列在 about plugins 页面上 但是 当我使用标签在示例 html 页面中调用此插件时
  • groupBy 的子流可以依赖于它们生成的键吗?

    我有一个包含与用户关联的数据的流程 我还为每个用户提供了一个状态 我可以从数据库异步获取该状态 我想将我的流与每个用户一个子流分开 并在具体化子流时加载每个用户的状态 以便可以根据该状态来处理子流的元素 如果我不想合并下游的子流 我可以做一
  • 为什么C++中的多重定义错误不是由const int声明引起的?

    我有一个头文件foo h ifndef FOO H define FOO H const char USB MANAGER DBUS SERVICE com USBService define USB MANAGER DBUS OBJ PA
  • 淘汰赛js的无容器声明在热毛巾SPA中​​不起作用?

    我试图使用无容器语句 例如热毛巾模板中的淘汰赛 js 但它不起作用 相反 如果我使用与某些元素 如 div 的可见绑定 那么它工作得很好 div div 谁能告诉我 knockoutjs 的无容器语句在热毛巾模板中是否不起作用 在默认热毛巾
  • CMake MacOS X 捆绑包与用于 Qt 应用程序的 BundleUtiliies

    我是一名 CMake 初学者 在为 MacOS X 创建 Qt 应用程序包时遇到问题 让我们考虑一个简单的小部件 helloworld 应用程序main cpp file main cpp include