Semantic version parser in C++

Semantic version parser in C++

TL;DR

  • C++14 library for parsing and comparing semantic versioning 2.0.0 (semver200) version strings;
  • Git repo: https://github.com/zmarko/semver;
  • Used in production; thoroughly unit tested;
  • MIT license;
  • Flexible design.

Introduction

One of the projects I’m working on (a security monitoring agent) consists of two principal components: an engine that does the actual work and the service that handles startup, shutdown, updates, etc. The service component is expected to be stable and only infrequently updated, while the engine undergoes continuous development and deployment of new versions. As with all such loosely coupled systems, I need a way for different components to know if they can “talk” to each other, i.e. if the public interface between them is not changed.

This is exactly the situation semantic versioning specification is designed to help address.

Not wanting to re-invent the wheel, I start searching Google, GitHub, etc. for C++ (the language the software is being written in) library that can parse and compare semantic version strings. Requirements are really simple:

  • correct implementation of semantic versioning 2.0.0 specification;
  • no external dependencies.

Even though the search came up with a few candidates, none of them fit these requirements, so, off I went rolling my own.

The results of the effort can be accessed here: https://github.com/zmarko/semver.
The code is written in C++14, uses only STL and is released under business-friendly MIT license. It consists of a handful of header and source files and comes with CMake project files that build the library and run a bunch of unit tests.

Usage

All the complexities of string parsing and version comparison according to semver200 specification are hidden behind, hopefully, easy-to-use facade. Comparing version strings should be as easy as:

1
2
3
4
5
6
7
8
9
10
#include "semver200.h"
...
version::Semver200_version v1("1.0.0");
version::Semver200_version v2("2.0.0");

if (v2 > v1) {
std::cout << v2 << " is indeed greater than " << v1 << std::endl;
} else {
std::cout << "This thing is broken, what a waste of time!" << std::endl;
}

It is also possible to access individual version fields:

1
2
3
4
5
6
7
8
#include "semver200.h"
...
version::Semver200_version v("1.2.3-alpha.1+build.no.123");
std::cout << "Major: " << v.major() << std::endl;
std::cout << "Minor: " << v.minor() << std::endl;
std::cout << "Patch: " << v.patch() << std::endl;
std::cout << "Pre-release: " << v.prerelease() << std::endl;
std::cout << "Build: " << v.build() << std::endl;

and the output should be:

1
2
3
4
5
Major: 1
Minor: 2
Patch: 3
Pre-release: alpha.1
Build: build.no.123

Building

The code should build with any C++14-compatible compiler. I have tested it on following platforms:

  • Microsoft Visual Studio 2015
  • GCC 5.1.1
  • Clang 3.7.0

Library itself does not have any external dependencies. Unit tests that verify the library work as expected, on the other hand, depend on the Boost.Test library. If you do not have and do not want to install Boost.Test, then comment out appropriate section of CMakeLists.txt file.

The project comes with CMake project files. In order to build semver library you should:

  • create, if it doesn’t already exist, directory build in the project directory;
  • invoke cmake .. in build directory;
  • once CMake is done, use your toolset (Visual Studio, nmake, make, …) to build the library;
  • remember to link in the library you have built and to include ./include directory to your build.

Advanced usage

Under the hood, the library builds on two major abstractions: parser and comparator. As you can, probably, guess by the names, parser, well, parses strings into Version_data structure and comparator performs comparison of two instances of this structure.

The library comes with semantic versioning 2.0.0 compatible implementations of these interfaces, but, you can write your own parser, comparator or both.

You can check semver200.h header file for signatures and Semver200_comparator.cpp and Semver200_parser.cpp for implementations.

Conclusion

I’d love to hear from you whether you are using this code or you have any comment, issue, bug report or anything else to say on this subject. You can use either comment here or file an issue.