迁移到MSYS2 与 Qt 工具链注意的几个事情(注意链接顺序,并且人造mingw工具链所没有的局部midl.exe命令)

Posted 朝闻道

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了迁移到MSYS2 与 Qt 工具链注意的几个事情(注意链接顺序,并且人造mingw工具链所没有的局部midl.exe命令)相关的知识,希望对你有一定的参考价值。

     Microsoft Visual Studio 2015社区版提供了强大的开发体验,且 Qt 提供了预编译版本。然而,由于客户提出兼容Windows XP ~ Windows 8.1 这样宽泛的环境要求,使得我们不得不考虑更换工具链。经过反复对比测试,在Mingw32, Cygwin,  MSYS2, Visual Studio 2010几个工具链中,综合性能、未来的可持续性、中文支持以及第三方库支持(比如qwt),认为MSYS2较为合适。在后续复杂的迁移过程中,基本是平顺的,但也遇到了一些问题,这里做个记录。

     1、ActiveQt COM/OLE 支持有问题,需要额外设置编译参数

      我们有个子项目需要生成一个ActiveX控件,使用到了 QAxContainer模块。在编译时,报告了上百个编译错误,提示找不到 libole32.a, libuuid.a 等库中包含的符号。经过简单分析,特别是MakeFile中的编译器指令提示,MSYS2没有正确处理ActiveQt的链接选项。具体说来,由于g++在链接时,符号依赖项查找遵循从左至右的顺序,如果设置不当,会导致诡异的链接错误,请参考这篇文章。 

      知道了这个问题,我们手工在pro文件中加入下面的内容:

    

[plain] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. LIBS += -lQt5AxServer -lQt5AxBase -lole32 -loleaut32 -luser32 -lgdi32 -ladvapi32 -luuid  

 

 

错误竟然依旧!继续观察qmake出来的MakeFile,发现-lQt5Ax* 都被放到了最后。一拍脑袋,怎么忘记了, qmake 在产生Makefile对相同名称的库进行合并,会改变其原有的顺序这个坑~!于是,把需要使用 QAxServer 模块的工程改成这样:

 

[plain] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. win32-g++{  
  2.     CONFIG += no_lflags_merge  
  3.     LIBS += -lQt5AxServer -lQt5AxBase -lole32 -loleaut32 -luser32 -lgdi32 -ladvapi32 -luuid  
  4. }  

        把需要使用 QAxContainer 模块的工程改成这样:

 

 

[plain] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. win32-g++{  
  2.     CONFIG += no_lflags_merge  
  3.     LIBS += -lQt5AxContainer -lQt5AxBase -lole32 -loleaut32 -luser32 -lgdi32 -ladvapi32 -luuid  
  4. }  


    no_lflags_merge 表示不进行库合并和排序(排序是合并的副作用,估计内部合并时用了类似set 之类的类stl容器),这样,Makfile中,Qt5Ax*库就位于系统库之前了!这一点在Qt官方Mingw32安装版里是调整好了的。

 

     修改后,链接通过,但是,Post Link 流程出错。

    

    2. 解决参数转译符冲突

      链接后,第一个问题是无法生成IDL文件。考察编译输出命令行,发现对 idc.exe 调用时,传参数使用的是 windows 参数转译符 "/"。然而,在msys2环境里,"/"不是unix命令行的合法参数转译符,应该用“-”(减号)才对。不要紧,这个编译后事件的命令全部存储在 mingw32(64)/share/qt5/mkspecs/features/win32/idcidl.prf 里。这个文件的内容如下:

 

