cmake 配置 MySQL 版本号

背景

MySQL 源码包的“根目录”下保存着一个叫MYSQL_VERSION 的文本文件,它用来指定 MySQL 的版本号,以 MySQL-8.0.23 为例,其内容如下。

MYSQL_VERSION_MAJOR=8
MYSQL_VERSION_MINOR=0
MYSQL_VERSION_PATCH=23
MYSQL_VERSION_EXTRA=

MySQL 是直接读这个文件来指定版本号的嘛?虽然最终的效果和直接读文件差不多,不过事实上是在 cmake 的帮助下完成的。下面我们来看 cmake 做了什么。

cmake-version


之前的实现方法

之前的做法比较简单粗暴,就是把版本号作为程序中的一个变量(通常是在头文件中声明),下面以 hello-world 项目为例子。

tree .
.
├── hello-world.cpp # 源文件
└── hello-world.h   # 头文件

hello-world.h 文件的内容如下。

#ifndef hello_world_h_

#define HELLO_WORLD_VERSION_MAJOR 1
#define HELLO_WORLD_VERSION_MINOR 0

#endif

hello-world.cpp 文件的内容如下。

#include<iostream>
#include "hello-world.h"

using namespace std;
int main()
{
    // 直接打印版本号别的什么都不做
    cout<<HELLO_WORLD_VERSION_MAJOR<<"."<<HELLO_WORLD_VERSION_MINOR<<endl;
    return 0;
}

存在的问题

我觉得最大的问题就是在于源代码文件无法封闭,也就是说改一个版本号我要去改源代码;后面大家的想法是头文件中的内容根据配置动态生成。下面我用 cmake 来演示一下。


cmake 的实现方法

cmake 用来配置这个也比较方便,主要是因为 cmake 配置文件本身就有指定软件的版本号,像下面这个配置文件把软件的版本号配置成了 1.0 。

cmake_minimum_required(VERSION 3.0)
project(HELLO_WORLD VERSION 1.0)

那么剩下的就是告诉 cmake 把版本号“填”入哪个头文件模板,这个也只是一行 cmake 指令的事。

cmake_minimum_required(VERSION 3.0)
project(HELLO_WORLD VERSION 1.0)

configure_file(hello-world.h.in src/hello-world.h) # 用项目目录下的 hello-world.h.in 文件作为模板生成  src/hello-world.h 这个头文件。

hello-world.h.in 模板文件的内容如下。

#ifndef HELLO_WORLD_H_

#define HELLO_WORLD_VERSION_MAJOR @HELLO_WORLD_VERSION_MAJOR@
#define HELLO_WORLD_VERSION_MINOR @HELLO_WORLD_VERSION_MINOR@

#endif

完整的 cmake 配置。

cmake_minimum_required(VERSION 3.0)
project(HELLO_WORLD VERSION 1.0)

configure_file(hello-world.h.in src/hello-world.h)

add_executable(hello-world-cmake src/hello-world.cpp)

target_include_directories(hello-world-cmake PUBLIC
                           "${PROJECT_BINARY_DIR}/src"
                           )

项目的文件分布如下。

tree .
.
├── CMakeLists.txt # 
├── hello-world.h.in
└── src
    └── hello-world.cpp

1 directory, 3 files

编译

mkdir build
cd build/

cmake ../
-- The C compiler identification is GNU 8.3.1
-- The CXX compiler identification is GNU 8.3.1
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /opensource/cpps/build

cmake --build .
Scanning dependencies of target hello-world-cmake
[ 50%] Building CXX object CMakeFiles/hello-world-cmake.dir/src/hello-world.cpp.o
[100%] Linking CXX executable hello-world-cmake
[100%] Built target hello-world-cmake

检查

./hello-world-cmake
1.0

注意

MySQL 并没有像我这样把版本号直接写到 CMakeLists.txt ,它把 CMakeLists.txt 给封闭了,把版本号的放到了 MYSQL_VERSION 这个文件中去。 它在 CMakeLists.txt 中加入了这么两行,总的效果是一样的。

INCLUDE(mysql_version)

CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/include/mysql_version.h.in
               ${CMAKE_BINARY_DIR}/include/mysql_version.h )