文章

升级tk服务的vs配置

升级tk服务的vs配置

[TOC]

目标

将 TK 服务从 vs2010 升级至 vs2017 。

背景

DBA 提供了 MongoDB 7.0.5 的数据库,现要测试在 TK 服务中用 MongoDB 代替 Redis 。目前行为数据组的 TK 服务均是使用 VisualStudio 2010 构建的。

若要在 C++ 项目中连接 MongoDB,需要使用 MongoDB 官方提供的 C 库 mongo-c-driver1,或 c++ 库 mongocxx2

mongocxx 需要 C++11 编译器,因此不适用于 VS2010 的项目;mongo-c-driver 最后一版支持 VS2010 项目的版本号为 1.17.2,该版本是针对 MongoDB 3.x 使用的,兼容 MongoDB 5.x,与 MongoDB 7.x 可能存在兼容问题。

现状总结:目前使用 vs2010 构建的 TK 服务不能连接到高版本的 MongoDB 7.0.5 上。

解决方案 有两个:

  1. 将 TK 服务从 vs2010 升级至 vs2017。
  2. 探索怎样在 vs2010 的 C++ 项目上连接高版本 MongoDB,成功后还需进行大量测试验证稳定性(因为官方没有进行验证和维护这一套通路)。

经过简单探索,最终选择方案 1,理由如下

  1. 两个方案的投入时间预估相差不大,但前者是面向未来,后者是给历史打补丁。
  2. 前者可以使用 MongoDB 官方提供的 c++ 驱动库,后者只有 C 驱动库,使用体验有差距。
  3. 前者的链路是官方验证且一直维护的,后者官方没有维护过,可靠性上有很大差距,且即使方案2尝试成功,也需要大量的测试来保证其实用性。

TK 服务使用基类是通过静态库来使用的,最高能升级到什么版本的 VS,需要看基类提供的最高版本是什么。

经查看,TK 基类提供了 vs03、vs10、vs12、vs15、vs17 的完整静态库,如下图所示。

image-20240820151536686

本次选择 vs2017 作为项目的升级目标。

升级流程

1)环境介绍

系统信息:

版本 Windows 10 企业版 LTSC
版本号 21H2
安装日期 2024/‎4/‎17
操作系统内部版本 19044.4780
体验 Windows Feature Experience Pack 1000.19060.1000.0

IDE:我本地有 vs2010、vs2017、vs2022 三个,本文只使用 vs2017 即可。

注:本文来自于升级项目 TKMarkerService 和 TKNOSService 的过程总结

2)拉取公共库源码

在GitLab存储库 UBDsharecode\ShareCode 中新建分支 UpToVS2017 ,为TK项目提供支持vs2017的公用库。

截止至 2024年8月20日,已将升级 NOS 和 Marker 用到的公共库提交到了上述分支中,提交内容见 Git 记录。

2025年1月13日 注:上述 ShareCode 的 UpToVS2017 分支已合并到 master 分支。

