编译大型项目源码这件事情,你要是没有搞过,肯定觉得多少都有些难度,但是你一旦实践过,你就会在心里有个大概。所以不要有抵触情绪,动手去实践。
从我实践的经验来看,核心就是一点:环境的配置。如何做到环境的最优配置,不污染其他的环境才是核心,还要注意配置信息的输出。
一个大型项目,代码基本上没有问题的。如果在编译过程的出现一些非常低级的编译错误,我觉得极大的可能性环境配置有问题。
比如,我在编译过程出现的问题:
D:/qt/qt-everywhere-src-6.2.2/qtbase/src/corelib/text/qstringconverter.h:188:87: internal compiler error: in make_rtl_for_nonlocal_decl, at cp/decl.c:6590
Q_CORE_EXPORT static const Interface encodingInterfaces[Encoding::LastEncoding + 1];
上面的这个错误,我花了很长时间去排查。得出的结论是:gcc 8.3版本不支持这种写法,升级gcc版本就行了。
那么我是windows版本怎么升级gcc呢,我去google了,没有找到解决方案。
后来没有办法我手动修改了源码,咋修改的我现在忘记了。总之编译过去了,为此我还沾沾自喜呢。
后来我有遇到一个错误,真的束手无策
tst_graphicshelpergl3_2.cpp.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) public: __thiscall Qt3DRender::Render::OpenGL::ShaderUniform::ShaderUniform(void)" (__imp_??0ShaderUniform@OpenGL@Render@Qt3DRender@@QAE@XZ) referenced in function "private: void __thiscall tst_GraphicsHelperGL3_2::uniformsByteSize(void)" (?uniformsByteSize@tst_GraphicsHelperGL3_2@@AAEXXZ)
tst_graphicshelpergl3_2.cpp.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) public: __thiscall Qt3DRender::Render::OpenGL::ShaderUniform::~ShaderUniform(void)" (__imp_??1ShaderUniform@OpenGL@Render@Qt3DRender@@QAE@XZ) referenced in function "struct Qt3DRender::Render::OpenGL::ShaderUniform * __cdecl std::_Insertion_sort_unchecked >(struct Qt3DRender::Render::OpenGL::ShaderUniform * const,struct Qt3DRender::Render::OpenGL::ShaderUniform * const,class )" (??$_Insertion_sort_unchecked@PAUShaderUniform@OpenGL@Render@Qt3DRender@@V@@@std@@YAPAUShaderUniform@OpenGL@Render@Qt3DRender@@QAU1234@0V@@@Z)
tst_graphicshelpergl3_2.cpp.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) public: __thiscall Qt3DRender::Render::OpenGL::ShaderUniform::ShaderUniform(struct Qt3DRender::Render::OpenGL::ShaderUniform const &)" (__imp_??0ShaderUniform@OpenGL@Render@Qt3DRender@@QAE@ABU0123@@Z) referenced in function "private: void __thiscall tst_GraphicsHelperGL3_2::programUniformsAndLocations(void)" (?programUniformsAndLocations@tst_GraphicsHelperGL3_2@@AAEXXZ)
各种链接错误,这我真的很头大。
我开始反思……,可能不是代码的问题,而是我的问题。我重新执行了configure.bat,看到一个很重要的信息。居然看到了make指定了gcc作为编译器。
我就很纳闷了,我不是初始化了vs2019编译器的环境,为什么还是用gcc呢,真是日了狗。到这里我才意识到我的环境有点问题,但是距离刚开始编译Qt源码已经过了2天。
我开始去排查环境问题,最后还是发现问题在我这里。我在指定perl的目录时候,多指定了一个bin目录,这个目录下就包含了gcc.exe。
所以:编译环境很重要
注意:先不要编译QDoc,因为从官方的文档上面看编译QDoc用的是Clang编译器。
Qt 6.2.2源码地址
cmake工具
perl工具
ninja
vs2019 Enterprise
上面的这几个工具都需要去国外的网站下载,为了方便大家,我直接下载了放到百度网盘上了。
链接: https://pan.baidu.com/s/1x0NIuLz73q3cIZcBZlkswQ
Qt的源码地址,我们可以直接清华的源就可以了。
https://mirrors.tuna.tsinghua.edu.cn/qt/official_releases/qt/6.2/6.2.2/single/
REM 找到你的vs2019初始化环境的bat目录,我用的enterprise版本,不用的版本只需要替换下面的"Enterprise"就可以了
CALL "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x86
SET _ROOT=D:\qt\qt-6.2.2
SET PATH=D:\soft_dev\build_qt_devs\cmake-3.22.0\bin;%PATH%
SET PATH=%_ROOT%\qtbase\bin;%PATH%
SET PATH=D:\soft_dev\build_qt_devs\strawberry-perl-5.32.1.1\perl\bin;%PATH%
SET PATH=D:\soft_dev\build_qt_devs\ninja-win;%PATH%
set "MY_INSTALL_PATH=D:\qt\qt-6.2.2\bin"
configure.bat -prefix %MY_INSTALL_PATH% -DQT_NO_EXCEPTIONS=1 -debug-and-release -force-debug-info -platform win32-msvc -opensource -confirm-license -opengl es2
把上面代码copy出来放到bat文件里面,打开cmd命令行,在命令行里面执行bat文件
在初始化环境变量的时候,我把所有的用到的软件都放到一个目录下,就是为了好管理,而且cmd窗口退出之后,不会影响我系统原来的环境变量。
我解释下上面用的编译参数:默认是动态编译
命令 | 含义 |
---|---|
QT_NO_EXCEPTIONS | 宏开关,关闭Qt异常 |
-debug-and-release | 编译debug和release版本 |
-force-debug-info | 为release版本创建符号信息 |
-platform win32-msvc | win32-msvc 平台 |
-opensource -confirm-license | 编译的时候开源版本 |
-opengl es2 | 支持ES2 API的opengl |
-prefix %MY_INSTALL_PATH% | 编译完成之后,执行 cmake insall 自动复制到MY_INSTALL_PATH目录下 |
在初始化上面的环境之后,你可以执行.\configure --help
,就可以查到更多的选项信息,我建议你看一遍。
在命令行中执行bat文件的时候一定要仔细观察输出的信息,这是其中的一段:这里面包含了编译器的版本。我之前就是坑在这里。
-- CMAKE_VERSION: "3.22.0"
-- CMAKE_HOST_SYSTEM: "Windows-10.0.19042"
-- CMAKE_HOST_SYSTEM_NAME: "Windows"
-- CMAKE_HOST_SYSTEM_VERSION: "10.0.19042"
-- CMAKE_HOST_SYSTEM_PROCESSOR: "AMD64"
-- CMAKE_SYSTEM: "Windows"
-- CMAKE_SYSTEM_NAME: "Windows"
-- CMAKE_SYSTEM_VERSION: "10.0.19042"
-- CMAKE_SYSTEM_PROCESSOR: "AMD64"
-- CMAKE_CROSSCOMPILING: "FALSE"
-- CMAKE_C_COMPILER: "C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Tools/MSVC/14.28.29910/bin/Hostx86/x86/cl.exe" (19.28.29920.0)
-- CMAKE_CXX_COMPILER: "C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Tools/MSVC/14.28.29910/bin/Hostx86/x86/cl.exe" (19.28.29920.0)
-- MSVC_VERSION: "1928"
-- MSVC_TOOLSET_VERSION: "142"
再看看最后的提示信息
WARNING: QDoc will not be compiled, probably because libclang could not be located. This means that you cannot build the Qt documentation.
Either set CMAKE_PREFIX_PATH or LLVM_INSTALL_DIR to the location of your llvm installation.
On Linux systems, you may be able to install libclang by installing the libclang-dev or libclang-devel package, depending on your distribution.
On macOS, y-- Configuring incomplete, errors occurred!
ou can use Homebrew's llvm package.
You will also need to set the FEATURE_clang CMake variable to ON to re-evaluate this check.
WARNING: Clang-based lupdate parser will not be available. LLVM and Clang C++ libraries have not been found.
You will need to set the FEATURE_clangcpp CMake variable to ON to re-evaluate this check.
WARNING: QtWebEngine won't be built. node.js version 10.19 or later is required.
WARNING: QtPdf won't be built. node.js version 10.19 or later is required.
Qt is now configured for building. Just run 'cmake --build . --parallel'
Once everything is built, you must run 'cmake --install .'
Qt will be installed into 'D:/qt/qt-6.2.2/bin'
To configure and build other Qt modules, you can use the following convenience script:
D:/qt/qt-6.2.2/bin/bin/qt-configure-module.bat
If reconfiguration fails for some reason, try to remove 'CMakeCache.txt' from the build directory
这里的信息需要仔细看,提示几点内容
我感觉到这里,编译应该没什么问题。
编译过程遇到的环境配置是一大难关,我在刚开始的时候就做了着重的介绍,希望能够引起大家的重视。
我再说说其他的问题,也是折腾了我很久时间。
大家看到我在上面设置环境变量时候都是分开设置是吧。如果你放在一起设置,会报错:输入行太长,命令语法不正确。
关键这个错你如果是放到bat文件去执行,它是没有这个错误信息的。
而我也是偶然发现的,因为开了很多个cmd命令行窗口,有时候直接复制代码来得快。才发现这个错误。
我先给出结论:不要浪费时间编译MT和MTd格式
Qt默认的就是MDd(debug版本)和MD(release版本)编译,我编译完成之后。就立马结合libcef做个测试。
结果发现libcef使用的MTd和MT方式编译的。
一编译,就发现链接的问题:
检测到“RuntimeLibrary”的不匹配项: 值“MT_StaticDebug”不匹配值“MD_DynamicDebug”
我心想着libcef我用的是官方编译好二进制文件,我已经不能修改了。所以只好回过头重新以MT和MTd方式编译Qt。
然后,我又去分析了好久,cmake到底在哪里指定了MDd和MD的编译选项。最后我找到了build.ninja里面找到了已经指定的编译选项,我手动将MDd修改MTd,将MD修改MT。我还花了一点时间去分析这个build.ninja怎么生成的,哎……没有找出头绪,我放弃了。因为我是想直接从源头修改,而不是这个生成的文件。
编译了2个小时还是挺顺利的,但问题还是来了。在调用那个翻译的exe时候,就直接报出:
Error:
Expression: __acrt_first_block == header
我查了资料,也有在Qt的论坛提出相同的疑问,为什么不用MT mode编译Qt。其中有一个回答就是:MD mode对内存管理更方便。
对于MT和MD的信息,大家可以看这篇文章https://blog.csdn.net/weixin_43744293/article/details/117367119
我觉得用一句话概括:他们对内存的管理方式不同,MT必须那个模块申请那就必须由那个模块来释放,MD就是统一管理。用MT模式,一旦出现驴头不对马嘴(这个模块申请内存,其他模块释放内存),就会报错。而MD就是一套管理内存,不存在跨模块申请和释放内存问题。
还是那句话,环境很重要。
我台式机器性能不差,只编译了debug版本,花了大概有3个小时左右。我建议大家在编译的时候先编译debug,后面在空余时间编译release。
最后要准备大一点硬盘。我这边编译的时候,一共花了78.2G,这中间包含我各种编译失败的垃圾文件。