当前位置: 首页 > news >正文

如何在CMake项目中实现类似MFC的版本信息配置:详解VS_VERSION_INFO的应用

1. 为什么需要版本信息配置

在Windows平台上开发应用程序时,版本信息是一个非常重要的元数据。它不仅能帮助用户识别软件版本,还能在系统管理、错误报告和更新检查中发挥关键作用。如果你用过MFC开发,一定对资源文件中的版本信息配置非常熟悉。右键点击一个exe文件选择"属性",在"详细信息"标签页看到的那些版本号、公司名称等信息,就是通过VS_VERSION_INFO资源实现的。

传统MFC项目直接在.rc资源文件中硬编码这些信息,但对于现代CMake项目来说,我们需要更灵活的配置方式。想象一下每次发布新版本都要手动修改资源文件,既容易出错又不便于自动化构建。我在实际项目中就遇到过因为忘记更新版本号导致测试混乱的情况,后来改用CMake动态生成才彻底解决了这个问题。

2. 准备工作:理解VS_VERSION_INFO结构

2.1 VS_VERSION_INFO资源详解

VS_VERSION_INFO是Windows定义的标准资源类型,它采用了一种特殊的结构体格式。这个结构包含了两类信息:

  1. 固定信息:包括文件版本、产品版本、文件类型等
  2. 字符串信息:包含可读的版本字符串、公司名称、版权信息等

在资源脚本(.rc)中,它通常长这样:

VS_VERSION_INFO VERSIONINFO FILEVERSION 1,0,0,0 PRODUCTVERSION 1,0,0,0 FILEFLAGSMASK 0x3fL FILEFLAGS 0x0L FILEOS VOS__WINDOWS32 FILETYPE VFT_APP { BLOCK "StringFileInfo" { BLOCK "040904E4" { VALUE "FileVersion", "1.0.0" VALUE "ProductName", "我的应用" } } BLOCK "VarFileInfo" { VALUE "Translation", 0x409, 1252 } }

2.2 版本号的组成规则

Windows版本号通常由4个数字组成,格式为主版本.次版本.修订号.构建号。在实际项目中,我建议这样使用:

  • 主版本:重大功能更新
  • 次版本:新增功能
  • 修订号:bug修复
  • 构建号:持续集成系统的自动递增编号

3. CMake项目中的实现方案

3.1 创建模板文件version.rc.in

首先我们需要创建一个模板文件,让CMake能够动态填充版本信息。在项目根目录下新建version.rc.in

#include <windows.h> VS_VERSION_INFO VERSIONINFO FILEVERSION @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_PATCH@,0 PRODUCTVERSION @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_PATCH@,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS VOS__WINDOWS32 FILETYPE VFT_APP { BLOCK "StringFileInfo" { BLOCK "040904E4" { VALUE "FileVersion", "@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@" VALUE "ProductVersion", "@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@" VALUE "CompanyName", "@PROJECT_COMPANY_NAME@" VALUE "FileDescription", "@PROJECT_DESCRIPTION@" VALUE "ProductName", "@PROJECT_NAME@" VALUE "LegalCopyright", "@PROJECT_COPYRIGHT@" } } BLOCK "VarFileInfo" { VALUE "Translation", 0x409, 1252 } }

这个模板使用了CMake的变量替换语法@VAR_NAME@,稍后我们会在CMakeLists.txt中定义这些变量。

3.2 配置CMakeLists.txt

接下来修改你的CMakeLists.txt,添加版本信息配置:

# 设置版本号 set(PROJECT_VERSION_MAJOR 1) set(PROJECT_VERSION_MINOR 0) set(PROJECT_VERSION_PATCH 0) # 设置其他元数据 set(PROJECT_NAME "我的应用") set(PROJECT_COMPANY_NAME "我的公司") set(PROJECT_DESCRIPTION "这是一个使用CMake构建的应用程序") set(PROJECT_COPYRIGHT "版权所有 © 2023") # 生成版本资源文件 configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version.rc @ONLY ) # 添加资源文件到项目 add_executable(MyApp WIN32 src/main.cpp ${CMAKE_CURRENT_BINARY_DIR}/version.rc )

这里有几个关键点需要注意:

  1. configure_file命令会将模板中的变量替换为实际值
  2. 生成的文件放在CMAKE_CURRENT_BINARY_DIR,保持源码目录干净
  3. 资源文件必须添加到可执行文件的源文件列表中

4. 高级配置技巧

4.1 自动生成构建号

手动维护构建号很麻烦,我们可以利用CMake的脚本功能自动生成:

# 获取当前日期作为构建号 string(TIMESTAMP BUILD_DATE "%Y%m%d") set(PROJECT_BUILD_NUMBER ${BUILD_DATE}) # 在模板中使用 FILEVERSION @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_PATCH@,${PROJECT_BUILD_NUMBER}

4.2 支持多语言

如果你的应用需要支持多语言,可以修改StringFileInfo块:

