GCC
GCC command-line cheatsheet from first compilation to debugging, linking, optimization, and production builds.
GCC Cheatsheet
GCC is the GNU Compiler Collection. For ordinary projects:
| Command | Use It For |
|---|---|
gcc | Compile and link C programs |
g++ | Compile and link C++ programs; automatically links the C++ standard library |
cpp | Run only the C/C++ preprocessor |
gcov | Read coverage data generated by GCC |
The basic pattern is:
gcc [options] input.c -o output
g++ [options] input.cpp -o outputExamples on this page use Unix-style executable names (./app). On Windows with MinGW, run the output as app.exe.
1. Beginner: Compile and Run
First C Program
// hello.c
#include <stdio.h>
int main(void) {
puts("Hello, GCC!");
return 0;
}gcc hello.c -o hello # Compile and link
./hello # Run on Linux/macOSFirst C++ Program
// hello.cpp
#include <iostream>
int main() {
std::cout << "Hello, GCC!\n";
}g++ hello.cpp -o hello # Use g++ for C++ linking
./helloEssential Commands
| Command | Meaning |
|---|---|
gcc main.c | Build C program as a.out (a.exe on some Windows setups) |
gcc main.c -o app | Name the output executable app |
gcc -std=c17 main.c -o app | Compile using the C17 language standard |
g++ -std=c++20 main.cpp -o app | Compile C++20 source |
gcc --version | Print GCC version |
gcc -v main.c -o app | Show commands and paths used while building |
Recommended Learning Build
gcc -std=c17 -Wall -Wextra -Wpedantic -g main.c -o app| Flag | Purpose |
|---|---|
-std=c17 | Select a defined C standard |
-Wall | Enable many common warnings |
-Wextra | Enable additional useful warnings |
-Wpedantic | Warn about non-standard language extensions |
-g | Include debug information for a debugger |
Warnings are not failures by default. Fix warnings instead of ignoring them.
2. How Compilation Works
GCC usually performs four stages:
source.c -> preprocessed source -> assembly -> object file -> executable
preprocessing compile assemble link| Stage | GCC Option | Typical Output | What Happens |
|---|---|---|---|
| Preprocess | -E | .i | Expands #include, #define, and conditional compilation |
| Compile | -S | .s | Translates C/C++ into assembly |
| Assemble | -c | .o | Produces machine-code object file without linking |
| Link | default final step | executable/library | Resolves functions and combines object files/libraries |
gcc -E hello.c -o hello.i # Stop after preprocessing
gcc -S hello.c -o hello.s # Stop after generating assembly
gcc -c hello.c -o hello.o # Stop after object file
gcc hello.o -o hello # Link object into executableKeep Intermediate Files
gcc -save-temps hello.c -o helloThis is useful when learning, investigating macros, or inspecting generated assembly.
3. Common Option Reference
Input and Output
| Option | Example | Purpose |
|---|---|---|
-o file | -o calculator | Set output filename |
-c | gcc -c util.c | Compile only; do not link |
-E | gcc -E config.c | Preprocess only |
-S | gcc -S math.c | Generate assembly |
-x language | gcc -x c input.txt | Treat input as a particular language |
-pipe | gcc -pipe main.c | Use pipes between compilation stages where supported |
Standards
| Language | Common Selection |
|---|---|
| C90 | -std=c90 |
| C11 | -std=c11 |
| C17 | -std=c17 |
| GNU C17 extensions | -std=gnu17 |
| C++17 | -std=c++17 |
| C++20 | -std=c++20 |
| GNU C++20 extensions | -std=gnu++20 |
-std=c17 is stricter and more portable; -std=gnu17 also allows GNU extensions commonly used on Linux.
Macros and Include Paths
| Option | Example | Purpose |
|---|---|---|
-DNAME | -DDEBUG | Define macro with value 1 |
-DNAME=value | -DPORT=8080 | Define macro with a value |
-UNAME | -UDEBUG | Undefine a macro |
-I dir | -Iinclude | Add header search directory |
-iquote dir | -iquote src/include | Search directory for quoted includes only |
-isystem dir | -isystem vendor/include | Add system header directory with reduced warning noise |
#ifdef DEBUG
fprintf(stderr, "x = %d\n", x);
#endifgcc -DDEBUG -Iinclude src/main.c -o app4. Warnings and Diagnostics
Sensible Warning Sets
# Everyday C development
gcc -std=c17 -Wall -Wextra -Wpedantic -Wconversion -Wshadow main.c -o app
# Everyday C++ development
g++ -std=c++20 -Wall -Wextra -Wpedantic -Wconversion -Wshadow main.cpp -o app
# Continuous integration: reject newly introduced warnings
gcc -std=c17 -Wall -Wextra -Wpedantic -Werror main.c -o app| Option | Catches or Controls |
|---|---|
-Wall | Frequently useful warnings such as unused values and suspicious constructs |
-Wextra | Additional parameter, comparison, and initializer warnings |
-Wpedantic | Extensions beyond the selected standard |
-Wconversion | Implicit conversions that may alter a value |
-Wsign-conversion | Signed/unsigned conversions |
-Wshadow | Declarations hiding earlier names |
-Wformat=2 | Stricter printf/scanf format checking |
-Wundef | Unknown identifiers used in preprocessor #if expressions |
-Werror | Treat warnings as errors |
-Wno-error=name | Keep one warning non-fatal under -Werror |
-Wall does not mean every possible warning. Strong warning flags can be noisy on legacy or third-party code, so introduce them deliberately.
More Readable Errors
gcc -fdiagnostics-color=always -fdiagnostics-show-option main.c -o app
gcc -fmax-errors=5 main.c -o app| Option | Purpose |
|---|---|
-fdiagnostics-color=always | Colorize compiler output when the terminal supports it |
-fdiagnostics-show-option | Show the warning flag associated with a message |
-fmax-errors=n | Stop after n errors |
5. Debug Builds
Debug Build Recipe
gcc -std=c17 -Wall -Wextra -Wpedantic -g -O0 main.c -o app
gdb ./app| Option | Purpose |
|---|---|
-g | Generate debugger information |
-ggdb | Generate debugging information tailored for GDB |
-O0 | Turn off most optimization for straightforward stepping |
-Og | Optimize while preserving a useful debugging experience |
-fno-omit-frame-pointer | Make stack traces/profiling easier on many targets |
For most active debugging, this is a useful balance:
gcc -std=c17 -Wall -Wextra -g3 -Og -fno-omit-frame-pointer main.c -o appUseful Debug Tools
gdb ./app # Interactive debugger
gcc -E main.c | less # Inspect expanded macros/includes
gcc -S -fverbose-asm main.c # Assembly with compiler comments
gcc -H -c main.c # Print included header hierarchy6. Finding Memory and Undefined-Behavior Bugs
Sanitizers add runtime checks. Use them in testing and debugging builds, not as your usual optimized production binary.
Address and Undefined Behavior Sanitizers
gcc -std=c17 -Wall -Wextra -g -Og \
-fsanitize=address,undefined -fno-omit-frame-pointer \
main.c -o app
./app| Sanitizer | Option | Detects Examples |
|---|---|---|
| AddressSanitizer | -fsanitize=address | Out-of-bounds access, use-after-free, some leaks |
| UndefinedBehaviorSanitizer | -fsanitize=undefined | Invalid shifts, signed overflow, misaligned access |
| LeakSanitizer | -fsanitize=leak | Heap allocations not released |
| ThreadSanitizer | -fsanitize=thread | Data races in multithreaded programs |
Do not combine -fsanitize=thread with -fsanitize=address in the same executable. Sanitizer availability and behavior depend on the target platform and GCC installation.
Static Analysis
gcc -std=c17 -Wall -Wextra -fanalyzer -c main.c-fanalyzer explores paths through code to report issues such as double-free, null dereference, and some resource leaks. It can be slower and may need judgment when reviewing results.
7. Multiple Source Files
Small Project Layout
project/
include/math_utils.h
src/main.c
src/math_utils.c# One command: compile and link everything
gcc -std=c17 -Wall -Wextra -Iinclude \
src/main.c src/math_utils.c -o app
# Separate compilation: rebuild only changed files
gcc -std=c17 -Wall -Wextra -Iinclude -c src/main.c -o main.o
gcc -std=c17 -Wall -Wextra -Iinclude -c src/math_utils.c -o math_utils.o
gcc main.o math_utils.o -o appHeader Dependency Generation
When a header changes, its dependent source files must be rebuilt. GCC can generate dependency rules for make:
gcc -std=c17 -Wall -Wextra -MMD -MP -Iinclude -c src/main.c -o main.o| Option | Purpose |
|---|---|
-MMD | Write a .d dependency file for user headers |
-MP | Add dummy targets so removed headers do not break old dependency files |
-MF file | Choose dependency output file |
-MT target | Choose dependency rule target name |
8. Linking Libraries
Link a System Library
gcc main.c -lm -o app # Link libm for functions such as sqrt() on Unix-like systems
gcc main.c -pthread -o app # Compile/link POSIX threads where supported| Option | Purpose |
|---|---|
-lNAME | Link a library named like libNAME.so or libNAME.a |
-Ldir | Add a library search directory |
-pthread | Enable and link thread support on compatible systems |
-Wl,option | Pass comma-separated option(s) to the linker |
For traditional linkers, put libraries after object files that need them:
gcc main.o geometry.o -Llib -lshape -lm -o appCreate a Static Library
gcc -std=c17 -O2 -Iinclude -c src/math_utils.c -o math_utils.o
ar rcs libmathutils.a math_utils.o
gcc main.o -L. -lmathutils -o appStatic libraries are copied into the final executable as required during linking.
Create a Shared Library on Linux
gcc -std=c17 -O2 -fPIC -Iinclude -c src/math_utils.c -o math_utils.o
gcc -shared math_utils.o -o libmathutils.so
gcc main.o -L. -lmathutils -Wl,-rpath,'$ORIGIN' -o app| Option | Purpose |
|---|---|
-fPIC | Generate position-independent code commonly required for shared libraries |
-shared | Produce a shared library rather than an executable |
-Wl,-rpath,... | Embed a runtime library search path; use with care when packaging |
Shared-library commands and filename conventions differ on Windows and macOS.
9. Optimization and Release Builds
Optimization Levels
| Option | Typical Use | Notes |
|---|---|---|
-O0 | Initial debugging | Fast compile; easiest source-level stepping |
-Og | Debugging with reasonable performance | Keeps many debugging expectations intact |
-O1 | Light optimization | Smaller optimization cost |
-O2 | General release build | Strong default for many applications |
-O3 | Benchmark-driven performance work | Can increase size; measure results |
-Os | Optimize for size | Useful for constrained binaries |
-Ofast | Aggressive performance | May relax language/IEEE math guarantees |
Release Build Recipe
gcc -std=c17 -O2 -DNDEBUG -Wall -Wextra main.c -o app-DNDEBUG disables the standard assert() macro. Use it only when removing runtime assertions is appropriate for the release.
Link-Time Optimization (LTO)
gcc -std=c17 -O2 -flto -c main.c -o main.o
gcc -std=c17 -O2 -flto -c util.c -o util.o
gcc -O2 -flto main.o util.o -o app-flto allows optimization across translation units. Use it consistently for compile and link steps, then measure compile time, binary size, and performance.
Target-Specific Code Generation
gcc -O2 -march=native main.c -o app-march=native may use instructions available only on the build machine. It is useful for local performance tests, but usually wrong for binaries distributed to different computers.
10. Coverage and Profiling
Code Coverage with gcov
gcc -std=c17 -O0 -g --coverage main.c -o app
./app
gcov main.c--coverage instruments the program and produces files that gcov uses to show which source lines executed. Run representative tests before reading coverage.
Profile-Guided Optimization (PGO)
# 1. Build an instrumented program
gcc -O2 -fprofile-generate main.c -o app
# 2. Run realistic workloads
./app input.txt
# 3. Rebuild using measured behavior
gcc -O2 -fprofile-use main.c -o appPGO is useful only when the training runs resemble real use. Keep profile data aligned with the same source and build configuration.
11. Preprocessor Workflows
Define Build Configurations
gcc -DDEBUG -DLOG_LEVEL=2 main.c -o debug_app
gcc -DNDEBUG -DAPP_VERSION='"1.2.0"' main.c -o release_app#if defined(DEBUG)
#define LOG(message) fprintf(stderr, "%s\n", message)
#else
#define LOG(message) ((void)0)
#endifInspect Predefined Macros
gcc -dM -E - < /dev/null # Unix shell: built-in C macros
gcc -std=c17 -dM -E - < /dev/null # Include selected standard modeOn PowerShell, a comparable empty input pipeline is:
'' | gcc -std=c17 -dM -E -Include Search and Macro Investigation
gcc -E -Iinclude src/main.c -o main.i
gcc -v -E -x c /dev/null # Print configured include search paths on Unix
gcc -H -Iinclude -c src/main.c # Trace headers being included12. C Versus C++ with GCC
| Task | C | C++ |
|---|---|---|
| Compile and link | gcc main.c -o app | g++ main.cpp -o app |
| Standard | -std=c17 | -std=c++20 |
| Object compile | gcc -c file.c | g++ -c file.cpp |
| Link object files containing C++ | Prefer g++ | g++ *.o -o app |
GCC can compile a .cpp file when invoked as gcc, but the final link step does not automatically add the C++ standard library. Use g++ for C++ executables:
g++ -std=c++20 main.cpp widget.cpp -o appLink C Code into C++
/* math_api.h */
#ifdef __cplusplus
extern "C" {
#endif
int add(int a, int b);
#ifdef __cplusplus
}
#endifextern "C" prevents C++ name mangling for APIs implemented in C.
13. Hardening and Production Checks
For applications that accept untrusted input, compiler flags can add defense in depth. The suitable combination depends on target operating system, libc, deployment requirements, and performance budget.
gcc -std=c17 -O2 -Wall -Wextra \
-fstack-protector-strong -D_FORTIFY_SOURCE=2 \
-fPIE -pie main.c -o app| Option | Purpose |
|---|---|
-fstack-protector-strong | Add stack corruption checks to more vulnerable functions |
-D_FORTIFY_SOURCE=2 | Add some checked libc operations when optimization and libc support are available |
-fPIE -pie | Build a position-independent executable for address randomization support |
-Wl,-z,relro,-z,now | Request additional ELF/Linux linker hardening |
Sanitizers help find bugs during testing; hardening options help make some bugs harder to exploit in deployed builds. Neither replaces input validation, correct ownership, or testing.
14. Advanced Compiler Inspection
Ask GCC About Available Options
gcc --help=warnings
gcc --help=optimizers
gcc --help=target
gcc -Q -O2 --help=optimizers-Q -O2 --help=optimizers is useful for inspecting which optimization switches GCC enables for the selected compiler and target.
Inspect Assembly Output
gcc -std=c17 -O2 -S main.c -o main.s
gcc -std=c17 -O2 -S -masm=intel main.c -o main.s # Supported on x86 targets
gcc -std=c17 -O2 -fverbose-asm -S main.c -o main.sSymbols and Binary Information on Unix-like Systems
nm app # List symbols
objdump -d app # Disassemble
readelf -h app # ELF header information
ldd app # Shared library dependencies on LinuxThese commands are provided by binutils or the operating system rather than by GCC itself.
15. A Practical Makefile with GCC
CC := gcc
CPPFLAGS := -Iinclude
CFLAGS := -std=c17 -Wall -Wextra -Wpedantic -MMD -MP
LDLIBS :=
TARGET := app
SOURCES := src/main.c src/math_utils.c
OBJECTS := $(SOURCES:.c=.o)
DEPENDS := $(OBJECTS:.o=.d)
.PHONY: all debug release clean
all: debug
debug: CFLAGS += -g -Og -fsanitize=address,undefined -fno-omit-frame-pointer
debug: LDFLAGS += -fsanitize=address,undefined
debug: $(TARGET)
release: CFLAGS += -O2 -DNDEBUG
release: $(TARGET)
$(TARGET): $(OBJECTS)
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
src/%.o: src/%.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
clean:
rm -f $(TARGET) $(OBJECTS) $(DEPENDS)
-include $(DEPENDS)Run:
make debug
make clean
make releaseFor larger projects, build into a separate directory so debug and release object files cannot be accidentally mixed.
16. Common Errors and Fixes
| Message or Symptom | Likely Cause | Typical Fix |
|---|---|---|
fatal error: foo.h: No such file or directory | Header search path missing | Add -Ipath/to/headers or fix include |
undefined reference to 'foo' | Declaration found, implementation not linked | Add its .o file or -l library |
undefined reference to 'sqrt' | Math library not linked on Unix-like system | Put -lm after object/source files |
multiple definition of 'x' | Global definition placed in multiple files/headers | Put extern declaration in header and one definition in a .c file |
C++ undefined reference to std::... | Linked C++ program using gcc | Link with g++ |
| Program crashes only at runtime | Memory bug or undefined behavior | Rebuild with -g -fsanitize=address,undefined |
| Debugger skips lines or variables vanish | Optimization changes program layout | Use -Og or -O0 for debugging |
| Works locally, fails on another CPU | Built with host-specific instructions | Avoid -march=native for distributed binaries |
Link Command Ordering
# Good: objects first, dependent libraries later
gcc main.o -L. -lutils -lm -o app
# Can fail with traditional static linking order
gcc -lutils -lm main.o -o app17. Copy-Paste Build Recipes
C Development
gcc -std=c17 -Wall -Wextra -Wpedantic -Wconversion -g -Og main.c -o appC Debugging with Sanitizers
gcc -std=c17 -Wall -Wextra -g -Og \
-fsanitize=address,undefined -fno-omit-frame-pointer \
main.c -o appC Release
gcc -std=c17 -Wall -Wextra -O2 -DNDEBUG main.c -o appC++ Development
g++ -std=c++20 -Wall -Wextra -Wpedantic -g -Og main.cpp -o appBuild with Headers and Multiple Files
gcc -std=c17 -Wall -Wextra -Iinclude \
src/main.c src/io.c src/math_utils.c -o appCompile Objects and Link Separately
gcc -std=c17 -Wall -Wextra -Iinclude -c src/io.c -o io.o
gcc -std=c17 -Wall -Wextra -Iinclude -c src/main.c -o main.o
gcc main.o io.o -o app18. Learning Path and Quick Recall
Beginner
- Compile one
.cfile withgcc file.c -o app. - Always enable
-Wall -Wextraand select a standard such as-std=c17. - Learn what preprocessing, compilation, assembly, and linking do.
- Use
-g -Ogand a debugger instead of adding endless print statements.
Intermediate
- Split a program into headers and source files, compiling with
-c. - Link libraries with
-Land-l, and understand link ordering. - Add dependency generation using
-MMD -MPin a Makefile. - Run sanitizer builds regularly and fix every real diagnostic.
Advanced
- Inspect generated assembly and optimization choices.
- Measure
-O2,-O3, LTO, and PGO rather than assuming they are faster. - Build shared/static libraries and control their public API.
- Add platform-appropriate hardening and automated warning/sanitizer builds.
Recall Card
Build C: gcc -std=c17 -Wall -Wextra file.c -o app
Build C++: g++ -std=c++20 -Wall -Wextra file.cpp -o app
Compile only: gcc -c file.c -o file.o
Link: gcc main.o util.o -lm -o app
Debug: gcc -g -Og file.c -o app
Sanitize: gcc -g -Og -fsanitize=address,undefined file.c -o app
Release: gcc -O2 -DNDEBUG file.c -o app
Preprocess: gcc -E file.c -o file.i
Assembly: gcc -O2 -S file.c -o file.s
Coverage: gcc --coverage file.c -o app && ./app && gcov file.c