[plain] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. ...  
  2. !qaxserver_no_postlink {  
  3.     !isEmpty(QMAKE_POST_LINK):QMAKE_POST_LINK += $ $quote($ $ACTIVEQT_NEWLINE)  
  4.     QMAKE_POST_LINK += $ $quote($ $ACTIVEQT_IDC $ ${ACTIVEQT_TARGET} /idl $ ${ACTIVEQT_OUTPUT}.idl -version $ ${ACTIVEQT_VERSION}$ ${ACTIVEQT_NEWLINE})  
  5.     !isEmpty(RC_FILE) {  
  6.         QMAKE_POST_LINK += $ $quote($ $ACTIVEQT_IDL "$ ${ACTIVEQT_OUTPUT}.idl" /nologo /tlb "$ ${ACTIVEQT_OUTPUT}.tlb"$ $ACTIVEQT_NEWLINE)  
  7.         QMAKE_POST_LINK += $ $quote($ $ACTIVEQT_IDC $ ${ACTIVEQT_TARGET} -tlb $ ${ACTIVEQT_OUTPUT}.tlb$ $ACTIVEQT_NEWLINE)  
  8.     } else {  
  9.         QMAKE_POST_LINK += $ $quote($ $ACTIVEQT_IDL "$ ${ACTIVEQT_OUTPUT}.idl" /nologo /tlb "$ ${ACTIVEQT_TLBOUT}"$ $ACTIVEQT_NEWLINE)  
  10.         message("No rc-file linked into project; type library will be a separate file.")  
  11.     }  
  12.     !qaxserver_no_register: \\  
  13.         QMAKE_POST_LINK += $ $quote($ $ACTIVEQT_IDC $ ${ACTIVEQT_TARGET} /regserver)  
  14.     QMAKE_CLEAN += $ ${ACTIVEQT_OUTPUT}.idl $ ${ACTIVEQT_OUTPUT}.tlb  
  15. }  



 

二话不说,全部改为"-"

 

[plain] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. !qaxserver_no_postlink {  
  2.     !isEmpty(QMAKE_POST_LINK):QMAKE_POST_LINK += $ $quote($ $ACTIVEQT_NEWLINE)  
  3.     QMAKE_POST_LINK += $ $quote($ $ACTIVEQT_IDC $ ${ACTIVEQT_TARGET} -idl $ ${ACTIVEQT_OUTPUT}.idl -version $ ${ACTIVEQT_VERSION}$ ${ACTIVEQT_NEWLINE})  
  4.     !isEmpty(RC_FILE) {  
  5.         QMAKE_POST_LINK += $ $quote($ $ACTIVEQT_IDL "$ ${ACTIVEQT_OUTPUT}.idl" -nologo -tlb "$ ${ACTIVEQT_OUTPUT}.tlb"$ $ACTIVEQT_NEWLINE)  
  6.         QMAKE_POST_LINK += $ $quote($ $ACTIVEQT_IDC $ ${ACTIVEQT_TARGET} -tlb $ ${ACTIVEQT_OUTPUT}.tlb$ $ACTIVEQT_NEWLINE)  
  7.     } else {  
  8.         QMAKE_POST_LINK += $ $quote($ $ACTIVEQT_IDL "$ ${ACTIVEQT_OUTPUT}.idl" -nologo -tlb "$ ${ACTIVEQT_TLBOUT}"$ $ACTIVEQT_NEWLINE)  
  9.         message("No rc-file linked into project; type library will be a separate file.")  
  10.     }  
  11.     !qaxserver_no_register: \\  
  12.         QMAKE_POST_LINK += $ $quote($ $ACTIVEQT_IDC $ ${ACTIVEQT_TARGET} -regserver)  
  13.     QMAKE_CLEAN += $ ${ACTIVEQT_OUTPUT}.idl $ ${ACTIVEQT_OUTPUT}.tlb  
  14. }  



 

修改后,再次重新编译(要重新编译才能触发编译后事件),idl 顺利产生。

 

      可是,接着问题又大了,msys2 的工具链里没有 midl.exe。这个工具是windows SDK 的一部分,且需要Visual C++的 cl.exe。先是尝试在PATH里加入路径,但没有成功。除非彻底加入vcvars32.bat的所有设置,否则无法通过。这个问题有办法:

    3. 为Mingw32 环境提供midl.exe支持

      前文书,midl.exe 是 windows SDK中的工具,这个工具依赖Visual C++编译器。然而,在MingW工具链中,默认是无法调用VC编译器的。为了给Mingw32-make创造出一个局部的VC编译环境,新建一个简单的控制台外壳,名字也叫“midl.exe”,在内部调用 vcvars32.bat并把命令行参数传给真正的 midl.exe即可:

pro文件,控制台Qt应用:

 

