StupidBeauty
Read times:4574Posted at: - no title specified

Qt5.5文档翻译:用于OS X系统的Qt——部署,Qt for OS X - Deployment

这篇文档,说明的是,如何创建一个 OS X 程序包,并且确保 该程序在运行时能够找到它所需要的资源。 为了演示这个过程,我们会在此文档中说明如何Qt 部署安装包自带的那个 Plug & Paint 示例程序。

OS X 版的Qt 安装程序中包含了一个 部署工具 ,它会自动完成这里所描述的过程。

应用程序包

OS X系统中,一个图形界面的程序,必须被作为一个应用程序包来构建及运行,这种应用程序包,是一个目录结构,在Finder 中会呈现为一个单个的实体。一个应用程序包,一般会包含着可执行程序以及它所需要的所有资源。下面是某个应用程序包结构的截屏:

应用程序包,为用户提供了狠多优点:

  • •.它狠容易安装,因为,它被看作是一个单个的实体。

  • •.可从代码中获取应用程序包中的信息。

这种特性,是 OS X独有 的,已经超出了本文的研究范围。欲知更多关于应用程序 包的信息,则访问 苹果公司 的开发者网站

qmake 会自动地为妳的应用程序生成一个应用程序包。要禁用这种行为,则向妳的应用程序的项目文件( .pro )中加入以下指令:

CONFIG-=app_bundle

静态链接

如果想要让事情尽可能地简单,并且只部署少数几个文件的话,那么,必须利用静态链接的库来编译妳的程序。

静态编译Qt

首先安装一个静态编译版本的Qt库。记住,妳无法使用插件,并且,必须以静态链接的方式来构建那些依赖库,例如图片格式、SQL驱动等等

cd /path/to/Qt

./configure -static <other parameters>

make sub-src

可运行 configure  -help,以了解 有哪些可用的选项。

将程序与静态链接版本的Qt链接起来

当妳完成静态编译Qt的过程之后,下一步就是,重新生成makefile,并且重新构建程序。首先,我们必须切换到包含着该程序的目录:

cd /path/to/Qt/examples/tools/plugandpaint

然后 ,运行 qmake ,以 便 为该应用程序生成一个新的makefile 。然后 ,重新构建该应用程序,以产生出一个静态链接的程序:

make clean

qmake -config release

make

妳可能想要与发布版本的库链接起来,那么 ,妳可以在运行 qmake 的时候指定这一点。如果 妳安装了 Xcode Tools 1.5 或更高的版本,那么, 妳还可以利用 " 死代码剥离 "功能 来减小该二进制文件的尺寸。具体 做法就是, 在运行 qmake 的时候,除了 -config release 参数之外,还传入另一个参数 LIBS+= -dead_strip

现在,如果所有代码 都正确的编译及链接通过了,那么, 我们应当已经得到一个可以部署的 plugandpaint.app 应用程序包了。试试 ,将这个应用程序包安装到 一个未安装Qt 或任何Qt 应用程序的OS X 系统上。

可使用 otool 来检查妳的程序还会链接到哪些其它库:

otool -L plugandpaint.app/Contents/MacOs/plugandpaint

对于静态链接 Plug & Paint ,其输出应当是以下这样的:

plugandpaint.app/Contents/MacOS/plugandpaint:

/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon

        (compatibility version 2.0.0, current version 128.0.0)

/System/Library/Frameworks/QuickTime.framework/Versions/A/QuickTime

        (compatibility version 1.0.0, current version 10.0.0)

/usr/lib/libz.1.dylib

        (compatibility version 1.0.0, current version 1.2.3)

/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices

        (compatibility version 1.0.0, current version 22.0.0)

/usr/lib/libstdc++.6.dylib

        (compatibility version 7.0.0, current version 7.3.0)

/usr/lib/libgcc_s.1.dylib

        (compatibility version 1.0.0, current version 1.0.0)

/usr/lib/libmx.A.dylib

        (compatibility version 1.0.0, current version 92.0.0)

/usr/lib/libSystem.B.dylib

        (compatibility version 1.0.0, current version 88.0.0)

如果妳在输出内容中发现了 Qt 库,那么,意味着,妳的机器上同时安装着动态和静态的Qt库。链接器永远会优先选项进行动态链接,其次才进行静态链接。如果妳只想使用静态库,那么,可采用以下某种方法:

  • •. 在链接程序时,将妳的 Qt动态 ( .dylibs )移动 到别的目录去,日后 再移动回来,

  • •. 或者 ,编辑 Makefile 文件,将针对Qt 库的链接代码修改成指向静态库的绝对路径。

