前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >基于cmake为项目自动获取git分支tag的版本号和commitid

基于cmake为项目自动获取git分支tag的版本号和commitid

作者头像
码农心语
发布2024-07-20 11:29:13
350
发布2024-07-20 11:29:13
举报
文章被收录于专栏:码农心语
  1. 引言

  在项目构建的时候,我们经常会希望能够将git提交的分支信息和提交号(commitid)以及当前版本发布的tag信息作为版本号自动构建到程序里面,以便后续能够快速定位所运行的程序所定影的git源码的版本,从而快速发现和定位问题。  

本文利用cmake的自动构建能力,来实现以下信息的自动提取并构建到程序中:

  • 当前代码的git 分支名
  • 当前代码的git 提交号(commitid)
  • 当前代码的tag所设置的版本号
  • 当前代码的构建时间
  • 当前代码的构建号(buildno)

  以下以c语言构成为例,展示了利用cmake自动生成config.h文件,从而将以上信息自动集成到c语言工程代码中的过程。

  1. 实现过程

2.1 工程目录规划

  如下图:

  其中有c语言源码都放在工程根目录下面,当然,对于比较大型的工程,可以对源码目录进行更细地拆分和规划,本demo只有一个test.c和config.h的c源码文件,因此源码目录从简;创建一个cmake目录,用来存放自定义的cmake模块文件;创建一个build目录,用来存放cmake运行所产生的输出文件。

2.2 c程序文件

  test.c 文件的内容如下:

代码语言:javascript
复制
#include <stdio.h>
#include "config.h"

int main()
{
    printf("version: %s\n", PROJECT_VERSION);
    printf("commit:  %s\n", GIT_COMMITID);
    printf("branch:  %s\n", GIT_BRANCH);
    printf("build time: %s\n", BUILD_TIME);
    printf("build no: %s\n", BUILD_NO);
    return 0;
}

  程序非常简单,无需多言。

  config.h文件的内容如下:

代码语言:javascript
复制
#ifndef __CONFIG_H__
#define __CONFIG_H__

#define PROJECT_VERSION "0-1-9-alpha"
#define GIT_COMMITID    "51045662cffc38c5cf706090a6f0c3d16311d85e"
#define GIT_BRANCH      "test"
#define BUILD_TIME      "2024-07-10 10:45:29"
#define BUILD_NO        "10"

#endif

  这个config.h文件是用cmake自动构建出来的,不需要每次手工修改。以下是程序运行的效果:

代码语言:javascript
复制
stone:build$ ./gitversion

version: 0-1-9-alpha
commit:  51045662cffc38c5cf706090a6f0c3d16311d85e
branch:  test
build time: 2024-07-10 10:45:29
build no: 10

2.3 CMakeLists.txt

代码语言:javascript
复制
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)

project(gitversion C)

# 设置自定义模块文件的所在路径
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/")

# 导入自定义模型文件
include(GitVersion)
include(BuildNumber)

# 获取程序的版本信息
fetch_version_from_git("GITVERSION")

# 获取程序的构建号
new_build_number("GITVERSION")

set(GITVERSION_VERSION "${GITVERSION_VERSION_MAJOR}-${GITVERSION_VERSION_MINOR}-${GITVERSION_VERSION_PATCH}-${GITVERSION_VERSION_STAGE}")

# 生成程序的构建时间
string(TIMESTAMP BUILD_TIME "%Y-%m-%d %H:%M:%S")

# 利用config.h.in模板文件自动生成config.h文件
configure_file("${PROJECT_SOURCE_DIR}/config.h.in"
            "${PROJECT_SOURCE_DIR}/config.h" @ONLY)

# 创建构建目标为可执行程序
add_executable(${PROJECT_NAME} test.c)

2.4 GitVersion.cmake文件

代码语言:javascript
复制
# This module defines the following variables utilizing
# git to determine the parent tag. And if found the macro
# will attempt to parse them in the github tag format
#
# Useful for auto-versioning in our CMakeLists
#
#  ${VARPREFIX}_VERSION_MAJOR - Major version.
#  ${VARPREFIX}_VERSION_MINOR - Minor version
#  ${VARPREFIX}_VERSION_PATCH - Patch number
#  ${VARPREFIX}_VERSION_STAGE - Stage version
#  ${VARPREFIX}_COMMITID      - Git commitid
#  ${VARPREFIX}_BRANCH        - Git branch
#
# Example usage:
#
# fetch_version_from_git("test")
#    message("        major=${test_VERSION_MAJOR}")
#    message("        minor=${test_VERSION_MINOR}")
#    message("        patch=${test_VERSION_PATCH}")
#    message("        stage=${test_VERSION_STAGE}")
#    message("        stage=${test_BRANCH}")

include(FindGit)

