Professional CMake:

A Practical Guide

Learn to use CMake effectively with practical advice from a CMake co-maintainer. You can also have the author work directly with your team!

C++20 Modules, CMake, And Shared Libraries

CMake 3.28 was the first version to officially support C++20 modules. Tutorials and examples understandably tend to focus on the fairly simple scenario of building a basic executable, perhaps also adding in a static library. The import CMake; the Experiment is Over! blog article from Kitware is perhaps one of the best known, and it covers exactly these things. And while these are important first steps, stopping there sells the reader short. The real fun starts when building, installing, and consuming shared libraries. This quickly exposes current limitations of toolchains and the build system, and it also highlights common misconceptions about what modules provide.

Estimated reading time: 13 minutes

Read more

CppCon 2019: Deep CMake For Library Authors

This talk presents a road map for C++ library authors grappling with cross-platform aspects of library development and deployment. It highlights key CMake features that every cross-platform library project should be using and digs deeper into the platform-specific quirks and conventions behind them. The material presented will give library authors more robust control over their API, smoother integration with major platforms and packaging systems, and more convenient inclusion by other projects.

The presentation will firstly examine how symbol visibility, library versioning and API evolution can be handled coherently across all major platforms and compilers. CMake provides dedicated features for these that are easy to use, but with the deeper understanding provided by this talk, library authors will be able to make these areas work together more seamlessly and avoid future maintenance and compatibility issues.

We will then explore how platform and vendor differences affect the installed directory layout for projects with libraries. CMake features for transparently handling the different conventions and policies will be presented, including recent CMake improvements which simplify this task. The importance of RPATH/RUNPATH functionality for improved runtime robustness and ease of use will also be explained, along with some associated support CMake provides.

Along the way, the talk will mention a number of specific things that CMake library projects should do or avoid to make themselves easy for other projects to consume. This will include versioning support for CMake config package files, guidance on defining install components and accounting for the different ways that projects may incorporate yours into their build.

Read more

CMake And C++ Consulting Services Now Available

Following the successful launch of my book Professional CMake: A Practical Guide last year and receiving positive feedback from readers, I’m pleased to announce that I’ve formed my own consulting company, Crascit Pty Ltd. An overview of the sort of consulting services I will be providing are available on the services page. The general intention though is to make myself available to clients to help them address their CMake, C++ and build/release challenges.

Read more

Avoiding Copies And Moves With auto

When C++11 introduced auto, it opened up a whole range of useful techniques and improved the life of C++ developers in a variety of ways. There’s no shortage of simple examples and tutorials teaching how to start using auto, but as is often the case, many of these well intentioned examples have left readers with an incomplete picture of how to use auto effectively and in some cases have resulted in poor habits becoming common practice. Since auto essentially hides away some of the details of how objects are created, there is a risk that developers don’t think as carefully about what is actually taking place. This article aims to arm the reader with information often omitted so that common pitfalls can be avoided.

Read more

Using ccache with CMake

Updated 1st February 2017

Working with very large C/C++ code bases will sometimes test your patience. Build times in particular can be a sore point, especially if the development team do not have a great understanding of how to minimise dependencies between source files, headers, etc. The problem gets worse if the developer frequently switches between branches of their source control system, resulting in source files often changing their contents and/or timestamps. The ccache tool aims to minimise that pain by caching compilation outputs (i.e. object files) and reusing them instead of compiling the source again if it gets a compilation request it has seen before and cached. It supports GCC or any compiler that looks like GCC (eg clang). When rebuilding a large project that ccache has mostly compiled before already, the time saving can be significant, even sometimes reducing many minutes down to seconds.

Getting ccache to work with CMake is not overly complicated, but the way to do it is not always obvious. This is especially true with Xcode builds. This article demonstrates how to set up a CMake project to use ccache with Unix Makefiles, Ninja or Xcode generators, with Xcode receiving special attention. The techniques presented do not require any changes to the host system. Specifically, no symlinks need to be set up for ccache, making it suitable for use in CI systems, etc. where the developer may not be in control of how/where ccache is installed.

Read more

Member Function Overloading: Choices You Didn’t Know You Had

Let’s explore your understanding of member function overloading. For a given class, how many different non-template overloads can you define for a given function where the function takes no arguments? Putting aside exception specifications (since allowing them would make the answer to this essentially infinite), let’s make this a multiple choice, pick your answer from: 1, 2, 4 or 8. I’ll even provide a clue that the return types of the functions don’t matter. For extra points, how many of the function overloads are likely to be useful?

Read more

Move constructors can copy and std::move doesn’t move anything

I recently came across an interesting use of std::move which looked something like the following:

void MyObject::processItems()
{
    std::vector<int> items(std::move(m_items));
    for (auto item : items)
    {
        // Do things which may add new items to m_items
    }
}

The intent of the code was that every time the member function processItems() was called, it would perform some operation on each item held in the member variable m_items. Each processed item should be removed from m_items. The operation to be performed might generate new items which would be added to m_items, so care had to be taken about how to iterate over the set of items.

To ensure robust iteration over the items to be processed, the code transfers the contents of m_items to a local object and then iterates over that local object. Thus, if new items are created during processing, they would be added to m_items and the container being iterated over (items) would not be affected. All good, right? Well, probably yes, but by no means is it guaranteed.

Read more

OnLeavingScope: The sequel

In a previous article, the OnLeavingScope class was presented as a technique for robustly and concisely handling scenarios involving multi-step setup, run and cleanup stages. It focused on ease of learning and wide applicability rather than performance, so while the implementation was complete, it was not necessarily optimal. This article picks up where the previous article left off and deals with some of the more advanced aspects to provide some improvements.

Read more

Let your compiler do your housekeeping

A common sequence of steps we mortal software developers frequently find ourselves implementing goes something like this:

  1. Perform some sort of setup or acquire some sort of resource.
  2. Carry out some arbitrary sequence of actions.
  3. Tear down things we setup or release resources we acquired in step 1.

There are well-known patterns for implementing this scenario robustly, but when there are multiple sub-steps to be performed in the setup phase and where any of those sub-steps can each fail individually, things get more complicated. This article presents a concise, self-documenting and robust way to handle these more complicated cases. A follow-up article will extend this further to improve some performance characteristics and ends up having a lot in common with the ScopeGuard11 pattern described in various places online.

The multi-step setup problem

Conceptually, the problem we want to solve can be described as follows:

  1. For each setup sub-step:
    • Perform sub-step.
    • If sub-step fails, stop and release/clean up after all previous setup sub-steps.
  2. Carry out some arbitrary sequence of actions.
  3. Tear down things we setup or release resources we acquired in all sub-steps of step 1.

    Read more

Enabling C++11 And Later In CMake

Updated June 2020

With the constant evolution of C++, build systems have had to deal with the complication of selecting the relevant compiler and linker flags. If your project targets multiple platforms and compilers, this can be a headache to set up. Happily, with features added in CMake 3.1, it is trivial to handle this in a generic way.

Read more