例如,将以下代码:

-lQtGui

替换成:

/where/static/qt/lib/is/libQtGui.a

Plug & Paint 示例 由多个组件组成:核心程序 ( Plug & Paint ) ,以及, Basic Tools Extra Filters 插件。由于 我们无法使用静态链接方式来部署插件,因此, 我们目前所产生的应用程序包是不完整的。 这个程序将能够运行起来,但是,由于缺失插件, 其功能会受限。 要想部署基于插件的程序,我们应当采用框架方式,这是OS X 独有的。

框架

在这种方式中,需要确保,Qt运行时环境是随着该应用程序包正确地分发了,那些插件也要被安装到正确的位置,以使得程序能够找到它们。

以框架方式在程序中附带Qt,也有两种不同方法:

  • •.在妳的程序包中自带的私有框架。

  • •.标准框架(同时,使用安装的二进制程序中的Qt 框架作为替补)

如果妳以某种特殊的方式构建了Qt,或者想要确保该框架的存在的话,则应当采用第一种手段。它就在妳自己放置Qt 框架的位置。

如果妳有多个Qt 程序,并且希望它们共用同一个Qt 框架,而不是各自附带一个,那么,妳应当采用第二种手段。

以框架的形式构建Qt

我们假设妳已经将 Qt 以框架的形式安装了, 而这是安装Qt 时的默认情况,它会被安装到/path/to/Qt目录。欲知更多关于如何 将Qt 构建为不带框架的形式,则阅读 用于OS X Qt ——特殊问题 文档。

在安装时,会为那些框架设置其标识名字。链接 器( dyld )会利用这个名字来找到妳的应用程序所需要的库。

以框架的形式将妳的程序与Qt 链接起来

在以框架的形式构建了Qt 之后, 我们就可以构建 Plug & Paint 程序了。首先 ,我们切换到包含着该程序的目录:

cd /path/to/Qt/examples/tools/plugandpaint

现在 ,运行 qmake ,以便为该程序创建一个新的makefile。然后 ,重新构建,以产生出一个动态链接的可执行文件:

make clean

qmake -config release

make

这样就会构建出核心程序。然后,使用以下命令来构建那些插件:

cd ../plugandpaintplugins

make clean

qmake -config release

make

现在 ,针对那些Qt 框架运行 otool ,例如,对于Qt Gui:

otool -L QtGui.framework/QtGui

将会产生以下输出:

QtGui.framework/QtGui:

/path/to/Qt/lib/QtGui.framework/Versions/4.0/QtGui

        (compatibility version 4.0.0, current version 4.0.1)

/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon

        (compatibility version 2.0.0, current version 128.0.0)

/System/Library/Frameworks/QuickTime.framework/Versions/A/QuickTime

        (compatibility version 1.0.0, current version 10.0.0)

/path/to/Qt/QtCore.framework/Versions/4.0/QtCore

        (compatibility version 4.0.0, current version 4.0.1)

/usr/lib/libz.1.dylib

        (compatibility version 1.0.0, current version 1.2.3)

/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices

        (compatibility version 1.0.0, current version 22.0.0)

/usr/lib/libstdc++.6.dylib

        (compatibility version 7.0.0, current version 7.3.0)

/usr/lib/libgcc_s.1.dylib

        (compatibility version 1.0.0, current version 1.0.0)

/usr/lib/libmx.A.dylib

        (compatibility version 1.0.0, current version 92.0.0)

/usr/lib/libSystem.B.dylib

        (compatibility version 1.0.0, current version 88.0.0)

对于Qt框架 ,第一行 ( 也就是说, path/to/Qt/lib/QtGui.framework/Versions/4/QtGui (compatibility version 4.0.0, current version 4.0.1) ) 即成为该框架的标识名字,动态链接 器( dyld )会使用该名字。

可是 ,当妳部署该应用程序的时候,用户 的电脑上可能并没有在对应的位置安装有Qt 框架。因此 妳必须做点什么:或者 将框架放置到某个一致同意的位置去;或者, 将框架直接放置在应用程序包里。无论 妳采用哪种手段,都必须确保,那些框架 为自己返回了正确的标识名字, 而同时呢,应用程序 也正是以那些名字来寻找框架。幸运 的是,我们可以使用命令行工具 install_name_tool 来控制这些东西。

install_name_tool 有两种工作模式: -id -change -id 模式用于 库和框架, 可用来指定一个新的标识名字。 -change 模式呢,用来改变程序内部的那些路径。