BLOCK "StringFileInfo" { BLOCK "040904E4" # 英语(美国) { VALUE "FileDescription", "English description" } BLOCK "040404E4" # 中文(简体) { VALUE "FileDescription", "中文描述" } }

4.3 从外部文件读取版本号

对于大型项目,建议将版本信息单独放在一个文件中,比如version.cmake

# version.cmake set(PROJECT_VERSION_MAJOR 1) set(PROJECT_VERSION_MINOR 2) set(PROJECT_VERSION_PATCH 3)

然后在主CMakeLists.txt中包含它:

include(version.cmake)

这样版本管理会更清晰,也便于自动化脚本处理。

5. 常见问题与解决方案

5.1 版本信息不显示

如果生成的exe文件没有显示版本信息,检查以下几点:

  1. 确保资源文件被正确添加到add_executable
  2. 检查生成的version.rc文件内容是否正确
  3. 尝试清理并重新生成整个项目

5.2 版本号格式问题

Windows资源管理器显示的版本字符串有时会忽略最后的0,这是正常现象。比如1.0.0.0可能显示为1.0.0

5.3 调试版与发布版的区分

在模板中我们使用了预处理器判断_DEBUG宏:

#ifdef _DEBUG FILEFLAGS 0x1L # VS_FF_DEBUG #else FILEFLAGS 0x0L #endif

这可以确保调试版和发布版有不同的版本标志。

6. 实际应用案例

在我最近的一个跨平台项目中,我们使用这套方案管理Windows版本的版本信息,同时通过Git标签自动生成版本号。具体实现如下:

# 从Git标签获取版本号 find_package(Git) if(GIT_FOUND) execute_process( COMMAND ${GIT_EXECUTABLE} describe --tags --abbrev=0 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE GIT_TAG OUTPUT_STRIP_TRAILING_WHITESPACE ) if(GIT_TAG) string(REGEX MATCH "v([0-9]+)\\.([0-9]+)\\.([0-9]+)" _ ${GIT_TAG}) set(PROJECT_VERSION_MAJOR ${CMAKE_MATCH_1}) set(PROJECT_VERSION_MINOR ${CMAKE_MATCH_2}) set(PROJECT_VERSION_PATCH ${CMAKE_MATCH_3}) endif() endif()

这样每次打tag发布时,版本号会自动更新,完全不需要手动维护。

http://www.jsqmd.com/news/617642/

相关文章:

  • Ostrakon-VL-8B多模态模型教程:货架商品销量预测辅助特征生成方法
  • 终极Windows快捷键侦探指南:3分钟揪出隐藏的热键占用者
  • NVIDIA显卡风扇控制组件状态切换异常的技术诊断与NvApiWrapper兼容性解决方案实践
  • 2026浏览器指纹追踪与反追踪技术深度解析:从风控原理到安全实践
  • 3分钟搞定Windows和Office激活:KMS_VL_ALL_AIO智能脚本完整教程
  • OpenClaw技能市场探索:安装Phi-3-vision-128k-instruct专用插件的正确姿势
  • Pixel Mind Decoder 数据预处理实战:文本清洗、分词与向量化技巧
  • Smartforms 单元格动态换行与格式优化实战
  • 终极罗技鼠标宏实战指南:PUBG压枪脚本快速配置与深度优化
  • PHP网关调试失效?93%的线上事故源于这3个被忽略的底层配置项(工业场景实测数据支撑)
  • 如何实现游戏隐身:Deceive隐私保护工具终极指南
  • 5个关键步骤掌握OpenFace:终极面部行为分析工具完全指南
  • 突破性技术解析:JiYuTrainer如何高效破解教学控制系统限制 [特殊字符]
  • 百考通:AI精准赋能期刊论文写作,打破传统学术写作的壁垒
  • STM32c8t6与激光雷达A1M8的串口通信实战
  • Pixel Aurora Engine 生成代码注释与文档图示实战
  • Padavan固件+K2路由器:低成本破解校园网锐捷认证全攻略
  • Linux服务器监控:OpenClaw对接SecGPT-14B实现安全事件自动研判
  • 终极解决方案:如何快速修复显卡风扇控制问题并优化电脑散热
  • Qwen3-14B私有化部署实操手册:从镜像拉取到WebUI对话全流程详解
  • 【读书笔记】《彷徨》
  • 无网络环境下 MySQL 5.7 完整离线部署指南
  • 通义千问1.5-1.8B-Chat-GPTQ-Int4系统管理助手:Linux操作系统问题排查指南
  • 地理数据可视化架构升级:如何用geojson2svg实现下一代SVG智能转换方案
  • 跨平台媒体压缩架构:CompressO如何重新定义本地化媒体处理范式
  • 保护你在线隐私的10个建议
  • NaViL-9B应用场景解析:如何用AI模型做图片内容识别与文字提取
  • SMUDebugTool:解锁AMD Ryzen处理器隐藏性能的硬件调谐器
  • OBS-VirtualCam技术架构解析:Windows平台虚拟摄像头的高效实现方案
  • 八大网盘直链下载助手终极指南:告别龟速下载,拥抱高效传输