Check If Source Code Can Be Compiled using CMake

Check If Source Code Can Be Compiled using CMake

When working on cross-platform C or C++ projects, you might need to verify whether certain language features or compiler options are supported before using them. For example, a specific C++ attribute or syntax might not be recognized by all compilers or older toolchains. Instead of guessing or hard-coding assumptions, you can let CMake test whether a snippet of source code compiles successfully on the current platform. This tutorial explains how to check if source code can be compiled using CMake.

CMake provides a built-in command called check_source_compiles, which tries to compile a short code snippet and sets a variable based on the result. This lets you conditionally enable or disable specific parts of your code or configuration logic.

Here's an example that checks whether the compiler supports the C++17 [[nodiscard]] attribute:

cmake_minimum_required(VERSION 3.27)
project(myapp)

set(CMAKE_CXX_STANDARD 17)

include(CheckSourceCompiles)

check_source_compiles(CXX "
    [[nodiscard]] int test() { return 1; }
    int main() { test(); return 0; }
" HAVE_CXX17_NODISCARD)

if (HAVE_CXX17_NODISCARD)
    # ...
endif ()

add_executable(${PROJECT_NAME} main.cpp)

When CMake runs, it generates and attempts to compile the provided code. If compilation succeeds, the corresponding variable is set to TRUE. You can then use that variable in CMake logic or define it as a preprocessor macro in the source code.

The first argument to the check_source_compiles command specifies the language to use when compiling the test code. This command supports several languages, including C, CXX, CUDA, Fortran, Swift, and others.

By default, check_source_compiles prints diagnostic messages like:

-- Performing Test HAVE_CXX17_NODISCARD
-- Performing Test HAVE_CXX17_NODISCARD - Success

If you're running several such checks and prefer to keep the output clean, you can silence these messages by setting the CMAKE_REQUIRED_QUIET variable before calling the command:

# ...

set(CMAKE_REQUIRED_QUIET TRUE)

include(CheckSourceCompiles)

check_source_compiles(CXX "
    [[nodiscard]] int test() { return 1; }
    int main() { test(); return 0; }
" HAVE_CXX17_NODISCARD)

# ...

Leave a Comment

Cancel reply

Your email address will not be published.