Compile and Check C and C++ with clang-20
clang-20 can check, assemble and link a program in one command, or pull those stages apart one at a time. This guide walks through both, so when a build breaks you know exactly which stage did it. Allow about 10 minutes for the first run. You need the clang-20 package, a shell, and a writable working directory; none of the commands below needs elevated privileges.
The route
Jump straight to the step you need, or tick off Done means at the end.
1. Confirm the compiler
Check that the command resolves to Clang 20:
clang-20 --version
dpkg-query -W -f='${Package} ${Version}\n' clang-20
On the machine described by this guide, the installed package is clang-20 version 1:20.1.8~++20250804090239+87f0227cb601-1~exp1~20250804210352.139. The compiler identifies itself as Clang 20.1.8 and targets x86_64-pc-linux-gnu. Package versions and the target can differ on another machine, so keep this check with your build notes when reproducibility matters.
2. Check source without creating a program
Create a small C source file in a scratch directory:
mkdir -p "$HOME/clang-20-example"
cd "$HOME/clang-20-example"
cat > hello.c <<'EOF'
#include <stdio.h>
int main(void)
{
puts("hello from clang");
return 0;
}
EOF
Then run only preprocessing, parsing and semantic analysis:
clang-20 -std=c17 -Wall -Wextra -fsyntax-only hello.c
A successful check prints nothing and returns status 0. -fsyntax-only writes neither an object nor an executable. -Wall -Wextra enables useful warning groups, but warnings still aren't failures unless you add -Werror. If Clang reports a source location and an error, fix that diagnostic before moving on. A frequent distraction is a missing header: check the include path and the selected language before touching unrelated flags.
3. Build an executable
Compile and link in one command, naming the output explicitly:
clang-20 -std=c17 -Wall -Wextra -O0 -g hello.c -o hello
./hello
The expected program output is:
hello from clang
With no stage-selection option, the driver compiles the source, assembles the result and invokes the linker. -o hello avoids the less helpful default output name a.out. -g adds debug information, and -O0 keeps optimisation off, which makes source-level debugging easier. Neither option makes a program safe or correct; they only change the generated artefact and its diagnostics.
4. Use the stages separately when diagnosing a build
Produce an object file without linking:
clang-20 -std=c17 -Wall -Wextra -c hello.c -o hello.o
file hello.o
Link that object file into a new executable:
clang-20 hello.o -o hello-from-object
./hello-from-object
Inspect the generated assembly when code generation itself is the question:
clang-20 -std=c17 -O0 -S hello.c -o hello.s
sed -n '1,40p' hello.s
The stages are deliberately cumulative: -E stops after preprocessing, -fsyntax-only stops after semantic analysis, -S emits assembly, and -c emits an object file. Don't confuse a successful -fsyntax-only check with a successful link: missing libraries and duplicate symbols only show up later.
5. Build a C++ file with an explicit standard
Choose the C++ standard and invoke the same driver:
cat > hello.cpp <<'EOF'
#include <iostream>
int main()
{
std::cout << "hello from C++\n";
}
EOF
clang-20 -std=c++20 -Wall -Wextra -O0 -g hello.cpp -o hello-cpp
./hello-cpp
The installed manpage says the default C++ mode is gnu++17. An explicit -std=c++20 makes this build independent of that default and turns off GNU language extensions for the selected standard. Use -std=gnu++20 when the source intentionally depends on those extensions. The available standard-library choice is platform-dependent; -stdlib=libstdc++ and -stdlib=libc++ are the documented choices when both are installed.
6. Inspect a failing or surprising command
Ask the driver to show the commands it would run, without running them:
clang-20 -### -std=c17 -Wall hello.c -o hello
Show include and linker search paths when a dependency can't be found:
clang-20 -v -print-search-dirs
-### is useful for seeing the assembler and linker stages without changing any files. -v prints the tools and paths used during a real invocation. Keep the output when reporting a build problem: it records the selected target and toolchain assumptions. Avoid copying a -Wl, or -Xlinker argument from another machine without checking its linker and target first.
Common traps
- Wrong input language. Use a meaningful suffix such as
.cor.cpp. For generated or extensionless input, select it explicitly with-x cor-x c++; the setting applies to subsequent input files. - Unexpected include files.
-I/pathadds an include directory, whileCPATHand language-specific include-path environment variables also affect lookup. Check them when a build works in one shell but not another. - Overwriting an existing output.
-o helloreplaces that path. Confirm it's the intended file before using it in a script. To undo this guide's changes, remove only the scratch directory withrm -rf -- "$HOME/clang-20-example"after checking its contents; that removal is irreversible and must not be pointed at a directory containing other work. - Optimisation assumptions.
-O3can produce larger code and take longer than-O2. The manpage marks-Ofastas deprecated in Clang 19 because it can enable behaviour that violates strict language standards; use an explicit, justified fast floating-point setting only when its changed rules are acceptable.
Done means
- Compiler confirmed.
clang-20 --versionreports the expected installed compiler. - Syntax checked separately.
-fsyntax-onlychecks the source without producing a binary. - Object and link stages separated.
-cproduces an object and a separate link command produces the executable. - Run confirmed. The executable runs and prints the expected line.
- Build settings explicit. Language standard, warning level, optimisation level and output path are all stated, not left to defaults.