Clang — LLVM C++ Compiler
Clang reference for C++ developers: best-in-class diagnostics, fast incremental builds, clang-cl for MSVC compatibility, and sanitizer integration.
TL;DR
Clang is the LLVM C++ compiler. It produces the clearest diagnostic messages of any C++ compiler, is the best platform for sanitizer use (MSan is Clang-only), and acts as the engine behind clangd, clang-tidy, and clang-format. Use Clang 18+ for strong C++23 support; Clang 19+ for C++26 draft features.
# Install (Ubuntu/Debian)
sudo apt install clang-19
# Compile
clang++ -std=c++23 -O2 -Wall -Wextra -o myapp main.cpp
# Dev build with sanitizers
clang++ -std=c++20 -O1 -g -fsanitize=address,undefined \
-fno-omit-frame-pointer -o myapp main.cppKey Clang advantages over GCC:
- Caret diagnostics point to the exact token causing the error
- Fixit hints show the corrected code inline
clang-clmode for Windows MSVC-ABI compatibility- MemorySanitizer (MSan) — Clang-only sanitizer
- Powers the entire LLVM toolchain (clangd, clang-tidy, clang-format)
- Faster incremental builds in many configurations
Installation
Ubuntu / Debian
# Latest stable (LLVM APT repo — preferred over distro packages)
wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh
sudo ./llvm.sh 19
# Or from distro repos (may be older)
sudo apt install clang-19 clang++-19 clang-tools-19
# Set as default
sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-19 100
sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-19 100macOS
# Ships with Xcode Command Line Tools (Apple Clang — based on LLVM, slightly diverged)
xcode-select --install
clang++ --version # Apple clang version 15.x
# Upstream LLVM via Homebrew (recommended for latest features)
brew install llvm
export PATH="$(brew --prefix llvm)/bin:$PATH"
clang++ --version # clang version 19.xWindows
# winget (recommended)
winget install LLVM.LLVM
# Or download installer from releases.llvm.org
# LLVM-19.x.x-win64.exe
# In Developer PowerShell
clang++ --versionDocker
FROM silkeh/clang:19
WORKDIR /app
COPY . .
RUN clang++ -std=c++23 -O2 -Wall -Wextra -o myapp main.cppBasic Usage
Compilation flags
# Essential flags
clang++ -std=c++23 -O2 -Wall -Wextra -Wpedantic -o myapp main.cpp
# Debug build
clang++ -std=c++23 -O0 -g -Wall -Wextra -o myapp main.cpp
# Multiple source files
clang++ -std=c++20 -O2 -I include/ -o myapp src/main.cpp src/utils.cpp
# Compile only (no link)
clang++ -std=c++20 -O2 -c src/main.cpp -o main.o
# Preprocess only (useful for debugging macros)
clang++ -std=c++20 -E main.cpp -o main.iColor diagnostics
Clang enables color output by default when attached to a terminal.
# Force color (e.g. in scripts or pipes)
clang++ -fcolor-diagnostics main.cpp
# Disable color
clang++ -fno-color-diagnostics main.cppDiagnostic Quality
Clang's diagnostics are the clearest in the industry. Every error includes a caret (^) pointing to the exact offending token, plus fixit hints where applicable.
Fixit hints
// Source
#include <iostream>
void greet(std::string name) {
std::cout << "Hello " << name << std::endl;
}
// Clang error (missing header):
// error: use of undeclared identifier 'string'
// ^~~~~~
// note: 'std::string' is defined in header '<string>'; did you forget to '#include <string>'?Template error messages
Template errors in GCC produce hundreds of lines. Clang keeps the stack readable:
# Show template instantiation tree (Clang 16+)
clang++ -fdiagnostics-show-template-tree main.cpp// Example: passing wrong type to a template
std::vector<int> v;
v.push_back("hello");
// Clang:
// error: no matching member function for call to 'push_back'
// note: candidate function not viable: no known conversion from 'const char[6]' to 'int'
//
// GCC: 30+ lines of template instantiation noiseParseable fixits (for tooling)
# Emit fixits in machine-readable format (for editors/scripts)
clang++ -fdiagnostics-parseable-fixits main.cppOutput format:
fix-it:"main.cpp":{5:10-5:10}:"#include <string>\n"Error limit
# Stop after N errors (default: 20)
clang++ -ferror-limit=5 main.cpp
# Show all errors (no limit)
clang++ -ferror-limit=0 main.cppC++ Standards Support
| Standard | Minimum Clang | Flag | Status |
|---|---|---|---|
| C++11 | Clang 3.3 | -std=c++11 | Full |
| C++14 | Clang 3.4 | -std=c++14 | Full |
| C++17 | Clang 5 | -std=c++17 | Full |
| C++20 | Clang 14 | -std=c++20 | Full |
| C++23 | Clang 18 | -std=c++23 | Mostly complete |
| C++26 (draft) | Clang 19 | -std=c++2c | In progress |
GNU extensions
# GNU extensions enabled (default on Linux)
-std=gnu++20
# Strict ISO mode (recommended for portable code)
-std=c++20 -WpedanticCompile-time feature detection
// Check for specific language features
#if __has_feature(cxx_lambdas)
// lambdas available
#endif
// Check for extensions (also covers features in -std=gnu++ mode)
#if __has_extension(cxx_relaxed_constexpr)
// relaxed constexpr available
#endif
// Standard feature-test macros (preferred, portable)
#if __cpp_concepts >= 201907L
// concepts available
#endif
// Check for builtins
#if __has_builtin(__builtin_expect)
#define LIKELY(x) __builtin_expect(!!(x), 1)
#define UNLIKELY(x) __builtin_expect(!!(x), 0)
#endifOptimization Flags
Optimization levels
-O0 # No optimization — fastest compile, largest binary, best for debugging
-O1 # Minimal optimization — good for sanitizer builds
-O2 # Standard release — best balance of speed and compile time (use this)
-O3 # Aggressive — more vectorization, unrolling; profile before choosing over -O2
-Os # Optimize for size — smaller binary than -O2
-Oz # Minimize size — more aggressive than -Os (Clang only)
-Ofast # -O3 + unsafe math (violates IEEE 754); use only if you need itCPU targeting
# Optimize for the build machine's CPU (not portable)
clang++ -O2 -march=native main.cpp
# Target a specific CPU family
clang++ -O2 -march=x86-64-v3 main.cpp # AVX2 (Haswell+)
clang++ -O2 -march=znver4 main.cpp # AMD Zen 4
# Tune scheduling without changing instruction set
clang++ -O2 -march=x86-64 -mtune=skylake main.cpp
# List available values
clang++ -march=help 2>&1 | head -30Link-Time Optimization (LTO)
# ThinLTO — parallel, fast, almost as effective as full LTO (recommended)
clang++ -O2 -flto=thin -o myapp main.cpp lib.cpp
# Full LTO — best optimization, slow link step
clang++ -O2 -flto=full -o myapp main.cpp lib.cpp
# Requires lld for best results
clang++ -O2 -flto=thin -fuse-ld=lld -o myapp main.cpp lib.cppProfile-Guided Optimization (PGO)
# Step 1: Instrument binary
clang++ -O2 -fprofile-generate -o myapp_instr main.cpp
# Step 2: Run with representative workload
./myapp_instr --benchmark-input data.bin
# Step 3: Compile with profile data
clang++ -O2 -fprofile-use=default.profdata -o myapp main.cpp
# Merge multiple profile runs
llvm-profdata merge -output=merged.profdata *.profraw
clang++ -O2 -fprofile-use=merged.profdata -o myapp main.cppSanitizers
Clang has the best sanitizer support of any compiler. MSan is Clang-only.
AddressSanitizer (ASan)
Catches: heap/stack buffer overflows, use-after-free, double-free, memory leaks.
clang++ -fsanitize=address -g -O1 -fno-omit-frame-pointer -o myapp main.cppUndefinedBehaviorSanitizer (UBSan)
Catches: signed integer overflow, null dereference, misaligned access, invalid enum casts.
clang++ -fsanitize=undefined -g -O1 -o myapp main.cpp
# Make all UB fatal (don't continue after first error)
clang++ -fsanitize=undefined -fno-sanitize-recover=all -g -O1 -o myapp main.cppThreadSanitizer (TSan)
Catches: data races between threads. Mutually exclusive with ASan.
clang++ -fsanitize=thread -g -O1 -o myapp main.cppMemorySanitizer (MSan) — Clang only
Catches: use of uninitialized memory. Requires all linked code to be MSan-instrumented.
clang++ -fsanitize=memory -fPIE -pie -g -O1 -o myapp main.cpp
# With origin tracking (slower, but shows where uninitialized memory came from)
clang++ -fsanitize=memory -fsanitize-memory-track-origins=2 -g -O1 -o myapp main.cppCombined sanitizers
# Most useful dev combination
clang++ -fsanitize=address,undefined -g -O1 -fno-omit-frame-pointer -o myapp main.cpp
# For multithreaded code
clang++ -fsanitize=thread,undefined -g -O1 -o myapp main.cpp
# Note: TSan + ASan are incompatible — run in separate buildsSanitizers in CMake
option(ENABLE_ASAN "AddressSanitizer" OFF)
option(ENABLE_UBSAN "UndefinedBehaviorSanitizer" OFF)
option(ENABLE_TSAN "ThreadSanitizer" OFF)
option(ENABLE_MSAN "MemorySanitizer (Clang)" OFF)
function(target_enable_sanitizers target)
set(san_flags "")
if(ENABLE_ASAN)
list(APPEND san_flags -fsanitize=address -fno-omit-frame-pointer)
endif()
if(ENABLE_UBSAN)
list(APPEND san_flags -fsanitize=undefined -fno-sanitize-recover=all)
endif()
if(ENABLE_TSAN)
list(APPEND san_flags -fsanitize=thread)
endif()
if(ENABLE_MSAN)
list(APPEND san_flags -fsanitize=memory -fsanitize-memory-track-origins=2 -fPIE)
endif()
if(san_flags)
target_compile_options(${target} PRIVATE ${san_flags})
target_link_options(${target} PRIVATE ${san_flags})
endif()
endfunction()
# Usage
add_executable(myapp main.cpp)
target_enable_sanitizers(myapp)# Enable from command line
cmake -B build -DCMAKE_CXX_COMPILER=clang++ -DENABLE_ASAN=ON -DENABLE_UBSAN=ON
cmake --build build
./build/myappclang-cl — MSVC Compatibility Mode
clang-cl is a Clang frontend that accepts MSVC-style flags (/std:c++20, /O2, /W4) and produces MSVC-ABI-compatible binaries. It is useful for:
- Cross-compiling Windows code on Linux CI
- Getting Clang's superior diagnostics while targeting the MSVC ABI
- Enabling clang-tidy integration in MSVC projects
Basic usage
REM Windows (Developer Command Prompt or CI)
clang-cl /std:c++20 /O2 /W4 /EHsc /Fe:myapp.exe main.cpp
REM AddressSanitizer with clang-cl
clang-cl /std:c++20 /O1 /Zi /fsanitize=address /Fe:myapp.exe main.cppLinux CI compiling Windows code
# Install cross-compilation toolchain (Ubuntu)
sudo apt install clang-19 lld llvm
# Compile with MSVC-compatible flags on Linux
clang-cl --target=x86_64-pc-windows-msvc /std:c++20 /O2 /EHsc /Fe:myapp.exe main.cpp \
--sysroot=/path/to/msvc/sysrootCMake with clang-cl
# toolchain-clang-cl.cmake
set(CMAKE_C_COMPILER clang-cl)
set(CMAKE_CXX_COMPILER clang-cl)
set(CMAKE_LINKER lld-link)
set(CMAKE_CXX_FLAGS_INIT "/EHsc /W4")cmake -B build --toolchain toolchain-clang-cl.cmake -DCMAKE_BUILD_TYPE=Release
cmake --build buildclang-cl vs cl.exe flag mapping
MSVC (cl.exe) | clang-cl | Notes |
|---|---|---|
/std:c++20 | /std:c++20 | Identical |
/O2 | /O2 | Identical |
/Wall | /Wall | Accepted |
/fsanitize=address | /fsanitize=address | Identical |
/Wno-unused | /Wno-unused | Clang-style also works |
| (none) | -Weverything | Clang extension |
Integration with Build Systems
CMake
# Pass compiler at configure time
CC=clang CXX=clang++ cmake -B build -DCMAKE_BUILD_TYPE=Release ..
# Or as a -D flag
cmake -B build -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
# Generate compile_commands.json (required by clangd, clang-tidy)
cmake -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ONCMake toolchain file
# toolchain-clang.cmake
set(CMAKE_C_COMPILER clang)
set(CMAKE_CXX_COMPILER clang++)
set(CMAKE_LINKER lld)
# Use libc++ instead of libstdc++ (optional)
# set(CMAKE_CXX_FLAGS_INIT "-stdlib=libc++")
# ThinLTO for Release builds
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE ON)
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -flto=thin")cmake -B build --toolchain toolchain-clang.cmakeCMake: compiler-specific flags
add_executable(myapp main.cpp)
target_compile_options(myapp PRIVATE
$<$<CXX_COMPILER_ID:Clang>:
-Wall -Wextra -Wpedantic
-Wshadow -Wconversion -Wold-style-cast
-fcolor-diagnostics
>
$<$<AND:$<CXX_COMPILER_ID:Clang>,$<CONFIG:Release>>:
-O2 -flto=thin
>
)
target_link_options(myapp PRIVATE
$<$<AND:$<CXX_COMPILER_ID:Clang>,$<CONFIG:Release>>:
-flto=thin -fuse-ld=lld
>
)Meson
CC=clang CXX=clang++ meson setup build
meson compile -C build
# Or via native file
cat > native-clang.ini << 'EOF'
[binaries]
c = 'clang'
cpp = 'clang++'
[built-in options]
cpp_std = 'c++20'
EOF
meson setup --native-file native-clang.ini buildClang as a Toolchain Hub
Clang is the engine for the entire LLVM C++ developer toolchain. All of these tools read the same compile_commands.json generated by CMake:
| Tool | Purpose | Depends on |
|---|---|---|
clangd | Language server (LSP) — powers editor features | compile_commands.json |
clang-tidy | Static analysis, linting, auto-fixes | compile_commands.json |
clang-format | Code formatting | .clang-format config |
lldb | Debugger (LLVM's GDB equivalent) | Debug symbols |
llvm-cov | Code coverage | Clang instrumentation |
Generating compile_commands.json
cmake -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
# Symlink to project root so clangd and clang-tidy find it automatically
ln -s build/compile_commands.json compile_commands.jsonWhy clangd needs clang-compiled compile_commands.json
clangd uses the Clang AST internally. When your project uses GCC-specific extensions or -std=gnu++20, clangd may report spurious errors. The cleanest setup is building with Clang so compile_commands.json contains Clang-compatible flags.
# Build with Clang, export compile commands
cmake -B build \
-DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
ln -s build/compile_commands.json .
# clangd and clang-tidy now work with full accuracylibc++ (LLVM's standard library)
# Install libc++
sudo apt install libc++-19-dev libc++abi-19-dev
# Use libc++ instead of libstdc++
clang++ -std=c++20 -stdlib=libc++ -o myapp main.cpp
# Link libc++abi explicitly if needed
clang++ -std=c++20 -stdlib=libc++ -lc++abi -o myapp main.cppUseful Warning Flags
Recommended baseline
# Sensible default for any project
-Wall -Wextra -WpedanticExtra warnings worth enabling
-Wshadow # Local variable shadows outer-scope name
-Wconversion # Implicit narrowing conversions (int → char etc.)
-Wsign-conversion # Signed/unsigned conversion
-Wold-style-cast # C-style casts — use static_cast/reinterpret_cast instead
-Wnull-dereference # Potential null pointer dereference
-Wdouble-promotion # float silently promoted to double
-Wformat=2 # Stricter printf/scanf format string checks
-Wimplicit-fallthrough # Missing [[fallthrough]] in switchRecommended per-project preset
WARN_FLAGS="-Wall -Wextra -Wpedantic \
-Wshadow -Wconversion -Wsign-conversion \
-Wold-style-cast -Wimplicit-fallthrough \
-Wnull-dereference -Wdouble-promotion"
clang++ $WARN_FLAGS -std=c++20 -O2 -o myapp main.cpp-Weverything — audit mode
# Enables ALL Clang warnings — extremely noisy, not for production
# Useful as a one-off audit to find what you might be missing
clang++ -Weverything -Wno-c++98-compat -Wno-padded main.cpp 2>&1 | lessSilencing specific warnings
# Disable a single warning
-Wno-unused-parameter
-Wno-missing-field-initializers
# Promote a warning to an error
-Werror=return-type
-Werror=uninitialized
# Treat all warnings as errors (CI)
-WerrorIn source:
// Suppress for a single line
void func([[maybe_unused]] int unused_param) { }
// Suppress a warning region with pragmas
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wold-style-cast"
int x = (int)some_legacy_value;
#pragma clang diagnostic popMiscellaneous Useful Flags
# Show preprocessed output
clang++ -E main.cpp -o main.i
# Show assembly (annotated with source)
clang++ -S -fverbose-asm -O2 main.cpp -o main.s
# Dump LLVM IR (useful for understanding optimizations)
clang++ -emit-llvm -S -O2 main.cpp -o main.ll
# Show timing breakdown (identify slow TUs)
clang++ -ftime-report main.cpp
# Show all include paths
clang++ -v main.cpp 2>&1 | grep -A20 "#include"
# Use lld (LLVM linker) — faster than GNU ld
clang++ -fuse-ld=lld -O2 -o myapp main.cpp
# Header dependency tracking (for build systems)
clang++ -MD -MF main.d -c main.cpp -o main.o
# Limit memory usage per TU (useful on low-RAM CI)
clang++ -Wl,-z,noexecstack main.cppClang vs GCC — When to Prefer Which
| Situation | Prefer |
|---|---|
| Best error messages | Clang |
| MemorySanitizer (MSan) | Clang (GCC lacks MSan) |
| clangd / clang-tidy / clang-format | Clang |
| MSVC-ABI binaries (clang-cl) | Clang |
| Embedded: ARM, RISC-V, MIPS | GCC (wider arch support) |
| Linux kernel modules | GCC (ABI/attribute requirements) |
| Maximum GCC extension compatibility | GCC |
| ThinLTO build speed | Clang (lld + ThinLTO is faster) |
| New projects on Linux/macOS/Windows | Clang (or test both) |
Run both GCC and Clang in CI — they catch different bugs and have different UB interpretations.
See Also
- clangd — Language server powered by Clang
- clang-tidy — Static analysis and modernization linter
- clang-format — Automated code formatting
- Sanitizers — ASan, UBSan, TSan, MSan in depth
- GCC — GNU Compiler Collection reference
- MSVC — Microsoft Visual C++ reference
- Address Sanitizer — Deep dive into ASan