6.5 从文件中记录项目版本

NOTE:此示例代码可以在 https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-6/recipe-05 中找到,其中包含一个C++例子。该示例在CMake 3.5版(或更高版本)中是有效的,并且已经在GNU/Linux、macOS和Windows上进行过测试。

这个示例的目的和前一个相似,但是出发点不同。我们计划是从文件中读取版本信息,而不是将其设置在CMakeLists.txt中。将版本保存在单独文件中的动机,是允许其他构建框架或开发工具使用独立于CMake的信息,而无需将信息复制到多个文件中。与CMake并行使用的构建框架的一个例子是Sphinx文档框架,它生成文档并将其部署到阅读文档服务中,以便在线提供代码文档。

准备工作

我们将从一个名为VERSION的文件开始,其中包含以下内容:

  1. 2.0.1-rc-2

这一次,选择更安全的数据类型,并将PROGRAM_VERSION定义为version.hpp.in中的字符串常量:

  1. #pragma once
  2. #include <string>
  3. const std::string PROGRAM_VERSION = "@PROGRAM_VERSION@";

下面的源码(example.cpp),将包含生成的version.hpp:

  1. // provides PROGRAM_VERSION
  2. #include "version.hpp"
  3. #include <iostream>
  4. int main() {
  5. std::cout << "This is output from code v" << PROGRAM_VERSION
  6. << std::endl;
  7. std::cout << "Hello CMake world!" << std::endl;
  8. }

具体实施

逐步来完成我们的任务:

  1. CMakeLists.txt定义了最低版本、项目名称、语言和标准:

    1. cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
    2. project(recipe-05 LANGUAGES CXX)
    3. set(CMAKE_CXX_STANDARD 11)
    4. set(CMAKE_CXX_EXTENSIONS OFF)
    5. set(CMAKE_CXX_STANDARD_REQUIRED ON)
  2. 从文件中读取版本信息如下:

    1. if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/VERSION")
    2. file(READ "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" PROGRAM_VERSION)
    3. string(STRIP "${PROGRAM_VERSION}" PROGRAM_VERSION)
    4. else()
    5. message(FATAL_ERROR "File ${CMAKE_CURRENT_SOURCE_DIR}/VERSION not found")
    6. endif()
  3. 配置头文件:

    1. configure_file(
    2. version.hpp.in
    3. generated/version.hpp
    4. @ONLY
    5. )
  4. 最后,定义了可执行文件及其依赖关系:

    1. add_executable(example example.cpp)
    2. target_include_directories(example
    3. PRIVATE
    4. ${CMAKE_CURRENT_BINARY_DIR}/generated
    5. )
  5. 进行测试:

    1. $ mkdir -p build
    2. $ cd build
    3. $ cmake ..
    4. $ cmake --build .
    5. $ ./example
    6. This is output from code v2.0.1-rc-2
    7. Hello CMake world!

工作原理

我们使用以下构造,从一个名为VERSION的文件中读取版本字符串:

  1. if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/VERSION")
  2. file(READ "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" PROGRAM_VERSION)
  3. string(STRIP "${PROGRAM_VERSION}" PROGRAM_VERSION)
  4. else()
  5. message(FATAL_ERROR "File ${CMAKE_CURRENT_SOURCE_DIR}/VERSION not found")
  6. endif()

这里,首先检查该文件是否存在,如果不存在,则发出错误消息。如果存在,将内容读入PROGRAM_VERSION变量中,该变量会去掉尾部的空格。当设置了变量PROGRAM_VERSION,就可以使用它来配置version.hpp.in,生成generated/version.hpp:

  1. configure_file(
  2. version.hpp.in
  3. generated/version.hpp
  4. @ONLY
  5. )