[plain] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. QT += core  
  2. QT -= gui  
  3.   
  4. CONFIG += c++11  
  5.   
  6. TARGET = midl  
  7. CONFIG += console  
  8. CONFIG -= app_bundle  
  9.   
  10. TEMPLATE = app  
  11.   
  12. SOURCES += main.cpp  

唯一的代码文件,main.cpp:

 

 

[cpp] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. #include <QCoreApplication>  
  2. #include <QString>  
  3. #include <QSettings>  
  4. #include <QDir>  
  5. #include <QProcess>  
  6. #include <QStringList>  
  7. #include <QDebug>  
  8. #include <stdlib.h>  
  9. int main(int argc, char *argv[])  
  10. {  
  11.     QCoreApplication a(argc, argv);  
  12.     QString exeName = a.applicationName();  
  13.     //0. the exe name and ini filename should be  stored together.  
  14.     QString iniFile = a.applicationFilePath() + ".ini";  
  15.     QSettings settings(iniFile,QSettings::IniFormat);  
  16.     //1.get the current directory  
  17.     QString strCurrentDir = QDir::current().absolutePath();  
  18.     //2.get the visual studio vcvars32 path and raw EXE path  
  19.     QString vcvarsPath = settings.value("SETTINGS/VCVARS","D:\\\\Microsoft Visual Studio 10.0\\\\VC\\\\bin\\\\vcvars32.bat")  
  20.             .toString();  
  21.     QString exeDir = settings.value("SETTINGS/EXEDIR","C:\\\\Program Files (x86)\\\\Windows Kits\\\\8.1\\\\bin\\\\x86")  
  22.             .toString();  
  23.     //3.Make the cmd target  
  24.     QString cmd ;  
  25.     //3.1. call vc vars to  
  26.     //  cmd += " && ";  
  27.     cmd += "CALL ";  
  28.     cmd += "\\"" + vcvarsPath + "\\"";  
  29.     //3.2. chdir back to current  
  30.     cmd += " && ";  
  31.     cmd += "CD /D \\"" + strCurrentDir.replace("/","\\\\") + "\\"";  
  32.     //3.3. call exeName with args  
  33.     cmd += " && ";  
  34.     cmd += "\\"" + exeDir + "\\\\" + exeName + "\\" ";  
  35.   
  36.     for(int i=1;i<argc;++i)  
  37.         cmd += argv[i] + QString(" ");  
  38.   
  39.     settings.setValue("SETTINGS/VCVARS",vcvarsPath);  
  40.     settings.setValue("SETTINGS/EXEDIR",exeDir);  
  41.   
  42.     //4. display and exe the cmd  
  43.     puts(cmd.toStdString().c_str());  
  44.     int ret = system(cmd.toStdString().c_str());  
  45.     a.exit(0);  
  46.     return ret;  
  47. }  


默认的VC配置可能和实际的不符合,不要紧,只要在 midl.exe (壳子)同文件夹下设置midl.exe.ini即可:

 

 

[plain] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. [SETTINGS]  
  2. VCVARS=D:\\\\Microsoft Visual Studio 10.0\\\\VC\\\\bin\\\\vcvars32.bat  
  3. EXEDIR=C:\\\\Program Files (x86)\\\\Windows Kits\\\\8.1\\\\bin\\\\x86  

修改这个参数即可。VCVARS即是vc编译器批处理文件的位置,EXEDIR是真的midl.exe的文件夹。

 

4. 试试看!

 二话不说,开始编译,OK!

 

