拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Telegram Desktop 源码编译实战:QT 5.3.1 与 MSVC 工具链全解析

Telegram Desktop 源码编译实战:QT 5.3.1 与 MSVC 工具链全解析 简介这是一份Telegram开源IM在Windows环境下的编译实战记录主要面向有一定C基础、尝试自行编译Telegram桌面版或QT5.3.1的开发者。作者基于VS2013和tdesktop官方MSVC指南完整记录了从环境准备、OpenSSL/LZMA/zlib/libexif等依赖搭建到Telegram源码编译中各类典型错误的定位与处理并单独整理了QT5.3.1的编译过程包括Perl/Python/Ruby环境配置、ICU可选安装、VS2013开发人员命令提示下的configure与nmake参数等。整份资源为1个doc文档压缩包仅29KB内容高度浓缩适合作为编译Telegram/QT时快速查阅的排错手册。目前已有569人学习下载。文档中对openssl头文件路径错误、Qt5Widgets.lib缺失、libeay32MT.lib链接失败等高频问题给出了具体修改方法和命令示例能帮助读者少走弯路。1. 从源码编译 Telegram Desktop为什么非要碰 QT 5.3.1Telegram Desktop 的官方预编译包能满足日常使用但当你需要定制客户端、修改 UI 逻辑、或者想在离线内网环境部署时从源码编译就成了绕不开的路径。更麻烦的是Telegram Desktop 的历史版本和 QT 5.3.1 绑定得很死——新版 Qt 的接口变化会让老代码直接编译失败。我拆这个项目时踩了十几个坑从 MSVC 工具链到 qscintilla 静态库每一步都有值得记录的细节。这篇笔记直接给你可复现的完整流程包括 configure 参数、jom 并行编译设置、以及cannot find -lpublic这类高频报错的定位思路。如果你正准备在自己的机器上完整编译一遍 Telegram Desktop尤其是用 QT 5.3.1 这个老版本这篇就是给你写的。2. 环境准备与工具链选型先把三种“编译器”的账算清2.1 MSVC vs MinGWQT 5.3.1 的兼容性真相Telegram Desktop 官方推荐的编译环境是 MSVCMicrosoft Visual C而不是很多人习惯的 MinGW。原因很直接QT 5.3.1 时代的 Windows 版本对 MinGW 的支持不完整Telegram 源码里大量使用了windows.h底层 API 和 MSVC 特有的#pragma指令MinGW 的 GCC 解释不了这些代码。我见过有人硬用 MinGW 编 Telegram最后在链接阶段遇到几百个未解析符号那个排查过程非常痛苦。正确做法是安装 Visual Studio 2013 或 2015 的社区版——注意版本的匹配。Telegram Desktop 在 QT 5.3.1 分支时官方测试环境是 VS2013用 VS2015 也能编但 VS2017 以上的工具链会对老代码里的某些类型转换报错因为std::auto_ptr被彻底移除了。如果你只有 VS2019 或 VS2022也不是完全没救需要额外做一件事安装“单个组件”里的Windows 7 SDK和MSVC v120 工具集VS2013 的编译器核心。没有这个QT 5.3.1 的qmake生成的 Makefile 里的-GL-参数会直接报错。提示MSVC 工具链和 MinGW 的区别不只在编译速度最重要的是 ABI应用二进制接口不同。QT 库如果用的是 MSVC 编译的你的业务代码也必须用 MSVC混着链接会出LNK2038这类 mismatch 错误。2.2 源码获取Telegram 仓库的完整克隆方式Telegram Desktop 的源码在 GitHub 上仓库地址是telegramdesktop/tdesktop。因为项目体积很大超过 2GB加上子模块众多直接git clone经常会中断。常见做法是先用--depth1做浅克隆再拉子模块。git clone --depth1 --branch v1.0.0 https://github.com/telegramdesktop/tdesktop.git cd tdesktop git submodule init git submodule update --depth1这段命令的逻辑是--depth1只拉最新的一次提交大幅减少传输量--branch v1.0.0指定了你要编译的分支——如果你要编 QT 5.3.1 版本需要切到对应历史分支比如v0.9.6或v1.0.0。git submodule update会把 Telegram 依赖的第三方库如libtgvoip、ffmpeg、qscintilla等拉下来。这里有个重点子模块必须拉全否则编译到一半会报fatal error: libtgvoip/Media.h file not found之类的头文件缺失错误。检查子模块是否完整的命令是ls telgui/ThirdParty/正常情况下你应该看到libtgvoip、ffmpeg、qscintilla、catch等目录都在。缺哪个就单独初始化哪个比如缺 qscintilla 就执行git submodule update --init --recursive telgui/ThirdParty/qscintilla。2.3 依赖库清单QT 5.3.1 之外还需要什么Telegram Desktop 的依赖库比想象中多QT 只是其中一块。核心依赖包括依赖库用途获取方式QT 5.3.1主界面框架、网络、事件循环官方源码编译或预编译包qscintilla代码编辑器控件用于 Telegram 的代码高亮源码编译注意必须与 QT 同版本libtgvoipVoIP 语音通话子模块拉取ffmpeg音视频编解码子模块拉取如果不需要语音和视频可以禁用OpenSSL加密协议系统自带或另行编译其中最容易出问题的是 qscintilla。它本身是个独立的 QT 控件库Telegram 的TelegramMessenger里用它实现消息代码块的语法高亮。qscintilla 的编译必须和 QT 5.3.1 严格同版本否则会出现 slots 信号连接失败——这个报错在运行时才暴露编译期是看不出来的。另外如果你不需要语音通话编译时可以加TDESKTOP_DISABLE_TGVOIP1这个开关省掉 libtgvoip 的编译时间。我一般会禁用因为语音通话模块依赖的 WebRTC 编译复杂度很高动不动就要 40 分钟起步。3. QT 5.3.1 完整编译configure 参数与 qscintilla 联动3.1 configure 参数怎么给静态链接的关键配置QT 5.3.1 的编译是整个流程里耗时最长的环节用默认参数编一次大约 2 小时所以 configure 参数必须一次给对。我实际使用的参数组合是这样的cd qt-5.3.1 configure.bat -prefix D:\Qt\5.3.1\msvc2013 -opensource -confirm-license -debug-and-release -static -opengl desktop -no-openssl -no-icu -no-angle -nomake tests -nomake examples -mp逐个拆解这些参数的含义-prefix指定安装路径务必放在空间充足的盘QT 编译后占用约 5GB。-debug-and-release同时生成调试版和发布版。Telegram 的 qmake 文件里默认两个版本都会用省掉后面再次配置的麻烦。-static是关键——Telegram Desktop 默认要求静态链接 QT因为官方发布的 Windows 版就是这样打包的动态链接反而需要额外拷贝大量 dll。-no-openssl在 configure 阶段跳过 OpenSSL 检测Telegram 会自己处理加密库这能避免 QT 的 OpenSSL 版本和系统版本冲突。-no-angle很重要。ANGLE 是 QT 用来把 OpenGL ES 翻译成 DirectX 的库Telegram 不需要它而 ANGLE 编译极慢去掉能省 20 分钟。-mp开启多处理器编译配合后面的jom使用否则单线程编译 QT 是灾难。configure 执行完后会生成Makefile然后跑编译jom -j8 jom install第一条命令里的-j8表示 8 个并行任务。你要根据 CPU 核心数调整一般-j4到-j16之间。如果内存只有 8GB建议-j4因为并行编译每个任务会吃 700MB 左右内存8 个任务可能直接爆内存导致编译进程被系统杀掉。3.2 编译失败时怎么看jom 输出与日志定位jom 编译失败是常态关键是学会快读日志。QT 编译报错的常见形式有两种Error 1 (for counter) : cl开头——这是真正的 MSVC 编译错误说明某个 C 源文件编译不过。NMAKE : fatal error U1077—— 这是依赖错误通常是因为上一个文件没有正确生成导致链接阶段缺文件。处理策略就一条先修第一个报错不要往下翻。因为后续错误大概率是同一个原因导致的连锁反应。比如qtbase编译时报cannot open input file qtmain.lib这时候要检查是不是qtmain这个子项目还没 build 完——顺序乱了。QT 5.3.1 在 Windows 上编译时的“黄金顺序”是configure生成后手动构建qtbase这个子模块因为它是其他所有模块如qtscript、qtsvg的基础。命令行单独构建cd qtbase jom -j8 cd ..如果qtbase顺利通过剩下的模块基本不会有大问题。3.3 qscintilla 下载与编译必须手动干预的一步qscintilla 是个独立的库不跟随 QT 的 configure 流程。Telegram 的源码里虽然包含了 qscintilla 子模块但它的 build 文件需要单独执行。这个库的编译极其挑剔网上很多人在这里翻车。先看源码目录结构cd telgui/ThirdParty/qscintilla这个目录下有Qt4Qt5子目录里面有qscintilla.pro文件。进入这个目录执行cd Qt4Qt5 D:\Qt\5.3.1\msvc2013\bin\qmake.exe qscintilla.pro -spec win32-msvc2013 jom -j8如果你用的是 VS2015 工具链把-spec win32-msvc2013换成win32-msvc2015。这一步非常容易出错的地方是qmake 中间不能有空格或者中文路径。D:\Qt\5.3.1\msvc2013这个路径中如果出现中文qscintilla 的.vcxproj文件生成会失败报一堆Cannot find file的诡异错误。编译完成后把生成的qscintilla2.lib和头文件复制到 QT 的 lib 和 include 目录copy Qt4Qt5\release\qscintilla2.lib D:\Qt\5.3.1\msvc2013\lib\ copy Qt4Qt5\Qsci\qsciscintilla.h D:\Qt\5.3.1\msvc2013\include\注意qscintilla 是 LGPL 协议静态链接进 Telegram 后如果你不打算开源自己的改动需要仔细确认一下合规要求。这里只提编译技术问题不展开法律细节。4. Telegram Desktop 主程序编译qmake、jom 与生成目录4.1 生成主工程 Makefile两个关键文件缺一不可QT 编译完毕、qscintilla 就位之后才轮到 Telegram 主工程。项目根目录下的Telegram文件夹里有Telegram.pro文件需要先手动指定 qmake 路径cd Telegram D:\Qt\5.3.1\msvc2013\bin\qmake.exe Telegram.pro -spec win32-msvc2013 CONFIGdebug_and_release这一步的坑在于CONFIGdebug_and_release必须加不加的话后面编译会报debug\...obj : fatal error LNK1181: cannot open input file release\...obj——它试图链接一个不存在的 release 目录下的文件。qmake 成功执行后会生成Makefile和Makefile.Release两个文件。老手习惯直接打开Makefile.Release看编译选项——如果里面DEFINES那行没有TDESKTOP_DISABLE_CRASH_REPORTS和TDESKTOP_DISABLE_AUTOUPDATE建议手动加上。这两个宏分别关闭崩溃上报和自动更新纯本地编译时开着它们会额外引入网络请求逻辑反而让程序启动变慢。4.2 主程序编译jom 并行与内存调优Telegram 主工程的编译同样用 jom但这个项目的并发度不能贪高。Telegram 的代码里包含大量模板类特别是Streaming模块单个编译单元内存消耗极大-j8在 Telegram 主工程上实测容易把 16GB 内存吃满后触发 OOM。jom -j4如果内存足够32GB 以上可以尝试-j6内存 8GB 的机器老老实实-j2虽然慢但至少不会中途崩。编译时间上-j4环境下大概 1 小时左右跑完。编译过程中最常见的一道坎是fatal error C1060: compiler is out of heap space这是 MSVC 编译器自己内存不足的表现不是你系统内存不足。解决方法是把cl.exe的/Zm参数调大在 qmake 的QMAKE_CXXFLAGS里追加/Zm800。这个参数是给编译器预留更多预编译头文件内存的800 是一个比较安全的数值。4.3 编译产物路径与验证拿到 Telegram.exe 只是第一步编译完成后可执行文件在Telegram\Release\Telegram.exe。但别急着双击运行——这个 exe 还缺Telegram\Resources目录下的资源文件图标、语言包、字体等。如果不拷贝资源目录程序启动后界面是空白的或者直接闪退。复制资源的命令xcopy /E /I Telegram\Resources Telegram\Release\Resources拷完之后运行 Telegram.exe如果一切正常会弹出登录界面。这时候注意一个细节Telegram 首次启动会向官方服务器请求配置如果你的机器在国内网络环境下这个请求可能会超时。这不是你编译的问题是网络环境问题换个方式处理即可。另外Release 目录下除了 Telegram.exe还会看到Telegram.obj和一堆.pdb文件。.pdb是调试符号文件如果是自己本地编译建议保留但如果你要分发这个 exe.pdb会暴露源码路径信息不介意的话可以删掉。4.4 快速验证编译配置是否生效编译完之后验证你的自定义配置是否真的编进去了可以用这个命令strings Telegram.exe | findstr TDESKTOP_DISABLE_CRASH_REPORTS如果输出里有1或者宏名说明编译配置生效了。注意strings是 GNU 工具Windows 上可以装个sysinternals的替代品或者直接用find命令搜二进制里的文本。这个方法在排查“我明明改了配置为什么编译出的 exe 没变化”这种问题时非常实用。5. 编译避坑指南五条高频报错的定位与修复5.1 报错cannot find -lpublicQT 库路径没配对现象链接阶段报LINK : fatal error LNK1181: cannot open input file public.lib或者 GCC 系的cannot find -lpublic。原因qmake 生成的 Makefile 中LIBS变量引用了名为public的库源自代码里的QT public或类似的错误拼写但你的 QT 库里根本没有public.lib。这个问题的本质是 Telegram 的老代码里有一处对QtPlatformHeaders的错误引用。解决修改Telegram.pro文件把QT public删除或者改成QT gui。改完后重新执行 qmake不要只重新跑 jom——因为 Makefile 不会自动感知.pro文件的变化。一定要先删掉旧的 Makefile 再重新 qmakedel Makefile Makefile.Release qmake.exe Telegram.pro -spec win32-msvc2013 jom -j45.2 qscintilla 编译后链接报错版本不一致的无声失败现象Telegram 主程序链接时报unresolved external symbol public: virtual struct QMetaObject const * __thiscall QsciScintilla::metaObject(void)const之类的错误。原因qscintilla 编译时用的 QT 版本和 Telegram 主程序编译时用的 QT 版本不一致。最常见的情况是你机器上原来装过另一个版本的 QT比如 5.12qmake 时误用了旧版本的qmake.exe导致 qscintilla 的 moc 文件基于 5.12 生成但链接时用的 QT 5.3.1 的头文件布局对不上。解决检查 qscintilla 的 Makefile 里QTDIR变量指向哪里。确保D:\Qt\5.3.1\msvc2013\bin\qmake.exe在你的 PATH 最前面。再彻底一点的做法是清掉 qscintilla 的 build 缓存重编cd telgui/ThirdParty/qscintilla/Qt4Qt5 del Makefile* *debug *release /s /q然后重新 qmake、重新 jom。这件事没有捷径只能重来。5.3 编译中内存不足C1060玄学但可解的编译器堆问题现象fatal error C1060: compiler is out of heap space而且每次报错的代码文件都不一样看起来像是随机崩溃。原因MSVC 编译器在编译大量使用模板的现代 C 代码时预编译头PCH缓存占用会膨胀。这跟系统内存大小没有直接关系更像编译器内部堆的分配策略问题。解决在.pro文件里添加QMAKE_CXXFLAGS /Zm800这个参数把编译器的预编译头内存上限从默认值调高。如果还不行再把/MP多进程编译关掉——/MP会启动多个 cl.exe 实例每个实例各自维护堆总内存消耗成倍增加。QMAKE_CXXFLAGS /Zm800 /MP1/MP1是强制单进程编译虽然慢一点但稳。我用这个方法解决了十几台机器上的相同报错。5.4 编译产物能跑但界面空白资源文件缺失的迷局现象Telegram.exe能启动进程也在后台但窗口一片白色没有任何响应。原因缺少Resources目录下的样式表.tdesktop文件和图标资源。Telegram 的程序架构里所有 UI 资源都是运行时从Resources目录加载的而不是编译进 exe。这个设计初看很蠢但它是为了让设计资源能独立更新。解决从源码目录的Telegram\Resources完整拷贝到Release目录注意Resources下还有一个qrc子目录里面是字体文件不能漏拷贝。完成后目录结构应该是Release/ Telegram.exe Resources/ default.tdesktop icon.ico qrc/ font.ttf5.5LNK2038 mismatch detected for RuntimeLibraryMT 和 MD 之争现象编译到最后一个链接阶段报LNK2038: mismatch detected for RuntimeLibrary: value MD_DynamicRelease doesnt match value MT_StaticRelease。原因你的某个依赖库比如 qscintillarelease版本是用动态运行时/MD编译的但 Telegram 主工程用静态运行时/MT编译。Windows 不允许混合链接这两种运行时的目标文件。解决明确统一策略。如果主工程用/MT静态运行时则 qscintilla 也必须用/MT重新编。qscintilla 的qscintilla.pro里追加一行QMAKE_CXXFLAGS_RELEASE /MT然后重新编译 qscintilla。反过来如果主工程用/MD那在 Telegram.pro 里设QMAKE_CXXFLAGS_RELEASE /MD。关键是全项目一个标准不能混。6. 进阶验证与产物检查编译结果到底能不能直接分发6.1 用 dumpbin 检查 DLL 依赖链本地编译的Telegram.exe能不能在其他机器上运行关键看依赖链是否完整。用 MSVC 自带的 dumpbin 工具检查dumpbin /dependents Telegram.exe输出里会出现一长串 DLL 列表。其中值得关注的是Qt5Core.dll、Qt5Gui.dll、Qt5Widgets.dll这几项——如果你用的是-static编译的 QT这些 DLL 不应该出现在依赖列表里。如果出现了说明你的静态编译配置没生效通常是-static参数没被 qmake 读到这个 exe 拷到别的机器就会因缺 DLL 跑不起来。另外注意看有没有libgcc_s_seh-1.dll或libstdc-6.dll——出现这两个基本上可以判定你混入了 MinGW 编译的目标文件这个 exe 在纯净 Windows 环境一定缺 DLL。6.2 版本号与数字签名的修改编译出来的 Telegram.exe 默认版本号是源码分支的版本比如 1.0.0。如果你准备分发到公司内部或者自定义品牌需要改.rc资源文件里的版本信息。Telegram 的版本号定义在Telegram/Resources/telegram.rc里#define VERSION_MAJOR 1 #define VERSION_MINOR 0 #define VERSION_PATCH 0修改后需要重新编译才生效因为.rc文件是编译期嵌入 exe 的资源。这一步注意编码格式——.rc文件必须是 UTF-16 LE 编码否则rc.exe会报资源解析错误。数字签名这块如果只是内部使用可以不签。但要跨机器分发Windows SmartScreen 会因为无签名弹红窗警告。条件够的话用自签名证书签一下也行代码signtool sign /fd SHA256 /f mycert.pfx /p yourpassword Telegram.exe注意自签名证书依然会触发 SmartScreen 警告只是少一点威胁提示。6.3 环境变量隔离避免老 QT 残留的坑编译后的 Telegram.exe 启动时会先找同目录下的Qt5Core.dll如果用的是动态链接。但 Windows DLL 搜索顺序是优先系统目录的如果另一套 QT比如 5.12的 DLL 路径在你的系统 PATH 里可能出现“加载了错误的 Qt5Core.dll”导致运行崩溃。一个简单的验证方法设置环境变量QT_DEBUG_PLUGINS1后启动 Telegram.exe观察输出内容。set QT_DEBUG_PLUGINS1 Telegram.exe输出里会打印实际加载的 QT 插件路径。如果指向的不是你的编译目录D:\Qt\5.3.1\msvc2013\plugins说明 PATH 污染。这时候把 Telegram.exe 所在的目录拷贝到一个干净的临时目录单独运行问题通常就消失了。6.4 关于低配机器编译的最后提醒如果你用了-j8编译时内存吃满直接黑屏死机不要以为是硬件问题。这是 jom 并行任务把内存条榨干了Windows 直接触发 OOM killer。从那以后我每次编译 Telegram 都会做三件事打开任务管理器看内存占用、把 jom 并发数压到内存允许的下限、再设置页面文件至少 16GB。这个习惯救了我至少三次每次都能避免编译到 70% 时系统崩溃前功尽弃。希望这篇编译笔记帮到你也祝你在踩坑路上少走点弯路。本文还有配套的精品资源点击获取
返回列表