让我们来试验一下, 将那些 Qt框架复制 到Plug & Paint 应用程序包中。查看 otool 对于 该应用程序包的输出内容, 我们会发现,必须 QtCore QtGui 框架复制到应用程序包中。假设 ,我们现在正处在构建该应用程序包的目录中。

mkdir plugandpaint.app/Contents/Frameworks

cp -R /path/to/Qt/lib/QtCore.framework

        plugandpaint.app/Contents/Frameworks

cp -R /path/to/Qt/lib/QtGui.framework

       plugandpaint.app/Contents/Frameworks

首先 ,我们在应用程序包中创建一个 Frameworks 目录。 这是遵循 OS X应用程序惯例 的。然后 ,我们将那些框架复制到这个新目录中。由于框架 中包含着符号链接,所以,我们要使用 -R 选项。

install_name_tool -id @executable_path/../Frameworks/QtCore.framework/Versions/4.0/QtCore

       plugandpaint.app/Contents/Frameworks/QtCore.framework/Versions/4.0/QtCore

install_name_tool -id @executable_path/../Frameworks/QtGui.framework/Versions/4.0/QtGui

       plugandpaint.app/Contents/Frameworks/QtGui.framework/Versions/4.0/QtGui

然后 ,我们运行 install_name_tool 来为那两个框架设置标识名字。 -id 后面的第一个参数即为它的新名字,而第二个参数,就是我们要重命名的那个框架本身。字符串 @executable_path 是一个特殊的 dyld 变量 ,告知 dyld 要以该可执行程序为基准路径来查找文件。 新赋予的这些名字,表明, 这两个框架是位于此目录下的 Frameworks 目录中的。

install_name_tool -change path/to/Qt/lib/QtCore.framework/Versions/4.0/QtCore

        @executable_path/../Frameworks/QtCore.framework/Versions/4.0/QtCore

        plugandpaint.app/Contents/MacOs/plugandpaint

install_name_tool -change path/to/qt/lib/QtGui.framework/Versions/4.0/QtGui

        @executable_path/../Frameworks/QtGui.framework/Versions/4.0/QtGui

        plugandpaint.app/Contents/MacOs/plugandpaint

现在 ,动态链接器就知道去哪里寻找 QtCore QtGui 了。 我们还必须确保,这个应用程序知道去哪里寻找对应 的库, 这就要用到 install_name_tool -change 模式了。 这个过程本质上是字符串替换, 以匹配我们之前针对那两个框架所设置的标识名字。

最后 QtGui 框架 还依赖 QtCore ,所以 我们还要记得改变 QtGui 中的引用:

install_name_tool -change path/to/Qt/lib/QtCore.framework/Versions/4.0/QtCore

        @executable_path/../Frameworks/QtCore.framework/Versions/4.0/QtCore

        plugandpaint.app/Contents/Frameworks/QtGui.framework/Versions/4.0/QtGui

做完这些之后,我们再次运行 otool 将会发现,这个应用程序能够找到那些库了。

Plug & Paint 示例 中的那些插件,为它增加了额外的工作量。对于插件, 我们需要采取以下步骤:

  • •.将插件放置到应用程序包中,

  • •. 运行 install_name_tool ,以检查,那些插件是否使用了正确的库,

  • •.并且,确保该应用程序知道该去哪里寻找那些插件。

我们可以将插件放置在应用程序包中的任何位置,但是,最佳位置是,放置 在Contents/Plugins 目录中。 当我们构建Plug & Paint 中的插件时,基于 .pro 文件 中的 DESTDIR 变量,那些插件 .dylib 文件会被放置在 plugandpaint 目录下的 plugins 子目录中。 我们只需要将这个目录移动到正确的位置。

mv plugins plugandpaint.app/Contents

举个例子,如果我们针对 Basic Tools 插件的 .dylib 文件运行 otool ,则,会产生以下输出。

libpnp_basictools.dylib:

libpnp_basictools.dylib

       (compatibility version 0.0.0, current version 0.0.0)

/path/to/Qt/lib/QtGui.framework/Versions/4.0/QtGui

       (compatibility version 4.0.0, current version 4.0.1)

/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon

       (compatibility version 2.0.0, current version 128.0.0)

/System/Library/Frameworks/QuickTime.framework/Versions/A/QuickTime

       (compatibility version 1.0.0, current version 10.0.0)

/path/to/Qt/lib/QtCore.framework/Versions/4.0/QtCore

       (compatibility version 4.0.0, current version 4.0.1)

