# 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`的文件开始，其中包含以下内容:

```
2.0.1-rc-2
```

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

```cpp
#pragma once
#include <string>
const std::string PROGRAM_VERSION = "@PROGRAM_VERSION@";
```

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

```cpp
// provides PROGRAM_VERSION
#include "version.hpp"
#include <iostream>

int main() {
  std::cout << "This is output from code v" << PROGRAM_VERSION
  << std::endl;
  std::cout << "Hello CMake world!" << std::endl;
}
```

## 具体实施

逐步来完成我们的任务:

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

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

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

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

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

   ```
   $ mkdir -p build
   $ cd build
   $ cmake ..
   $ cmake --build .
   $ ./example

   This is output from code v2.0.1-rc-2
   Hello CMake world!
   ```

## 工作原理

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

```
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/VERSION")
  file(READ "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" PROGRAM_VERSION)
  string(STRIP "${PROGRAM_VERSION}" PROGRAM_VERSION)
else()
    message(FATAL_ERROR "File ${CMAKE_CURRENT_SOURCE_DIR}/VERSION not found")
endif()
```

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

```
configure_file(
  version.hpp.in
  generated/version.hpp
  @ONLY
  )
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://chenxiaowei.gitbook.io/cmake-cookbook/6.0-chinese/6.5-chinese.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