[plain] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. g++ -Wl,-s -shared -Wl,-subsystem,windows -mthreads -Wl,--out-implib,../bin/libqtaxviewer_planetosm.dll.a -Wl,../../qtv.planet/qtviewer_planetosm/qtaxviewer_planetosm.def -o ../bin/qtaxviewer_planetosm.dll object_script.qtaxviewer_planetosm.Release  -lglu32 -lopengl32 -lgdi32 -luser32 -lQt5AxServer -lQt5AxBase -lole32 -loleaut32 -luser32 -lgdi32 -ladvapi32 -luuid -lQt5AxServer -lQt5AxBase -lQt5Widgets -lQt5Gui -lQt5Network -lQt5Core   
  2. /D/msys64/mingw32/bin/idc.exe ../bin/qtaxviewer_planetosm.dll -idl release//qtaxviewer_planetosm.idl -version 1.0  
  3.   
  4. release\\\\qtaxviewer_planetosm.idl  
  5.   
  6. midl release//qtaxviewer_planetosm.idl -nologo -tlb release//qtaxviewer_planetosm.tlb  
  7.   
  8. Setting environment for using Microsoft Visual Studio 2010 x86 tools.  
  9. Processing release\\\\qtaxviewer_planetosm.idl  
  10. qtaxviewer_planetosm.idl  
  11. Processing C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v7.0A\\include\\ocidl.idl  
  12. ocidl.idl  
  13. Processing C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v7.0A\\include\\oleidl.idl  
  14. oleidl.idl  
  15. Processing C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v7.0A\\include\\objidl.idl  
  16. objidl.idl  
  17. Processing C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v7.0A\\include\\unknwn.idl  
  18. unknwn.idl  
  19. Processing C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v7.0A\\include\\wtypes.idl  
  20. wtypes.idl  
  21. Processing C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v7.0A\\include\\basetsd.h  
  22. basetsd.h  
  23. Processing C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v7.0A\\include\\guiddef.h  
  24. guiddef.h  
  25. Processing C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v7.0A\\include\\oaidl.idl  
  26. oaidl.idl  
  27. Processing C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v7.0A\\include\\servprov.idl  
  28. servprov.idl  
  29. Processing C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v7.0A\\include\\urlmon.idl  
  30. urlmon.idl  
  31. Processing C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v7.0A\\include\\msxml.idl  
  32. msxml.idl  
  33. Processing C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v7.0A\\include\\oaidl.acf  
  34. oaidl.acf  
  35. Processing C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v7.0A\\include\\ocidl.acf  
  36. ocidl.acf  
  37. CALL "D:\\Microsoft Visual Studio 10.0\\VC\\bin\\vcvars32.bat" && CD /D "D:\\documents\\Qt\\build-qplanetosm-Desktop_Qt_MinGW_w64_32bit_MSYS2-Release\\qtviewer_planetosm" && "C:\\Program Files (x86)\\Windows Kits\\8.1\\bin\\x86\\midl" release//qtaxviewer_planetosm.idl -nologo -tlb release//qtaxviewer_planetosm.tlb   
  38. /D/msys64/mingw32/bin/idc.exe ../bin/qtaxviewer_planetosm.dll -tlb release//qtaxviewer_planetosm.tlb  
  39. Type library attached to D:\\documents\\Qt\\build-qplanetosm-Desktop_Qt_MinGW_w64_32bit_MSYS2-Release\\bin\\qtaxviewer_planetosm.dll.  
  40. /D/msys64/mingw32/bin/idc.exe ../bin/qtaxviewer_planetosm.dll -regserver  
  41. Server registered successfully!  
  42. mingw32-make[2]: Leaving directory \'D:/documents/Qt/build-qplanetosm-Desktop_Qt_MinGW_w64_32bit_MSYS2-Release/qtviewer_planetosm\'  
  43. mingw32-make[1]: Leaving directory \'D:/documents/Qt/build-qplanetosm-Desktop_Qt_MinGW_w64_32bit_MSYS2-Release/qtviewer_planetosm\'  
  44. 09:57:52: 进程"D:\\msys64\\mingw32\\bin\\mingw32-make.exe"正常退出。  
  45. 09:57:52: Elapsed time: 01:26.  


 

http://blog.csdn.net/goldenhawking/article/details/51125604

以上是关于迁移到MSYS2 与 Qt 工具链注意的几个事情(注意链接顺序,并且人造mingw工具链所没有的局部midl.exe命令)的主要内容,如果未能解决你的问题,请参考以下文章

MSYS2 - 安装 gcc 或工具链?

Qt 多线程与数据库操作需要注意的几点问题

Qt 多线程与数据库操作需要注意的几点问题(QSqlDatabase对象只能在当前线程里使用)

MSYS2工具链方便快捷的安装方法

编译工具链,生成各个平台的ffmpeg版本的库

Qt学习虚拟机--基于MSYS2-MinGW环境并带有各种开源的软件库!