You Should Add FeatureSummary to your CMake Projects

Here's a common problem: your cmake build is failing with linker errors, and now your're looking through your CMake logs and reading the compilation database to see what libraries were actually included.

What if I told you that there was a better way? Enter Feature Summary.

Basic Usage

The FeatureSummary module has two parts

  • add_feature_info(<name>, <condition>, <description>) to add entries to the summary.
  • feature_summary(WHAT ALL) to print the summary.

In short, add include(FeatureSummary) to make the commands available to downstream modules, then when declaring options, add them to the summary with add_feature_info.

cmake_minimum_required(VERSION 3.28)
project(FeatureSummaryExample)

include(FeatureSummary)

# Will be reported in the feature summary without further intervention
find_package(Threads REQUIRED)
find_package(Catch2 3)

# Create an option, and add it to feature summary
option(WERROR "Enable -Werror to turn warnings into errors" False)
add_feature_info(
    Werror WERROR "Enable -Werror to turn warnings into errors"
)

option(RUN_CLANG_TIDY "Run clang-tidy as part of the build" False)
add_feature_info(
    "Run Clang Tidy" RUN_CLANG_TIDY "Run clang tidy as part of the build"
)

# Print the feature summary
feature_summary(WHAT ALL)

Best Practices

You should wait until the very end of your CMake file to call feature_summary. It will only print changes made to that point, so if you call too early, the result may not reflect the final state of the build.

When you run cmake, the options you set (or did not set) will be printed out:

-- The following features have been enabled:

 * Werror, Enable -Werror to turn warnings into errors

-- The following REQUIRED packages have been found:

 * Threads

-- The following features have been disabled:

 * Run Clang Tidy, Run clang tidy as part of the build

-- The following OPTIONAL packages have not been found:

 * Catch2 (required version >= 3)

-- Configuring done (0.4s)

Making it Less Verbose

Having to declare an option and then calling add_feature_info each time quickly becomes tedious. A quick script can improve this significantly.

include(FeatureSummary)

function(add_feature_option
    _variable_name
    _option_description
    _option_default
)
    if(NOT DEFINED default)
        set(default OFF)
    endif()

    # option(<variable> "<help_text>" [value])
    option(${_variable_name} ${_option_description} ${_option_default})

    # add_feature_info(<name> <enabled> <description>)
    set(_option_value ${${_variable_name}})
    add_feature_info(
        "${PROJECT_NAME}::${_variable_name}"
        ${_option_value}
        ${_option_description}
    )
endfunction()

This function declares the option, and adds it to the feature summary in a single pass, saving us quite some typing (and ensuring that all options are always in the feature summary).

cmake_minimum_required(VERSION 3.28)
project(FeatureSummaryExample)

include(FeatureSummary)
include(AddFeatureOption)

# Will be reported in the feature summary without further intervention
find_package(Catch2 3 QUIET)

# Create an option, and add it to feature summary
add_feature_option(
    WERROR "Enable -Werror to turn warnings into errors" False
)
add_feature_option(
    RUN_CLANG_TIDY "Run clang-tidy as part of the build" False
)

# Print the feature summary
feature_summary(WHAT ALL)