Working with GNU Compilers: A Practical Guide to gcc and g++
The GNU Compiler Collection provides two primary tools for C/C++ development: gcc for C programs and g++ for C++ programs. While g++ can compile both languages, conventional practice favors using each tool for its intended language.
Basic Compiler Invocation
For a typical C source file, compilation is straightforward:
gcc main.c
This produces a default executable named a.out that can be run immediately:
./a.out
The executable name is customizable using the -o flag:
gcc main.c -o myprogram
./myprogram
Installing the C++ Compiler
Most Linux distributions include gcc by default, but g++ often requires separate installation:
sudo yum install gcc-c++
After installation, compile C++ sources using:
g++ source.cpp -o application
The Four-Stage Compilation Pipeline
Creating an executable involves four distinct transformation stages:
- Preprocessing
- Compilation to assembly
- Assembly to object code
- Linking to final executable
Stage 1: Preprocessing
The preprocessor handles these transformations:
- Comment removal
- Header file inclusion
- Macro expansion
- Conditional compilation directives
To generate preprocessed output:
gcc -E main.c -o preprocessed.i
The -E flag halts compilation after preprocessing. The .i extension indicates preprocessed C source.
Cross-platform development relies on installed development headers and libraries. On Linux systems, standard headers reside in:
/usr/include
Opening stdio.h reveals its contents—preprocessing essentially copies these definitions into your source file. Similar development packages exist on Windows, installed with Visual Studio.
Conditional compilation allows feature selection at build time. Consider this example:
gcc -E main.c -o preprocessed.i -DVERSION=2
This defines a macro during preprocessing, enabling code variants without maintaining separate source files—useful for creating different product editions from a single codebase.
Stage 2: Generating Assembly Code
The compiler translates preprocessed C code into assembly language:
gcc -S preprocessed.i -o assembly.s
You can also compile directly from source:
gcc -S main.c -o assembly.s
During this phase, the compiler performs syntax checking, semantic analysis, and optimization before emitting assembly instructions.
Stage 3: Producing Object Code
The assembler converts .s files into binary object files containing machine instructions:
gcc -c assembly.s -o module.o
Object files are not human-readable text. Attempting to view them in a text editor shows binary data. Use od for proper inspection:
od module.o
Stage 4: Linking
The linker combines object files and libraries into a final executable:
gcc module.o -o finalprog
The resulting finalprog is a standalone executable ready for deployment.
Alternative Compilation Approaches
Several methods produce executables with varying control levels:
Direct compilation (default output):
gcc main.c
Named executable:
gcc main.c -o myapp
Reordered flags (functionally identical):
gcc -o myapp main.c
The -o flag always specifies the final output filename, regardless of its position in the command.