先从Windows平台开始。 Windows平台下的软件发布最主要的需求是想办法找到在你的发布中应该包含哪些必须的文件, 同时要保证应用程序运行时能正确找到这些文件, 发布基于Qt的软件也是同样的需求。 就不同的情况一一阐述:
静态链接的情况
静态链接是最简单的情况,这种情况下需要发布的文件数量是最少的, 只需要发布一个单独的执行档外加编译器相关的dll文件。 这种情况下Qt库首先要静态编译:
< [other -static>
nmake sub-src
//如果用mingw编译,nmake替换成mingw32-make
//sub-src指只编译src目录,这样省去编译examples等目录的时间注意哦,如果你在同一个build目录用不同的configure选项去编译Qt, 必须在重新configure之前运行nmake distclean清除以前生成的目标和中间文件, 保证一个干净的编译环境,不然有可能会出一些奇怪的链接错误哦~~
编译好Qt静态库下一步再编译应用程序:
cd application_dir
nmake clean
qmake -config release
nmake编译成功之后应该得到一个可以独立执行的exe文件, 可以将程序拷贝到其他没有安装qt的机器上测试。 需要注意的是这个程序不一定百分之百可以运行,因为编译器带的库仍然是动态编译的,如果你的目标机里没有这些库的话仍然会有运行时的问题。 后面会讲到如何用工具来检查应用程序的依赖。
静态链接方法比较重要的缺陷是无法支持插件, 而且插件不能编译进程序中,所以插件提供的功能就丢失了。 这样一来要想用到插件的功能还是要用下面的方法。
动态链接的情况
动态链接程序的发布需要解决两个问题, Qt库需要与应用一起发布, 另外插件也要一起打包,并保证放在适当的位置, 这样应用程序才能找到它。
动态编译应用的基础是先将Qt库动态编译(默认参数即是动态编译),这样用普通的程序编译流程就可生成动态编译的执行档,使用的命令与上面相同。 我们可以用一个Qt的例子测试前面说的发布方法, 在Qt包里带的例子Plug & Paint
是个非常合适的测试例子,它既包含应用又自带插件文件, 可以很好的验证发布是否正确。 该例子在examples/tools/plugandpaint下。 这个例子如果编译成功, 得到一个plugandpaint.exe和pnp_basictools.dll、pnp_extrafilters.dll两个插件文件。程序打包
第一步,将应用程序和Qt库拷贝到同一目录。(Windows下库的搜索先从当前目录开始,然后是在系统PATH环境变量指定的路径查找。)
第二步,检查应用程序还依赖哪些dll,如编译器带的dll或其他系统dll。 参见应用程序的依赖关系一节。
第三步,验证程序可以在目标系统上正确运行, 将目前包里的文件拷贝到目标系统上,尝试运行程序。
第四步,发布插件程序。 插件和普通的动态库的发布不同, 不能简单的将之拷贝到应用目录里。 应用程序在运行时会在其对应的plugins目录下去查找插件。 针对这个例子,发布包应该类似这样的结构:
模块
文件名
执行档 plugandpaint.exe Basic Tool插件 plugins\pnp_basictools.dll ExtraFilters插件 plugins\pnp_extrafilters.dll Qt Core模块 qtcore4.dll Qt Gui模块 qtgui4.dll 除了程序和Qt库,还有下面的编译器库:
VC++ 6.0
VC++ 7.1 (2003)
VC++ 8.0 (2005)
C运行库 msvcrt.dll msvcr71.dll msvcr80.dll C++运行库 msvcp60.dll msvcp71.dll msvcp80.dll 插件的位置除了Qt默认的路径还可以通过代码里调用Qt的API来指定, 相应的API是QApplication::addLibraryPath()或QApplication::addLibraryPaths(). 如:
qApp->addLibraryPath(”c:\some\path”);
上述代码的推荐调用位置是在main函数中,QApplication构造完毕之后。 应用程序会在搜索默认路径之后去搜索你指定的库路径。
Visual Studio 2005
vs2005编译的程序在发布的时候还需要考虑一些额外的情况,比较麻烦点。 要把manifest文件拷贝到应用程序的目录, 这个文件包含应用的依赖信息, 在运行时需要用到。 另外,如果你的动态库的依赖和应用不同,那么还需要把manifest文件内嵌到dll文件中。 Qt4.1.3之后的版本提供了CONFIG选项来提供内嵌manifest文件的功能, embed_manifest_dll和embed_manifest_exe, 用法是将下面的选项加入pro文件, 如下:
CONFIG+=embed_manifest_exe
默认情况下embed_manifest_dll已经开启。 关于manifest文件的更多信息参考MSDN的相关文章。
有两种发布vc运行库的方法, 一个是安装vs的运行库到目标系统中, 另外是将库打包到应用程序的目录。 打包vs运行库很简单,就是把 <Visual Studio Install Path>\VC\redist\<Architecture>\Microsoft.VC80.CRT拷贝到应用程序目录,与应用程序一起打包。 如果你在打包运行库的同时还要发布插件程序,要注意把manifest文件从插件中去掉,不然在一些系统上会导致插件无法加载。 去掉manifest的方法是在插件的pro文件中加入下面的选项:
CONFIG-=embed_manifest_dll
VS系统的运行包可以免费获得, 只需要将这个安装包和你的应用安装包一起发布,并且在安装你的程序的时候去运行这个安装包就行了。 比如32位的x86系统, 安装32bit-x86-vs运行时包。 其他平台对应的包可以在微软网站找到。
应用程序的依赖关系
额外的依赖库
这里我们的秘密武器终于隆重登场了! 那就是 Dependency Walker工具。 看一张截图:
用这个工具检查上面的例子, 发现下面的库不是系统自带的:
Qt
VC++ 6.0
VC++ 7.1 (2003)
VC++ 8.0 (2005)
MinGW
QTCORE4.DLL
QTGUI4.DLL
MSVCRT.DLL
MSVCP60.DLL
MSVCR71.DLL
MSVCP71.DLL
MSVCR80.DLL
MSVCP80.DLL
MINGWM10.DLL(如果用mingw来编译的话需要这个库) 别忘了也检查一下plugin库的依赖。
Qt自带的插件
很多情况下,我们的程序还依赖Qt带的一些插件,比如图像格式的支持或数据库驱动支持等。 这些插件需要放在plugins的特定子目录下, 如图像格式插件在plugins\imageformat下. Qt搜索插件的默认路径是QTDIR\plugins, 这个路径已经写入了Qt库中, 但我们可以通过以下几种方法来override这个路径。
- 编辑qt.conf文件,推荐的方法(后面将写一篇关于qt.conf的帖子)
- 用前面提到的QApplication::addLibraryPath函数
- 使用第三方的工具修改QtCore库里写入的路径
Qt文档里有一篇专门写插件的文章,如果你在编译和发布插件时遇到了问题,参考 How to Create Qt Plugins