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)

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.2s)

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)