CMake: Can subdirectories inherit compile features?

I have a C++ project that consists of a main program (main.cpp), a header that defines an abstract class (algorithm.hpp), and a subdirectory (algorithms/) full of classes that implement the abstract class. I’ve configured CMake to build the subdirectory as an object library:

# algorithms/CMakeLists.txt
add_library(algorithms_lib OBJECT
  algo1.cpp
  algo2.cpp
  # etc.
)

In my project’s root directory, I use this object library as one of the application’s sources:

# Top-level CMakeLists.txt
cmake_minimum_required(VERSION 3.1)
project(MyApp CXX)

add_subdirectory(algorithms)

add_executable(my-app
  main.cpp
  $<TARGET_OBJECTS:algorithms_lib>
)

My application is written in C++14, so I need to tell CMake to use the correct compile options for that. I don’t want to require CMake version 3.8 (since it’s not packaged in some recent Linux distros that I want to support), so I can’t use the cxx_std_14 compile feature; instead, I’ve listed a bunch of individual language features that I use:

# Top-level CMakeLists.txt (cont.)
target_compile_features(my-app PUBLIC
  cxx_auto_type
  cxx_constexpr
  cxx_defaulted_functions
  # ...14 more lines...
)

The problem is, these features only apply to the top-level my-app target, not the algorithms_lib target, so the sources in the subdirectory don’t get compiled as C++14.

I know I could copy the whole big target_compile_features block into algorithms/CMakeLists.txt, but I’d rather not do that — especially since this example is simplified and I actually have nine such subdirectories, each building its own object library. That’d be a lot of duplication of boilerplate code.

Is there a way to set compile features globally for all C++ targets in the project, including subdirectories? Or would it be better to get rid of add_subdirectory and the object library, and just list all the individual subdirectory files in the top-level add_executable command? I’m new to CMake, so I don’t know what the “best practices” are for this sort of thing.

Answer

It sounds like you want to put the following at the top of your CMakeLists.txt file:

set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

These set defaults for the same-named target properties without the leading CMAKE_. The equivalent target properties do the following:

CXX_STANDARD yy sets the desired minimum C++ standard your code wants to use.

CXX_STANDARD_REQUIRED bb says whether CXX_STANDARD is a requirement (bb is YES or some other boolean equivalent) or whether it is just desirable (bb is NO or equivalent).

CXX_EXTENSIONS bb enables (bb = YES) or disables (bb = NO) compiler extensions.

You don’t need to specify individual compiler features to achieve what you’re ultimately trying to do (enable C++14 for your targets). You can find a full discussion of this whole area here.

Leave a Reply

Your email address will not be published. Required fields are marked *