3)项目配置修改

  • 【项目属性】-【常规】-【平台工具集】改为: Visual Studio 2017(v141)

  • 【项目属性】-【常规】-【Windows SDK 版本】改为:8.1

    说明:目标服务器的系统版本为 Windows Server 2012 R2,因此挑选了一个与该系统版本兼容性最好的 WinSDK 统一使用;该版本的 SDK 可通过 VS2017 的安装程序进行安装。

  • 【项目属性】-【链接器】-【输入】-【附加依赖项】去掉:jsoncpp.lib;hiredis.lib;mysqlpp.lib;(如有这些项)

    说明:

    公共盘中提供的 jsoncpp.lib 和 hiredis.lib 是用早于 2017 版本的 VS 编译的,在本项目中使用的话会提示报错导致编译失败:“jsoncpp.lib 使用低于当前版本的VS编译”。因此这里不再使用 json、hiredis 相关的静态库,转为在项目中使用 json、hiredis 相关的源码,使用方法见下文。

    公共盘中提供的 mysqlpp.lib 中使用了 autoptr 等 C++17 已经淘汰的语法,因此需要用新版本的 mysql++ 代替。

  • 【项目属性】-【VC++目录】-【包含目录】新增 2 项:

    1
    2
    
    $(TKSDK)\Other\Boost\boost_1_71_0;
    $(TKSDK)\Other\Boost\boost_1_71_0\boost;
    

    若附加依赖项中去掉了 jsoncpp.lib,还需添加 1 项:

    1
    
    $(TKGIT)\sharecode\ShareCode\jsoncpp;
    

    若附加依赖项中去掉了 hiredis.lib,这里还需添加 1 项:

    1
    
    $(TKGIT)\sharecode\ShareCode\hiredis;
    

    若附加依赖项中去掉了 mysqlpp.lib,还需添加 2 项:

    1
    2
    
    $(TKGIT)\sharecode\ShareCode\mysqlUtil;
    $(TKGIT)\sharecode\ShareCode\mysqlUtil\mysql++3.3.0;
    

    说明:boost 是为了让项目能自动链接到需要的静态库;其它新增路径是为后面引入对应的源码做准备

  • 【项目属性】-【VC++目录】-【库目录】新增 1 项:

    1
    
    $(TKSDK)\Other\Boost\boost_1_71_0\lib32-msvc-14.1;
    

    说明:boost 之前是使用的 boost_1_54_0 版本,公共盘中提供的该版本 boost 静态库不兼容 vs2017,因此需要升级至兼容 vs2017 的公共库,经查看,公共盘中提供的 boost_1_71_0 是兼容 vs2017 的。

    将 boost_1_71_0 的路径放在 boost_1_54_0 的路径前面,可以在不修改本地用户配置的前提下,使本项目优先使用 boost_1_71_0。

  • 【项目属性】-【C/C++】-【命令行】-【其他选项】新增:/Zc:__cplusplus

    说明:NOS 项目中使用了第三方项目 mysql++,该项目 3.3.0 版本的文件中使用了宏定义 __cplusplus 来区分当前编译器的版本。但是在编辑、编译的时候该宏定义总是被识别为199711L。解决方法见参考3

  • 【项目属性】-【C/C++】-【语言】-【符合模式】选择:

    说明:这里如果不选 “否” 的话,会有非常多的语法报错,比如参数格式为 char*,但是入参为 “XXX”(const char*)的格式的话就会报错,导致编译不通过。因此这里选择降低语法审查标准。

  • 【项目属性】-【C/C++】-【语言】-【C++语言标准】选择:ISO C++17标准(/std:c++17)

    说明:这里默认会空着,不知道是啥,直接就选 C++17 一步到位好了。

4)代码修改

添加 json 源码(按需添加)

上文提到不再使用 jsoncpp.lib 静态库,转为使用 jsoncpp 相关的源码,通过以下步骤添加:

  • 在项目中新建筛选器 jsoncpp
  • 在新建的筛选器上右键:【添加】-【现有项】;
  • 选择路径 \ShareCode\ShareCode\jsoncpp\中的 4 个与 json 相关的文件:json.hjsoncpp.cppjson-forwards.hJsonUtil.h
  • 添加成功。

选择 sharecode 中的 jsoncpp 源码可以保证不同 TK 服务使用 json 的一致性。

这里添加的 jsoncpp 源码与之前使用的 jsoncpp.lib 是一致的,无须担心版本问题。

添加 hiredis 源码(按需添加)

操作步骤及原理同 jsoncpp。修改结果如下:

image-20240820161407152

添加 mysql++ 源码(按需添加)

之前使用的 mysqlpp.lib 不支持 c++17 的编译器,经过头文件跟踪,发现 mysqlpp.lib 的源码对应于 \ShareCode\ShareCode\mysqlUtil\mysql++ 中的所有文件。

