Skip to main content

Compiler

The compiler module configures targets for strict C23 development. It enforces the C23 standard, enables a comprehensive set of warning flags, activates link-time optimization when the toolchain supports it, and controls symbol visibility for libraries.

This configuration implements the requirements defined in ADR-0002 — C as the Core Language, which mandates C23 as the minimum standard with strict warnings treated as errors, and ADR-0005 — CMake as the Build System, which specifies the exact compiler settings that all components must use.

Warning flags

When the module loads, it populates the STRICT_C_WARNING_FLAGS variable with a curated list of compiler flags. These flags are organized by the category of problems they detect.

The base set enables the standard warning groups and treats every warning as an error, enforcing a zero-warnings policy across all components:

FlagPurpose
-WallEnable all common warnings
-WextraEnable extra warnings beyond -Wall
-WpedanticWarn on non-standard C extensions
-WerrorTreat all warnings as errors

Undefined behavior detection flags catch implicit conversions, pointer misuse, and other sources of unpredictable behavior at compile time:

FlagPurpose
-WconversionImplicit type conversions that may lose data
-Wsign-conversionImplicit signed/unsigned conversions
-Wfloat-equalDirect floating-point equality comparisons
-Wcast-qualCasts that remove a type qualifier
-Wcast-alignCasts that increase required alignment
-Wwrite-stringsString literal to non-const pointer conversions
-Wpointer-arithArithmetic on void or function pointers
-Wnull-dereferenceNull dereference paths
-Wdouble-promotionImplicit float to double promotion
-WvlaVariable-length array usage

C-specific correctness flags enforce modern function declaration practices, catching legacy K&R patterns that are a common source of subtle bugs:

FlagPurpose
-Wstrict-prototypesRequire full prototypes in function declarations
-Wmissing-prototypesGlobal functions without a prior prototype
-Wold-style-definitionK&R style function definitions
-Wbad-function-castCasts to mismatched function return types

Logic error flags help catch shadowing, incomplete switch coverage, and undefined preprocessor macros:

FlagPurpose
-WshadowLocal variable shadows another
-Wswitch-enumswitch that doesn't handle all enum values
-WundefUndefined macros used in #if directives

Format string checking is set to its strictest level for security, catching potential buffer overflows and injection vulnerabilities in printf-family calls:

FlagPurpose
-Wformat=2Strict format string checking with security warnings

GCC-specific flags

When the compiler is GCC, additional flags are enabled for deeper static analysis. These take advantage of GCC's more granular control over analysis levels:

FlagPurpose
-Wformat-overflow=2Format string buffer overflows
-Wformat-truncation=2Format string output truncation
-Wformat-signednessFormat string sign mismatches
-Wduplicated-condDuplicated conditions in if-else
-Wduplicated-branchesIdentical if-else branches
-Wlogical-opSuspicious logical operator usage
-Wstrict-aliasing=3Strict type-based alias analysis
-Wstrict-overflow=5Optimizations assuming no signed overflow
-Warray-bounds=2Strict out-of-bounds array access detection
-Wstringop-overflow=4Strict string operation buffer overflow detection
-WtrampolinesTrampoline generation (requires executable stack)
-Wjump-misses-initgoto that skips variable initialization

Clang-specific flags

When the compiler is Clang or AppleClang, a different set of additional flags is enabled. Some overlap with GCC's flags in purpose but use Clang's own analysis:

FlagPurpose
-Wstrict-aliasingType-based aliasing violations
-Wstrict-overflowSigned overflow assumptions
-Warray-boundsOut-of-bounds array access
-Wconditional-uninitializedConditionally uninitialized variables
-Wassign-enumAssigning values outside enum range
-WcommaSuspicious comma operator usage
-Wno-c2y-extensionsSuppress warnings for C2y extensions

The module checks at load time whether the toolchain supports interprocedural optimization (LTO) using CMake's CheckIPOSupported module. The result is stored in STRICT_C_IPO_SUPPORTED. When LTO is supported, target_enable_strict_c23 enables it automatically on every target it configures.

LTO allows the compiler to optimize across translation unit boundaries, producing smaller and faster binaries by eliminating dead code and inlining functions that would otherwise remain opaque.

Symbol visibility

For library targets (static, shared, module, or object), the module sets the C visibility preset to hidden by default. This means only symbols explicitly marked for export are visible to consumers — a best practice that reduces symbol table size and avoids accidental API surface. For executable targets, no visibility preset is set.

You can override the default by passing the VISIBILITY parameter:

add_library(plugin MODULE src/plugin.c)
target_enable_strict_c23(plugin VISIBILITY default)

Function reference

target_enable_strict_c23

target_enable_strict_c23(<target> [VISIBILITY <visibility>])

Configures a target for C23 standard with strict warnings and LTO.

ParameterDescription
targetThe CMake target to configure
VISIBILITYSymbol visibility preset: hidden, default, or protected (optional)

The function sets the C standard to C23 (required), applies all STRICT_C_WARNING_FLAGS as private compile options, enables interprocedural optimization if supported, and sets symbol visibility to hidden for library targets unless VISIBILITY is specified.

add_library(mylib src/mylib.c)
target_enable_strict_c23(mylib)

add_executable(mytool src/main.c)
target_enable_strict_c23(mytool)

add_library(plugin MODULE src/plugin.c)
target_enable_strict_c23(plugin VISIBILITY default)

Variables defined

VariableDescription
STRICT_C_IPO_SUPPORTEDWhether interprocedural optimization (LTO) is supported by the toolchain
STRICT_C_WARNING_FLAGSList of compiler warning flags for strict C compilation