macro(fetch_version_from_git VARPREFIX)
    # set our defaults.
    set(${VARPREFIX}_VERSION_MAJOR 1)
    set(${VARPREFIX}_VERSION_MINOR 0)
    set(${VARPREFIX}_VERSION_PATCH 0)
    set(${VARPREFIX}_VERSION_STAGE "alpha-dev")

    find_package(Git)

    if (GIT_FOUND)
        # 获取git的提交号
        execute_process(
           COMMAND
                ${GIT_EXECUTABLE} rev-parse  HEAD
            WORKING_DIRECTORY
                ${PROJECT_SOURCE_DIR}
            RESULT_VARIABLE
                GITRET
            OUTPUT_VARIABLE
                ${VARPREFIX}_COMMITID
            OUTPUT_STRIP_TRAILING_WHITESPACE
        )

        if (NOT GITRET EQUAL 0)
            message(FATAL_ERROR "Failed to fetch current git commitid.")
        endif()

        # 获取git的分支名
        execute_process(
           COMMAND
                ${GIT_EXECUTABLE} rev-parse  --abbrev-ref HEAD
            WORKING_DIRECTORY
                ${PROJECT_SOURCE_DIR}
            RESULT_VARIABLE
                GITRET
            OUTPUT_VARIABLE
                ${VARPREFIX}_BRANCH
            OUTPUT_STRIP_TRAILING_WHITESPACE
        )

        if (NOT GITRET EQUAL 0)
            message(FATAL_ERROR "Failed to fetch current git branch name.")
        endif()

        # 通过git的tag获取工程的版本号
        execute_process(
            COMMAND
                ${GIT_EXECUTABLE} describe --abbrev=0 --always
            WORKING_DIRECTORY
                ${PROJECT_SOURCE_DIR}
            RESULT_VARIABLE
                GITRET
            OUTPUT_VARIABLE
                GITVERSION
            OUTPUT_STRIP_TRAILING_WHITESPACE
        )

        # 匹配(.、_、-),并替换为;  即将字符串分割成字符串列表
        # 获取到的版本信息如:release-2.2.1-alpha, 总共5段
        string(REGEX REPLACE "[\\._-]" ";" VERSION_LIST "${GITVERSION}")
        if(VERSION_LIST)
            list(LENGTH VERSION_LIST VERSION_LIST_LENGTH)
        endif()

        if ((GITRET EQUAL 0) AND (VERSION_LIST_LENGTH EQUAL 5))
            list(GET VERSION_LIST 1 _MAJOR)
            list(GET VERSION_LIST 2 _MINOR)
            list(GET VERSION_LIST 3 _PATCH)
            list(GET VERSION_LIST 4 _STAGE)

            set(_DEFAULT_VERSION "${${VARPREFIX}_GIT___VERSION_MAJOR}.${${VARPREFIX}_GIT___VERSION_MINOR}.${${VARPREFIX}_GIT___VERSION_PATCH}-${${VARPREFIX}_GIT___VERSION_STAGE}")
            set(_GIT_VERSION     "${_MAJOR}.${_MINOR}.${_PATCH}-${_STAGE}")

            if (${_DEFAULT_VERSION} VERSION_LESS ${_GIT_VERSION})
                set(${VARPREFIX}_VERSION_MAJOR ${_MAJOR})
                set(${VARPREFIX}_VERSION_MINOR ${_MINOR})
                set(${VARPREFIX}_VERSION_PATCH ${_PATCH})
                set(${VARPREFIX}_VERSION_STAGE ${_STAGE})
            endif()
        endif()
    endif()
endmacro()

  以上fetch_version_from_git 宏利用git命令来获取工程的git提交号、分支名、以及版本号。其中版本号是在所打的git tag中获取的,tag名称的格式如下:gitversion-0.1.9-alpha。总共分为3个部分,第一个部分是工程名;第二个部分是版本号,要求格式为主版本号.次版本号.PATCH版本号;第三部分是版本发布阶段,包括rc、alpha、beta、alpha-dev、release、stable等等。

最后获取到的信息放在对应的变量中,其中变量名的前缀由宏的调用者传入,如下:

代码语言:javascript
复制
  ${VARPREFIX}_VERSION_MAJOR - Major version.
  ${VARPREFIX}_VERSION_MINOR - Minor version
  ${VARPREFIX}_VERSION_PATCH - Patch number
  ${VARPREFIX}_VERSION_STAGE - Stage version
  ${VARPREFIX}_COMMITID      - Git commitid
  ${VARPREFIX}_BRANCH        - Git branch

2.5 BuildNumber.cmake文件

代码语言:javascript
复制
# This module defines the following variables to denote 
# new generated buildno
#
#  ${VARPREFIX}_BUILD_NUMBER  - New generated BuildNo
#
# If the build_number.txt file does not exist under 
# ${CMAKE_CURRENT_SOURCE_DIR} directory, a new build_number.txt 
# will be created and the build no will be set to 1, otherwise 
# the build no will increment one by one everytime cmake command 
# is executed.
#
# Example usage:
#
# new_build_number("test")
#    message("        buildno=${test_BUILD_NUMBER}")

macro(new_build_number VARPREFIX)
    if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/build_number.txt")
        file(READ "${CMAKE_CURRENT_SOURCE_DIR}/build_number.txt" ${VARPREFIX}_BUILD_NUMBER)
        string(STRIP ${${VARPREFIX}_BUILD_NUMBER} BUILD_NUMBER)
    else()
        set(${VARPREFIX}_BUILD_NUMBER  1)
    endif()

    # 将 build number 加1
    math(EXPR NEW_BUILD_NUMBER "${${VARPREFIX}_BUILD_NUMBER} + 1")

    # 写入新的 build number 到文件
    file(WRITE "${CMAKE_CURRENT_SOURCE_DIR}/build_number.txt" "${NEW_BUILD_NUMBER}")

endmacro()

   以上宏代码会读取build_number.txt文件中的构建号,加1后从新写回build_number.txt中;如果build_number.txt文件不存在,则会创建一个新的build_number.txt,并将构件号设置为1。读取的构建号放在${VARPREFIX}_BUILD_NUMBER中。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-07-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码农心语 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 2.1 工程目录规划
  • 2.2 c程序文件
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档