–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:
- Log output of
--version
directly on every start: When a log lives longer than the version of the corresponding binary, it’s easier for error tracing. - Monitor deployed version: Having a lot of servers running different versions of a binary, it becomes easier to export the version using the version-flag.
- Distinguish binaries: Having multiple version of a binary at ones, it’s easier to distinguish them by version/date.
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:
- name
- package
- version
- target distro
- target distro version
- license
- author
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:
- last commit message
- last committer
- version of the compiler/runtime
- target platform