< up >
2021-01-12

–version always

Am I in the matrix?

Which sounds like a quote is the result of hours testing and debugging with development releases. When things get messy and intransparent, it’s always good to have a --version printing some build information. Where build information is defined as date and version in this post. Since version control is a industry standard, the last commit sha can be used as version if no other version system is used.

Bonus:

Contents

Example

$ ./blogctl --version

BuildVersion:  v0.1.3-10-ge84a71f
BuildDate:  2020-12-05T17:17:56+0100
$ ./femto --version
BuildDate: 2020-09-16T15:08:11+0200
BuildVersion: v0.4.0-3-g8a901a5

Linux variant

The linux variant includes a subset of:

Like gcc or bash:

$ gcc --version
gcc (GCC) 10.2.1 20201125 (Red Hat 10.2.1-9)
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ bash --version
GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ md5sum --version
md5sum (GNU coreutils) 8.30
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Ulrich Drepper, Scott Miller, and David Madore.

Others

Docker with version and build hash:

$ docker --version
Docker version 19.03.12, build 48a66213fe

Gpg which looks like the linux variant but with all supported algorithms on top:

$ gpg --version
gpg (GnuPG) 2.2.19
libgcrypt 1.8.5
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Home: /root/.gnupg
Supported algorithms:
Pubkey: RSA, ELG, DSA, ECDH, ECDSA, EDDSA
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
        CAMELLIA128, CAMELLIA192, CAMELLIA256
Hash: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed, ZIP, ZLIB, BZIP2

Vim with its verbose output:

$ vim --version
VIM - Vi IMproved 8.1 (2018 May 18, compiled Apr 15 2020 06:40:31)
Included patches: 1-2269
Modified by team+vim@tracker.debian.org
Compiled by team+vim@tracker.debian.org
Huge version without GUI.  Features included (+) or not (-):
+acl               -farsi             -mouse_sysmouse    -tag_any_white
+arabic            +file_in_path      +mouse_urxvt       -tcl
+autocmd           +find_in_path      +mouse_xterm       +termguicolors
+autochdir         +float             +multi_byte        +terminal
-autoservername    +folding           +multi_lang        +terminfo
-balloon_eval      -footer            -mzscheme          +termresponse
+balloon_eval_term +fork()            +netbeans_intg     +textobjects
-browse            +gettext           +num64             +textprop
++builtin_terms    -hangul_input      +packages          +timers
+byte_offset       +iconv             +path_extra        +title
+channel           +insert_expand     -perl              -toolbar
+cindent           +job               +persistent_undo   +user_commands
-clientserver      +jumplist          +postscript        +vartabs
-clipboard         +keymap            +printer           +vertsplit
+cmdline_compl     +lambda            +profile           +virtualedit
+cmdline_hist      +langmap           -python            +visual
+cmdline_info      +libcall           +python3           +visualextra
+comments          +linebreak         +quickfix          +viminfo
+conceal           +lispindent        +reltime           +vreplace
+cryptv            +listcmds          +rightleft         +wildignore
+cscope            +localmap          -ruby              +wildmenu
+cursorbind        -lua               +scrollbind        +windows
+cursorshape       +menu              +signs             +writebackup
+dialog_con        +mksession         +smartindent       -X11
+diff              +modify_fname      +sound             -xfontset
+digraphs          +mouse             +spell             -xim
-dnd               -mouseshape        +startuptime       -xpm
-ebcdic            +mouse_dec         +statusline        -xsmp
+emacs_tags        +mouse_gpm         -sun_workshop      -xterm_clipboard
+eval              -mouse_jsbterm     +syntax            -xterm_save
+ex_extra          +mouse_netterm     +tag_binary        
+extra_search      +mouse_sgr         -tag_old_static    
   system vimrc file: "$VIM/vimrc"
     user vimrc file: "$HOME/.vimrc"
 2nd user vimrc file: "~/.vim/vimrc"
      user exrc file: "$HOME/.exrc"
       defaults file: "$VIMRUNTIME/defaults.vim"
  fall-back for $VIM: "/usr/share/vim"
Compilation: gcc -c -I. -Iproto -DHAVE_CONFIG_H   -Wdate-time  -g -O2 -fdebug-prefix-map=/build/vim-iU6mZD/vim-8.1.2269=. -fstack-protector-strong -Wformat -Werror=format-security -D_REENTRANT -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1       
Linking: gcc   -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -o vim        -lm -ltinfo -lnsl  -lselinux  -lcanberra -lacl -lattr -lgpm -ldl     -L/usr/lib/python3.8/config-3.8-x86_64-linux-gnu -lpython3.8 -lcrypt -lpthread -ldl -lutil -lm -lm   

Implementation

Having compiled languages like Go or C, the build date and version can be added at the build process by setting the corresponding variables.

For the date one can use date '+%Y-%m-%dT%H:%M:%S%z' and the latest commit sha as version via git describe --always.

Go

The variables BuildDate and BuildVersion can be set during a go build like the following: go build -ldflags "-X main.BuildDate=<date> -X main.BuildVersion=<version>"

package main

import (
  "flag"
  "fmt"
)

var (
  BuildDate    string
  BuildVersion string
  Version      = flag.Bool("version", false, "Print build information")
)

func main() {
  flag.Parse()
  if *Version {
    fmt.Println("BuildVersion: ", BuildVersion)
    fmt.Println("BuildDate: ", BuildDate)
  }
}

C

With the gcc version and date can be added as key-value pair using the -D prefix like the following: gcc -DBUILD_DATE="\"DATE\"" -DBUILD_VERSION="\"VERSION\"" main.c

Where main.c looks like this:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#ifndef BUILD_DATE
#define BUILD_DATE "BUILD_DATE is missing"
#endif

#ifndef BUILD_VERSION
#define BUILD_VERSION "BUILD_VERSION is missing"
#endif

int main( int argc, char*argv[] ) {
  if( argc > 1 && strcmp( argv[1], "--version" ) == 0 ) {
    printf( "BuildDate: %s\n", BUILD_DATE );
    printf( "BuildVersion: %s\n", BUILD_VERSION );
  }

  return 0;
}

Further ideas

Some inspiration which variables could be added to the build information: