QGIS3.28编译:使用Qt5.14.2 + VS2017
公司SDK环境基于Qt 5.14.2,而QGIS各二进制发布版本中没有可兼容版本。尝试采用Qt 5.14.2 + VS 2017 Enterprise + QGIS 3.28.4 Firenze(32804)进行编译。
编译步骤参考:
官方:https://github.com/qgis/QGIS/blob/master/INSTALL.md#41-building-with-microsoft-visual-studio
国内博客:
https://www.cnblogs.com/m-zhang-yang/p/14694147.html
https://www.cnblogs.com/superbi/p/11188145.html
配置依赖环境
-
安装CMake:https://github.com/Kitware/CMake/releases/download/v3.26.3/cmake-3.26.3-windows-x86_64.msi,在GitHub的官方说明文档上,提供的链接式3.12版本的cmake,但是在使用过程中可能会遇到不少问题,像某些命令不支持等等,建议用更新版本的。
-
安装Cygwin:https://cygwin.com/setup-x86_64.exe,安装时需注意添加
bison
、flex
、git
三个工具 -
安装OSGeo4W:https://download.osgeo.org/osgeo4w/v2/osgeo4w-setup.exe,安装时注意选择
Advanced Install
,并添加qgis-dev-deps
模块 -
下载ninja:https://github.com/ninja-build/ninja/releases/download/v1.7.2/ninja-win.zip,下载后解压,将
ninja.exe
放到OSGeo4W64/bin/
目录下 -
把Qt 5.14.2的相关文件拷贝一份出来:OSGeo4W安装后在app目录下自带了Qt5文件夹,但是它的Qt版本是5.15.3,为避免干扰其他项目,将之前安装过的5.14.2文件复制出来一份。
C:/Qt/Qt5.14.2/5.14.2/msvc2017_64/
下的子文件夹->D:/Programs/OSGeo4W/Qt5.14.2/
-
下载Qt5WebKit,Qt 5.6以后版本中,移除了Qt5WebKit组件,可在GitHub中下载:https://github.com/qtwebkit/qtwebkit/releases/download/qtwebkit-5.212.0-alpha4/qtwebkit-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z,下载解压后,将其中文件拷贝到文件夹中。这里下载得到的Qt5WebKit版本是5.212.0,与自带的版本一致,但是在对qgis进行cmake时遇到版本不符。在cmake时有WITH_QTWEBKIT
选项,取消勾选,可以避开这个组件。 -
配置PkgConfig:PkgConfig本为Linux的软件包,qca、qtkeychain、qgis这几个的编译都用到,这里需要下载windows的版本,有网友遇到pkg-config还需要依赖gettext和glib两个库,我没有做测试,全都下载后放到一起了。
下载pkg-config:https://mirror.ossplanet.net/gnome/binaries/win32/dependencies/pkg-config_0.26-1_win32.zip
下载gettext:https://mirror.ossplanet.net/gnome/binaries/win32/dependencies/gettext-runtime_0.18.1.1-2_win32.zip
下载glib:https://mirror.ossplanet.net/gnome/binaries/win32/glib/2.28/glib_2.28.8-1_win32.zip
将
glib_2.28.8-1_win32\bin\libglib-2.0-0.dll
和gettext-runtime_0.18.1.1-2_win32\bin\intl.dll
文件复制到pkg-config_0.26-1_win32\bin
目录下。 -
安装docygen:https://www.doxygen.nl/files/doxygen-1.9.6-setup.exe,在编译qca时遇到
-
安装openssl:https://slproweb.com/download/Win64OpenSSL-3_0_8.exe,在编译qca时需要
编译qtkeychain
下载QtKeychain源代码:https://kgithub.com/frankosterfeld/qtkeychain/archive/refs/heads/master.zip
打开VS 2017的命令行(使用此命令行可以省去设置VS2017的环境变量的麻烦),
输入命令:
set PATH=%PATH%;C:/Qt/Qt5.14.2/5.14.2/msvc2017_64/bin;
cmake-gui
设定源代码和cmake生成目录。
注意在选择编译器时,千万注意设置架构为自己需要的。我这里的默认是win32平台,需要x64平台。
- 取消勾选BUILD_TEST_APPLICATION(用于test而生成的vs项目会非常多);
- Add Entry:设置name:CMAKE_DEBUG_POSTFIX,设置type:STRING,设置value:d(debug模式时,生成的.lib和.dll文件会带上尾字“d”);
- 执行Configure(可能需要反复多次,直到没有错误)、Generate、Open Project;
- 在VS中生成ALL_BUILD,生成INSTALL(cmake没问题的情况下是可以一次成功的,有编译或者链接错误先考虑是不是cmake的配置有问题),就可以在
CMAKE_INSTALL_PREFIX
指定位置看到生成结果(bin、lib、include等文件); - 将生成的bin、lib、include、mkspecs、translation等文件分别复制到Qt5.14.2的对应目录下(参考自带的app/Qt5的文件结构)。
后面qca、qgis的编译基本都是这个步骤,就不再赘述了。
若遇到Cannot find PkgConfig ……
,在qtkeychain-master目录下找到CmakeLists.txt,找位置添加环境变量设置语句(当然,可能这种方式不算最合理;后面遇到类似情况,而cmake-gui的列表中没有对应的name,也可参考这种方式):
后记-弯路:在这里,一开始没有设置x64平台,默认生成了win32,结果到了vs里,就需要建立新的解决方案平台为x64,此时又选择了空白模板,cmake设置好的附加目录等等自此都变成了无用功,自己不仅费时费力又配置了一遍附加包含目录、依赖库等这些东西,还遇到了“无法解析的符号:某个信号函数”这样的问题,为了解决链接错误,又费九牛二虎之力把.vcxproj文件里相关文件的ClInclude或者ClCompile标记换成了QtMoc,绕了如此大圈,回过头来看,其实是第一步就走错了,越走越远,可笑为何当时就是不肯回头看看。下面就是一些遇到的问题(自己瞎走的弯,供自己反思):
-
报错:有三个moc文件并不存在,从项目中排除掉;
-
必须定义程序入口点:qt5keychain->属性->链接器->系统->子系统->选择“窗口(/SUBSYSTEM:WINDOWS)”,或者链接器->高级->入口点->设为“WinMainCRTStartup”;
-
LNK2019 无法解析的外部符号 …… QKeychain::Job::finished(class QKeychain::Job *),这是一个信号函数,无法解析应该是vs将其作为普通VC类进行了编译,而没有用QtMoc去编译;LNK2001 无法解析的外部符号 …… QKeychain::JobPrivate::metaObject(void)const QObject子类之间的元对象关系无法解析,无法构造QObject的对象树,同样需要改为用QtMoc编译:在build-qtkeychain-x64目录下找到qt5keychain.vcxproj和qt5keychain.vcxproj.filters,以文本方式打开,找到使用了QObject宏的文件,将其标记改为QtMoc。
编译qca
下载qca源代码:https://kgithub.com/KDE/qca/archive/refs/heads/master.zip
打开VS 2017命令行,设置环境变量,启动cmake-gui,同编译qtkeychain的过程。
同样取消BUILD_TESTS、设置CMAKE_DEBUG_POSTFIX;遇到缺失openssl和doxygen,需在CMakeLists.txt中添加如下的几行,即可自动填充SSL_EAY_RELEASE、LIB_EAY_RELEASE等。
set(PKG_CONFIG_EXECUTABLE "D:/Programs/OSGeo4W/3rd_party/pkg-config_0.26-1_win32/bin/pkg-config.exe")
set(DOXYGEN_EXECUTABLE "D:/Programs/doxygen/bin/doxygen.exe")
set(OPENSSL_INCLUDE_DIR "D:/Programs/OpenSSL-Win64/include/openssl")
set(OPENSSL_CRYPTO_LIBRARY "D:/Programs/OpenSSL-Win64/lib/libcrypto.lib")
Configure、Generate、Open Project、生成ALL_BUILD、INSTALL ……
编译qscintilla
下载QScintilla:https://www.riverbankcomputing.com/static/Downloads/QScintilla/2.13.4/QScintilla_src-2.13.4.zip
打开VS 2017的命令行窗口,依次输入:
set PATH=%PATH%;C:/Qt/Qt5.14.2/5.14.2/msvc2017_64/bin;
qmake
nmake all
nmake install
这里忘了设置环境变量,直接在C:/Qt/Qt5.14.2/目录下添加了生成的结果,我又将其重新剪切到D:/Programs/OSGeo4W/Qt5.14.2/目录下,有些麻烦了。
编译qwt
基本过程同上。
编译QGIS源码
下载源代码:https://kgithub.com/qgis/QGIS/archive/refs/heads/master.zip
首先配置环境变量,然后从命令行打开cmake-gui,cmake可根据环境变量自动填充很多路径,否则像“VERSION_LIBRARY”这样的name,自己去找这是哪个lib的话,就太麻烦了。
1.以文本方式打开D:/Programs/OSGeo4W/QGIS/ms-windows/osgeo4w/msvc-env.bat
和D:/Programs/OSGeo4W/etc/ini/qt5.bat
,修改其中的环境变量。
@echo off
REM ***************************************************************************
REM msvc-env.cmd
REM ***************************************************************************
if not "%PROGRAMFILES(X86)%"=="" set PF86=%PROGRAMFILES(X86)%
if "%PF86%"=="" set PF86=%PROGRAMFILES%
if "%PF86%"=="" (echo PROGRAMFILES not set & goto error)
@REM 已修改为自己的版本号
if "%VCSDK%"=="" set VCSDK=10.0.17763.0
set ARCH=%1
if "%ARCH%"=="x86" goto x86
if "%ARCH%"=="x86_64" goto x86_64
goto usage
:x86
set VCARCH=x86
@REM set CMAKE_COMPILER_PATH=%PF86%\Microsoft Visual Studio 14.0\VC\bin
@REM set DBGHLP_PATH=%PF86%\Microsoft Visual Studio 14.0\Common7\IDE\Remote Debugger\x86
set CMAKE_COMPILER_PATH=%PF86%\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.16.27023\bin\Hostx64\x86
set DBGHLP_PATH=%PF86%\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\Remote Debugger\x86
set SETUPAPI_LIBRARY=%PF86%\Windows Kits\10\Lib\%VCSDK%\um\x86\SetupAPI.Lib
goto archset
:x86_64
set VCARCH=amd64
@REM set CMAKE_COMPILER_PATH=%PF86%\Microsoft Visual Studio 14.0\VC\bin\amd64
@REM set DBGHLP_PATH=%PF86%\Microsoft Visual Studio 14.0\Common7\IDE\Remote Debugger\x64
set CMAKE_COMPILER_PATH=%PF86%\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.16.27023\bin\Hostx64\x64
set DBGHLP_PATH=%PF86%\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\Remote Debugger\x64
set SETUPAPI_LIBRARY=%PF86%\Windows Kits\10\Lib\%VCSDK%\um\x64\SetupAPI.Lib
:archset
if not exist "%SETUPAPI_LIBRARY%" (echo SETUPAPI_LIBRARY not found & goto error)
if "%CC%"=="" set CC=%CMAKE_COMPILER_PATH:\=/%/cl.exe
if "%CXX%"=="" set CXX=%CMAKE_COMPILER_PATH:\=/%/cl.exe
set CLCACHE_CL=%CMAKE_COMPILER_PATH:\=/%/cl.exe
if "%OSGEO4W_ROOT%"=="" if "%ARCH%"=="x86" (
@REM set OSGEO4W_ROOT=C:\OSGeo4W
set OSGEO4W_ROOT=D:\Programs\OSGeo4W
) else (
@REM set OSGEO4W_ROOT=C:\OSGeo4W64
set OSGEO4W_ROOT=D:\Programs\OSGeo4W
)
if not exist "%OSGEO4W_ROOT%\bin\o4w_env.bat" (echo o4w_env.bat not found & goto error)
call "%OSGEO4W_ROOT%\bin\o4w_env.bat"
call "%OSGEO4W_ROOT%\bin\py3_env.bat"
call "%OSGEO4W_ROOT%\bin\qt5_env.bat"
@REM set VS140COMNTOOLS=%PF86%\Microsoft Visual Studio 14.0\Common7\Tools\
set VS150COMNTOOLS=%PF86%\Microsoft Visual Studio\2017\Enterprise\Common7\Tools\
@REM call "%PF86%\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %VCARCH%
call "%PF86%\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" %VCARCH%
@REM path %path%;%PF86%\Microsoft Visual Studio 14.0\VC\bin
path %path%;%PF86%\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.16.27023\bin\Hostx64
@REM set GRASS7=
@REM if exist %OSGEO4W_ROOT%\bin\grass74.bat set GRASS7=%OSGEO4W_ROOT%\bin\grass74.bat
@REM if exist %OSGEO4W_ROOT%\bin\grass76.bat set GRASS7=%OSGEO4W_ROOT%\bin\grass76.bat
@REM if exist %OSGEO4W_ROOT%\bin\grass78.bat set GRASS7=%OSGEO4W_ROOT%\bin\grass78.bat
@REM if "%GRASS7%"=="" (echo GRASS7 not found & goto error)
set GRASS8=
if exist %OSGEO4W_ROOT%\bin\grass82.bat set GRASS8=%OSGEO4W_ROOT%\bin\grass82.bat
if "%GRASS8%"=="" (echo GRASS8 not found & goto error)
for /f "usebackq tokens=1" %%a in (`%GRASS8% --config path`) do set GRASS_PREFIX=%%a
@REM set PYTHONPATH=
@REM if exist "%PROGRAMFILES%\CMake\bin" path %PATH%;%PROGRAMFILES%\CMake\bin
@REM if exist "%PF86%\CMake\bin" path %PATH%;%PF86%\CMake\bin
@REM if exist c:\cygwin64\bin path %PATH%;c:\cygwin64\bin
@REM if exist c:\cygwin\bin path %PATH%;c:\cygwin\bin
set PYTHONPATH=
if exist D:\Programs\CMake3.26.3\bin path %PATH%;D:\Programs\CMake3.26.3\bin
if exist D:\Programs\Cygwin\bin path %PATH%;D:\Programs\Cygwin\bin
set LIB=%LIB%;%OSGEO4W_ROOT%\Qt5.14.2\lib;%OSGEO4W_ROOT%\lib
set INCLUDE=%INCLUDE%;%OSGEO4W_ROOT%\Qt5.14.2\include;%OSGEO4W_ROOT%\include
goto end
:usage
echo usage: %0 [x86^|x86_64]
echo sample: %0 x86_64
exit /b 1
:error
echo ENV ERROR %ERRORLEVEL%: %DATE% %TIME%
exit /b 1
:end
@REM ******************************qt5.bat*********************************
@echo off
@REM path %OSGEO4W_ROOT%\apps\qt5\bin;%PATH%
@REM set QT_PLUGIN_PATH=%OSGEO4W_ROOT%\apps\Qt5\plugins
@REM set O4W_QT_PREFIX=%OSGEO4W_ROOT:\=/%/apps/Qt5
@REM set O4W_QT_BINARIES=%OSGEO4W_ROOT:\=/%/apps/Qt5/bin
@REM set O4W_QT_PLUGINS=%OSGEO4W_ROOT:\=/%/apps/Qt5/plugins
@REM set O4W_QT_LIBRARIES=%OSGEO4W_ROOT:\=/%/apps/Qt5/lib
@REM set O4W_QT_TRANSLATIONS=%OSGEO4W_ROOT:\=/%/apps/Qt5/translations
@REM set O4W_QT_HEADERS=%OSGEO4W_ROOT:\=/%/apps/Qt5/include
@REM set O4W_QT_DOC=%OSGEO4W_ROOT:\=/%/apps/Qt5/doc
path %OSGEO4W_ROOT%\Qt5.14.2\bin;%PATH%
set QT_PLUGIN_PATH=%OSGEO4W_ROOT%\Qt5.14.2\plugins
set O4W_QT_PREFIX=%OSGEO4W_ROOT:\=/%/Qt5.14.2
set O4W_QT_BINARIES=%OSGEO4W_ROOT:\=/%/Qt5.14.2/bin
set O4W_QT_PLUGINS=%OSGEO4W_ROOT:\=/%/Qt5.14.2/plugins
set O4W_QT_LIBRARIES=%OSGEO4W_ROOT:\=/%/Qt5.14.2/lib
set O4W_QT_TRANSLATIONS=%OSGEO4W_ROOT:\=/%/Qt5.14.2/translations
set O4W_QT_HEADERS=%OSGEO4W_ROOT:\=/%/Qt5.14.2/include
set O4W_QT_DOC=%OSGEO4W_ROOT:\=/%/Qt5.14.2/doc
2.新建.bat文件,输入以下命令:
@echo off
call D:\Programs\OSGeo4W\QGIS\ms-windows\osgeo4w\msvc-env.bat x86_64
@cmd
3.保存,双击运行,在打开的命令行窗口中,输入:cmake-gui
。
4.取消勾选BUILD_TESTING、WITH_BINDINGS、ENABLE_TESTS、WITH_GRASS7(QSGeo4W中只有grass8)、WITH_QTWEBKIT(前面提到版本不匹配)。
5.Add Entry:CMAKE_DEBUG_POSTFIX,STRING,d。
6.检查各路径,不要有“NOT_FOUND”,包括Protobuf等,否则编译时会遇到各种莫名其妙的错误。(关于OPEN_CL的路径,在这篇博客上提到忽略OPEN_CL,未解深意。设置其路径为“D:/Programs/OSGeo4W/include”时,在编译过程中确实遇到过“找不到opencl.hpp”文件的问题;后将其路径留空,cmake仍然输出“Found OpenCL C++ headers ……”,但没有再出现上述问题。原因未详查。
7.在VS中生成ALL_BUILD,主要时间都用于生成qgis_core,遇到的30多个链接错误,跟libprotobuf-lite.lib有关:
LNK2019 无法解析的外部符号 __tls_guard,该符号在函数 …… AddCleanup 中使用
LNK2001 无法解析的外部符号 __GSHandlerCheck_EH4
qgis_core ……
错误中提到的符号,在代码中搜不到,后尝试从GitHub重新下载protobuf 3.13.0,cmake时勾选BUILD_SHARED_LIBS,生成动态链接库(不知是不是之前OSGeo4W自带的只有静态链接库的原因),再用protoc.exe重新生成vector_tile.pb.cc和vector_tile.pb.h,替换后解决。感谢道友博客:https://blog.csdn.net/danshiming/article/details/126583284
8.解决上述链接错误后,又产生了新的链接错误:
LNK2019 无法解析的外部符号 class google::protobuf::internal::ExplicitlyConstructed<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > google::protobuf::internal::fixed_address_empty_string" (?fixed_address_empty_string@internal@protobuf@google@@3V?$ExplicitlyConstructed@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@123@A),该符号在函数 "private: void __cdecl QgsVectorTileMVTEncoder::addFeature(class vector_tile::Tile_Layer *,class QgsFeature const &)" (?addFeature@QgsVectorTileMVTEncoder@@AEAAXPEAVTile_Layer@vector_tile@@AEBVQgsFeature@@@Z) 中被引用 qgis_core D:\Programs\OSGeo4W\QGIS\ms-windows\build-qgis-x64\src\core\qgsvectortilemvtencoder.obj 1 D:\Programs\OSGeo4W\QGIS\ms-windows\build-qgis-x64\src\core
LNK2001 无法解析的外部符号 "class google::protobuf::internal::ExplicitlyConstructed<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > google::protobuf::internal::fixed_address_empty_string" (?fixed_address_empty_string@internal@protobuf@google@@3V?$ExplicitlyConstructed@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@123@A) qgis_core D:\Programs\OSGeo4W\QGIS\ms-windows\build-qgis-x64\src\core\vector_tile.pb.obj 1 D:\Programs\OSGeo4W\QGIS\ms-windows\build-qgis-x64\src\core
在属性->C/C+±>预处理器,添加PROTOBUF_USE_DLLS
,重新生成后解决。感谢道友的博客:https://blog.csdn.net/sun007700/article/details/100832422
9.生成ALL_BUILD、INSTALL,将以下目录中所有文件复制到install位置的bin(qgis.exe所在位置)
D:/Programs/OSGeo4W/bin/
D:/Programs/OSGeo4W/apps/gdal-dev/bin/
D:/Programs/OSGeo4W/Qt5.14.2/bin/
而后,将D:/Programs/OSGeo4W/Qt5.14.2/plugins/
下所有文件复制到install位置的plugins里,点击qgis.exe即可启动qgis-desktop。
附:最后install生成成功后,不知道bin文件夹中缺少哪些dll,可以双击qgis_process.exe,它会提示缺少哪些链接库,而qgis.exe只能报错:找不到qgis_core.dll。qgis_process.exe双击能看见命令行窗口,应该就可以了。