/usr/lib/libz.1.dylib

       (compatibility version 1.0.0, current version 1.2.3)

/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices

       (compatibility version 1.0.0, current version 22.0.0)

/usr/lib/libstdc++.6.dylib

       (compatibility version 7.0.0, current version 7.3.0)

/usr/lib/libgcc_s.1.dylib

       (compatibility version 1.0.0, current version 1.0.0)

/usr/lib/libmx.A.dylib

       (compatibility version 1.0.0, current version 92.0.0)

/usr/lib/libSystem.B.dylib

       (compatibility version 1.0.0, current version 88.0.0)

于是,我们会看到,这个插件被链接到了它在构建时指定的那些Qt 框架。由于我们希望这些插件使用应用程序包中的那些框架,所以,我们就像改变该应用程序那样地改变它们。例如,对于Basic Tools 插件:

install_name_tool -change /path/to/Qt/lib/QtCore.framework/Versions/4.0/QtCore

        @executable_path/../Frameworks/QtCore.framework/Versions/4.0/QtCore

        plugandpaint.app/Contents/plugins/libpnp_basictools.dylib

install_name_tool -change /path/to/Qt/lib/QtGui.framework/Versions/4.0/QtGui

        @executable_path/../Frameworks/QtGui.framework/Versions/4.0/QtGui

        plugandpaint.app/Contents/plugins/libpnp_basictools.dylib

我们还必须修改代码 tools/plugandpaint/mainwindow.cpp 做出 cdUp() 动作, 以确保, 该应用程序能够找到这些插件。 mainwindow.cpp 文件中加入以下代码:

#elif defined(Q_OS_MAC)

if (pluginsDir.dirName() == "MacOS") {

    pluginsDir.cdUp();

}

#endif

tools/plugandpaint/mainwindow.cpp 中的那些额外代码,使得我们能够在Finder 中查看那些插件,如图所示。

我们还可以加入那些扩展了Qt 功能的插件,例如SQL 驱动 或图片格式。 我们只需要遵循插件文档中所指明的目录结构,并且 ,确保,它们 被包含在 QCoreApplication::libraryPaths ()中。 让我们依据前面说明过的过程来对图片格式插件做一下这个操作。

Qt的图片格式插件复制到应用程序包中:

cp -R /path/to/Qt/plugins/imageformats

        pluginandpaint.app/Contents/plugins

使用 install_name_tool 来将这些插件链接到应用程序包中的框架上去:

install_name_tool -change /path/to/Qt/lib/QtGui.framework/Versions/4.0/QtGui

        @executable_path/../Frameworks/QtGui.framework/Versions/4.0/QtGui

        plugandpaint.app/Contents/plugins/imageformats/libqjpeg.dylib

install_name_tool -change /path/to/Qt/lib/QtCore.framework/Versions/4.0/QtCore

        @executable_path/../Frameworks/QtCore.framework/Versions/4.0/QtCore

        plugandpaint.app/Contents/plugins/imageformats/libqjpeg.dylib

更新 tools/plugandpaint/main.cpp 中的代码,以寻找那些新的插件。 在构建完毕 QApplication 之后,加上以下代码:

QDir dir(QApplication::applicationDirPath());

dir.cdUp();

dir.cd("plugins");

QApplication::setLibraryPaths(QStringList(dir.absolutePath()));

首先 ,我们告知应用程序,只在这个目录中寻找插件。 在我们的项目中,我们希望该应用程序 只载入我们随应用程序包附带的那些插件 。如果 我们的程序是一个更大的Qt 程序包中的一部分,那么,我们应当使用 QCoreApplication::addLibraryPath ()。

警告: 在部署插件时,我们改变了源代码, 那会导致 在应用程序被重新构建时重置 为默认的标识名字。所以 ,妳需要再次使用 install_name_tool 来让妳的应用程序链接到正确的Qt 框架。

现在,妳应当可以将这个应用程序复制到另一个OS X 机器上,并且在不安装 Qt 的情况下运行它了。另外,还可以将这些框架移动到妳的应用程序包之外的某个目录中,以试验一下,这个应用程序还能不能运行。

如果妳将这些框架放置在应用程序包之外的另一个位置,那么,用来链接妳的应用程序的技巧是类似的;妳必须让该应用程序的那些框架就以下事情达成一致:到哪儿去寻找Qt库;到哪里去寻找插件。

创建应用程序包

