基于vs2005以上版本Qt程序发布的注意事项

最近发现了一个非常恼人的程序deployment的问题,估计大家有可能也会遇到,特此memo。

问题的出现我觉得主要还是微软搞的花头太多, 一个不知所谓的manifest文件让本来简单的程序发布变得困难重重。 找了找关于manifest的介绍,貌似这个文件是用来描述程序或者库的依赖关系, 特别是对程序依赖的版本进行描述, 这样系统可以通过manifest的内容找到正确的库版本。 理论上讲这个dd确实是不错, 可以解决版本不兼容的问题, 保证程序运行的时候用的是指定版本的库。 不过实际操作起来麻烦事一箩筐。
笔者对vs/windows编程十分之菜,可能理解的有所偏差, 欢迎指正。 大概也是从vs2005以上的版本开始程序编译时对这个manifest要求更严格了? 要么可以将manifest信息内嵌到程序里,要么就在发布程序的时候带上这个manifest文件才能保证程序找到依赖的外部库。 Qt相对这种情况也在build system内部做了相应的调整, 目前的状况是默认把manifest内嵌在binary里, 包括库、程序和插件。

按照Qt文档的说法, 发布基于vs2005以上版本的Qt程序有两种方法, 一是把vc的crt目录Microsoft.VC80.CRT拷贝到程序路径下与程序一起发布; 另外一个是在目标机器上安装vc的redistribution package。 实际上经过笔者的实验, 第一种方法行不通, 常见的症状是按照文档做了程序不能启动,或者是插件无法载入。 找了个专家咨询了一下,发现问题就出在内嵌的manifest信息上。 由于Qt库内嵌了manifest信息, 程序运行的时候系统只会到固定的位置寻找vc的库,根本就不搜索本地的路径。 笔者的试验结果是即使把vc的库放在与程序exe相同的目录下都找不到,真是奇怪哉! vs2005的程序还没遇到过这样的情况哦!

专家给出的意见是要么安装vc的redistribution package, 这个是肯定能行的。 还有一种方法是在编译Qt时在pro里加 CONFIG-=embed_manifest_dll (这一点和文档上说的似乎是相反的,可见Qt的文档有谬误。), 编译的插件也需要在pro里加 CONFIG-=embed_manifest_plugin, 包括我们的程序pro里要加 CONFIG-=embed_manifest_exe, 这样才圆满了! 这种做法的原理是程序里不嵌入库的版本和路径信息, 系统就会按照传统的方式搜索匹配的库,也就会搜索到程序所在的路径或者是文档里提到的Microsoft.VC80.CRT路径等等。

各位看官谁家有vs2005以上的版本并遇到了类似问题可以试验一下, 成功与否来冒个泡。 笔者这里没有vs2008可测试,不过想想觉得这个方案还是比较靠谱的。

Tags: , , ,
This entry was posted on Monday, March 22nd, 2010 at 12:00 PM and is filed under Qt技术, Windows技术. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

12 Responses to “基于vs2005以上版本Qt程序发布的注意事项”

  1. Aladdina says:

    我正好前几天也碰到了一样的问题,我是VS2008 SP1,我的做法是把vcredist和程序一块发布了,其实既然有了Manifest,就把vcredist一块发布吧,只是在安装的时候检查一下,有了就不安装了。这样的做法是最稳妥的。因为我开始只打包了CRT的两个包,但是还是有问题,可能是因为我也用了GUI,对ComCTRL这个DLL也有要求。VS2008 的redist只有1M多,但是SP1的有4M多,可惜我是用VS2008SP1编译的,只好打包了后面一个4M多的了。

  2. reback says:

    好像没遇到这个问题呢?在编译的时候选择多线程调试(/MTD)把运行时库静态链接到程序里好像就没这个问题了?反正我发布的时候没遇到你说的问题^_^

  3. Jay Zhang says:

    还有一个方法。google 一下mt.exe这个小程序。运行mt.exe本身需要.net framework 2.0

    1. 新建一个extracted.manifest

    2. 运行以下命令:
    mt.exe -nologo -manifest buildtool\extracted.manifest -outputresource:{0};{1}

    {0} 填入 qt 编译后的 dll, exe 文件名,每次填一个文件名然后运行以下这个命令行,可以写一个简单的批处理。
    {1} 填入 1 如果 {0} 是 exe, 填入 2 如果 {0} 是 dll

    把所有 qt 的运行库如此处理一遍以后, qt 默认就会找当前目录的 vc crt 目录, 目标机器不用再安装vcredist, 这个方法适用于不希望从源代码编译来解决这个问题的同学。

  4. Jay Zhang says:

    呵呵,这个留言系统有问题,把 extracted.manifest 的内容给过滤掉了,要的同学还是发我加我 msn 算了: ghoster_e@msn.com

  5. shiroki says:

    嘿, 可以发bbs上啊, 好找!

  6. shajunxing says:

    (很抱歉我笔记本的逗号键坏掉了)

    这个问题十分麻烦 首先得明确 Qt程序的动态/静态链接其实有两处 一处是 Qt程序和Qt库之间 第二处是Qt程序/Qt库和CRT之间 微软公司做的一件非常恶心的事情是 明明系统自带了msvcrt.dll 非要每一个新版本的VC都再包装一遍 以显示和之前的不同 再加上XP之后的Side by Side技术 复杂到极致 解决办法是Qt程序/Qt库和CRT之间采用静态链接的方式 也就是编译器编译选项从默认的 MD/MDd 改成 MT/MTd Qt库的编译和程序的编译都要改 这样再用Dependency Walker观察编译完之后的DLL和EXE 会发现那些恼人的msvcrXX.dll引用不见了

    程序现在大部分情况能正常运行了 但是有一个非常严重的潜在问题 参见http://msdn.microsoft.com/en-us/library/ms235460.aspx 这里就不翻译了 所以要完全解决这个问题 只能Qt程序和Qt库之间也用静态链接的方式 也就是编译Qt库的时候加上-static选项

    其实我更倾向于在Windows平台上使用MinGW代替VC 因为MinGW的CRT始终用的是msvcrt.dll 很爽 呵呵

  7. shajunxing says:

    这篇文章详细批判了微软的msvcrXX.dll 呵呵:
    http://blog.koroirc.com/2008/06/visual-cpp-woes/

  8. chai says:

    qt现在都有专门的VS 2008版本,那为何不在默认的pro文件中配置好呢。

  9. 蓝色忧郁 says:

    还真没感觉到这么麻烦。
    我在VS2005、VS2008发布过应用程序(不过都是EXE,没试过DLL)时都是OK的,基本上都是把VS相应的dll连同应用程序的EXE及QT相应的库带上就行了,具体如下(以release为例,debug的相应加d就行了):
    VS2005 :
    Microsoft.VC80.CRT.manifest msvcm80.dll msvcp80.dll msvcr80.dll
    VS2008:
    msvcm90.dll msvcp90.dll msvcr90.dll

  10. dbzhang800 says:

    这个我试过,Qt Manual提到的方法在我这而正确的(测试环境VS2008)

    有图有真相,^_^
    http://hi.baidu.com/cyclone/blog/item/d77a86182fb915b84bedbc57.html

  11. shiroki says:

    你这篇文章好, 写的比我的清楚透彻, 应该转过来, 呵呵

Leave a Reply