blog. feed tags

CMake can omit the C standard flag

· c, cmake

Summary

After a recent system update, I started getting an error in my text editor: “unknown type name bool.” I fixed this by adding the following to CMakeLists.txt:

set_property(TARGET <target> PROPERTY C_STANDARD_REQUIRED ON)

Why it happened

This error was pretty surprising for a few reasons, not least because the project still compiled fine!

My codebase compiles under the C23 standard, where bool is a built-in type. This isn’t valid under previous C standards, though, where bool is a macro that’s created by the <stdbool.h> header.

CMake defaults to using the system compiler. Here, that’s GCC. After the system update, GCC defaulted to compiling code under the C23 standard.

GCC then defaults to compiling code under the C23 standard, and CMake knows this and omits -std=c23 by default.

However, my IDE isn’t using GCC’s language server for diagnostics (because GCC doesn’t have one); it’s using the clangd language server. So how does clangd know which language standard to interpret your codebase as?

Because this is C, the compiler is given command-line options by various nonstandard turing-complete build runners. Language servers can’t really hook into this, as they’re started by the editor and don’t really want to interface with the build system mess.

To solve this, Manuel Klimek proposed exporting compile_commands.json (then cxx_commands.json) from CMake. Later, this was gated behind the CMAKE_EXPORT_COMPILE_COMMANDS variable, which can be enabled by adding -DCMAKE_EXPORT_COMPILE_COMMANDS=ON to your command-line CMake invocation.

This file provides each source file’s compiler arguments. In my case, it looked something like this:

[
	{
		"directory": [...],
		"command": "/usr/bin/cc -g -Wall -Wextra -Werror -fsanitize=undefined -o [...]/file.c.o -c [...]/file.c",
		"file": [...],
		"output": [...]
	}
]

Importantly, clangd is from Clang infrastructure. This means it (re-)uses Clang’s command-line argument parsing! And when CMake omits the -std=c23 flag, Clang compiles under its default standard: C17.

The fix

Enabling the C_STANDARD_REQUIRED target property tells CMake to never omit this flag; the corresponding target property for C++ is CXX_STANDARD_REQUIRED.