当妳将妳的应用程序与Qt 链接 (无论是静态链接还是作为框架链接) 完了之后, 就可以发布它了。欲知更多信息 ,则阅读 工具工作 流指南

尽管部署应用程序的过程中有某些坑,但是,一旦妳搞清楚了各种各样的问题之后,就可以轻易地创建出让所有OS X 用户喜闻乐见的程序包了。

应用程序依赖

Qt插件

所有 Qt图形界面程序 都需要一个实现了Qt 5 中的 Qt平台抽象 (QPA)层的插件。对于 OS X ,这个平台插件的名字是 libqcocoa.dylib 这个文件,必须位于妳的发布目录中的某个特定的子目录(默认 platforms )。或者 ,也可以按照下面说明的方法来调整Qt 寻找插件时的搜索路径。

妳的应用程序可能还依赖着别的 Qt插件,例如JPEG图片格式插件 SQL驱动插件 请确保,在妳的应用程序包中带上 妳所需要的那些Qt 插件。 与平台插件类似的是,每种类型 的插件都必须放置在妳的发布目录中的特定子目录(例如 imageformats sqldrivers )中。

在部署一个使用Qt WebKit 来显示互联网上的HTML 页面的应用程序的时候,必须包含所有的文本解码器插件,以支持尽可能多的HTML 编码。

Qt 插件 的搜索路径( 以及一些其它的路径 )是硬编码到 QtCore 库中的。默认情况 下,第一 个插件搜索路径会被硬编码为 /path/to/Qt/plugins 。但是,使用 预定义的路径,有某些缺点。例如, 在目录机器上,它们可能不存在。所以 ,妳必须采用多种替代手段 ,来确保能够找到Qt 插件:

如何创建Qt插件 文档 中说明了一些问题,当妳 在构建并部署针对Qt 应用程序的插件时,需要注意 这些问题。

额外的库

妳可以使用 otool 来检查, 妳的应用程序链接到了哪些库。运行 它的时候,要提供应用程序的路径作为参数:

otool -L MyApp.app/Contents/MacOS/MyApp

与编译器相关的库,通常不需要随应用程序一起发布。但是,部署应用程序的时候有多种方式,因为,在 OS X 上,Qt可采用多种方式来配置、构建及安装。一般来说,妳的目标能够帮助决定要采用什么方式来部署该应用程序。最后小节,说明了一些在部署应用程序的过程中要注意的事项。

OS X版本依赖

Qt 5应用程序可在OS X 10.6 (Snow Leopard)及更高版本上构建及部署。这是通过 弱链接 来实现的。 弱链接 功能中,Qt会检测,当前所运行的电脑中,特定新版本的OS X 所加入的函数是否可用。这样,就使得,在运行于新版本的OS X 中的时候,Qt会使用新的特性,而同时,在旧版本的系统中,仍能保持兼容。

欲知更多关于OS X 上的交叉开发问题的信息,则访问 苹果公司 的开发者网站

链接 器被设置为与所有的OS X 版本相兼容,因此, 妳必须改变 MACOSX_DEPLOYMENT_TARGET 环境变量,以使得 弱链接 为妳的应用程序服务。 妳可以将以下代码:

QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.3

加入.pro文件中,然后,qmake就会做好后面的事。

欲知更多关于C++运行 时环境的信息,则访问 苹果公司 的开发者网站

苹果机部署工具

苹果机部署工具位于QTDIR/bin/macdeployqt。它被设计于,自动地完成以下任务:创建一个以私有框架的形式包含Qt 库的可部署的应用程序包。

苹果 机部署工具也会依据以下规则 来部署那些Qt 插件(除非指定 -no-plugins 选项 ):

要想在应用程序包中包含某个第三方库,则,在创建该应用程序包之后,手动将那个库复制到应用程序包中。

macdeployqt 支持 以下选项:

选项

说明

-verbose=<0-3>

0 = 无输出,1 = 输出错误/警告(默认)2 = 输出一般信息,3 = 输出调试信息

-no-plugins

跳过插件部署过程

-dmg

创建一个.dmg磁盘镜像

-no-strip

不要对二进制程序运行'strip'

-use-debug-libs

使用调试版本 的框架及插件进行部署 (隐匿设置 -no-strip )

-executable=<path>

让指定的可执行程序也使用这里部署的框架

-qmldir=<path>

针对指定路径下的那些.qml文件部署导入库(imports)

海藻

海藻

海藻

Your opinions
Your name:Email:Website url:Opinion content:
- no title specified

HxLauncher: Launch Android applications by voice commands