但这个版本的 mysql++ 中使用了 std::autoptr 等 c++17 中去掉的语法,因此需要升级。

我在网上下载了 mysql++3.3.0 版本的源码4,放在 \ShareCode\ShareCode\mysqlUtil\mysql++3.3.0 文件夹中;参照 jsoncpp 和 hiredis 的方法,将 mysql++3.3.0 的源码(共 78 个文件)添加至项目。

语法修改

有一些项目内或 sharecode 中的文件会使用一些 vs2017 不再支持的语法,这些报错均需要修改,否则编译不过。

我一开始以为这里会修改大量的代码,但是在 TKMarker 项目中仅修改了一处代码,还是在 sharecode 的 ServiceCLS.cpp 中,修改位置见下图:

image-20240820155453128

在 NOSService 中也只修改了两处,分别位于 TKMsgRecover.h 和 mysql++3.3.0/cpool.h 两个文件中,修改位置在文件中搜索注释即可。

5)依赖静态库说明

  • 通过上文的操作,编译时捣乱的低版本的静态库 jsoncpp.lib 和 hiredis.lib 已经用源码代替了;
  • 附加依赖项 mysqlpp.lib 不会影响升级后的编译;
  • boost 相关的静态库会在项目升级至 vs2017 后自动搜索(通过头文件读取项目、环境配置的宏定义)合适版本的静态库参与链接;
  • 基类相关的静态库同样会在项目升级至 vs2017 后自动搜索合适版本的静态库参与链接。

现阶段升级结果

截止至 2024年8月20日,已升级 NOS 和 Marker 两个服务并成功编译,相关修改已提交至对应 GitLab 存储库的 UpToVS2017 分支(不同项目都叫这个分支)。

于 2024年8月20日21:26:37 将升级后的 NOS.exe 上传到内网进行测试。

遇到的问题

1)无法识别的标志“-Ot”

我本地是用的 VS2017 的版本为 15.3.2,在该版本中编译 TKMaker 的时候会有如下报错:

1>TKBGServiceBase_vs17_vc150_RS.lib(ServiceStat.obj) : 找到 MSIL .netmodule 或使用 /GL 编译的模块;正在使用 /LTCG 重新启动链接;将 /LTCG 添加到链接命令行以改进链接器性能 1>LINK : fatal error C1007: 无法识别的标志“-Ot”(在“p2”中) 1>LINK : fatal error LNK1257: 代码生成失败 1>已完成生成项目“TKMarkerService.vcxproj”的操作 - 失败。

后来换到 VS2022 上编译就可以成功了,主要是因为低版本的 VS 不支持 “-Ot” 配置项,见参考文章5

2)mysql++

因为使用老版本的 mysqlpp.lib 项目编译不通过,所以本次升级采用了新的 mysql++3.3.0 版本(相对之前是新的),该版本发布于 2021.04.28。

使用时参照上一版本对源码进行了修改(ctool.h)。

3)宏定义 __cplusplus 不起作用

背景:项目中会使用宏定义 __cplusplus

问题:尽管修改了 C++ 语言标准为 ISO C++17 标准(/std:c++17),但是宏定义__cplusplus仍然被识别为199711L

解决方法:【属性】->【C/C++】->【命令行】->【其他选项】,输入:/Zc:__cplusplus

  • 在 Visual Studio 编译器中,/Zc:__cplusplus 是一个编译器选项。
  • 通常情况下,即使将项目设置为使用 C++17 或更高标准,__cplusplus 宏可能不会自动更新为相应的值(如对于 C++17 应该是 201703L),这是因为 Visual Studio 为了保持向后兼容性而采用的默认行为。
  • 当添加 /Zc:__cplusplus 选项时,编译器会强制更新 __cplusplus 宏,使其准确反映你正在使用的 C++ 标准。

参考

本文由作者按照 CC BY 4.0 进行授权