GCC Compiler

GCC cheatsheet — compile C/C++, set optimization, enable warnings, debug with -g. gcc -O2 -Wall -o myapp main.c, gcc -shared -fPIC, gcc -fsanitize=address. Full reference.

9 min read

What it is

GCC (GNU Compiler Collection) is the primary compiler for C, C++, Objective-C, Fortran, Ada, Go, and D, and it’s the standard for building software on Linux and many other Unix-like systems. You reach for it to turn your source code into executable programs.

Installation

Linux (Debian/Ubuntu)

sudo apt update
sudo apt install build-essential

This installs gcc, g++, make, and other essential development tools.

Linux (Fedora/CentOS/RHEL)

sudo dnf groupinstall "Development Tools"
# or for older systems:
# sudo yum groupinstall "Development Tools"

macOS

Install Xcode Command Line Tools:

xcode-select --install

This will install clang, which is a compatible compiler, and often gcc is provided as a symlink or an alternative. For a native GCC, you can use Homebrew:

brew install gcc

Windows

The easiest way is to install MinGW-w64:

  1. Download the installer from the MinGW-w64 website.
  2. Run the installer and select the desired architecture (e.g., x86_64 for 64-bit) and thread model (posix is generally recommended).
  3. Add the bin directory of your MinGW-w64 installation (e.g., C:\Program Files\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin) to your system’s PATH environment variable.

Core Concepts

  • Compilation: The process of translating human-readable source code (like .c or .cpp files) into machine-readable object code.
  • Linking: The process of combining one or more object files and libraries into a single executable file.
  • Pre-processing: The first stage of compilation where directives like #include and #define are handled.
  • Assembly: Translating pre-processed code into machine instructions.
  • Object File: An intermediate file (.o extension) produced by the compiler that contains machine code but is not yet a complete executable program.
  • Executable: The final output file that can be run directly by the operating system.

Commands / Usage

GCC is typically invoked directly from the command line. The most common usage is to compile source files into an executable.

Compiling a Single Source File

C:

gcc hello.c -o hello

Compiles hello.c into an executable named hello.

C++:

g++ main.cpp -o my_program

Compiles main.cpp into an executable named my_program. (Note: g++ is the C++ driver for GCC).

Compiling Multiple Source Files

C:

gcc main.c utils.c -o app

Compiles main.c and utils.c together into an executable named app.

C++:

g++ main.cpp helpers.cpp -o service

Compiles main.cpp and helpers.cpp together into an executable named service.

Linking Libraries

Linking a standard library (e.g., math library):

gcc math_example.c -o math_app -lm

Compiles math_example.c and links it with the math library (libm.so or libm.a).

Linking a custom library:

gcc main.c -L/path/to/your/lib -lyour_lib -o custom_app

Compiles main.c and links it with a library named your_lib found in /path/to/your/lib. The -L flag specifies the directory, and -l specifies the library name (e.g., -lyour_lib looks for libyour_lib.so or libyour_lib.a).

Debugging and Optimization Flags

  • -g: Include debugging information in the executable. Essential for using debuggers like GDB.
    gcc -g my_code.c -o my_code_debug
    
  • -O0: No optimization (default). Fastest compilation, slowest execution.
    gcc -O0 my_code.c -o my_code_no_opt
    
  • -O1: Basic optimization.
    gcc -O1 my_code.c -o my_code_opt1
    
  • -O2: More optimization. A good balance for release builds.
    gcc -O2 my_code.c -o my_code_opt2
    
  • -O3: Aggressive optimization. May increase code size.
    gcc -O3 my_code.c -o my_code_opt3
    
  • -Os: Optimize for size. Useful for embedded systems or where binary size is critical.
    gcc -Os my_code.c -o my_code_small
    
  • -Og: Optimize for debugging experience. Enables optimizations that don’t interfere with debugging.
    gcc -Og my_code.c -o my_code_debug_opt
    

Warning Flags

  • -Wall: Enable all common warning messages. Highly recommended.
    gcc -Wall my_code.c -o my_code_warn
    
  • -Wextra: Enable additional warning messages beyond -Wall.
    gcc -Wall -Wextra my_code.c -o my_code_extra_warn
    
  • -Werror: Treat all warnings as errors. Prevents compilation if any warnings are issued.
    gcc -Wall -Werror my_code.c -o my_code_no_warnings
    

Language Standards

  • -std=c99: Compile using the C99 standard.
    gcc -std=c99 my_c99_code.c -o c99_app
    
  • -std=c11: Compile using the C11 standard.
    gcc -std=c11 my_c11_code.c -o c11_app
    
  • -std=gnu99: Compile using the C99 standard with GNU extensions (often the default).
    gcc -std=gnu99 my_gnu_code.c -o gnu_app
    
  • -std=c++11: Compile using the C++11 standard.
    g++ -std=c++11 my_cpp11_code.cpp -o cpp11_app
    
  • -std=c++14: Compile using the C++14 standard.
    g++ -std=c++14 my_cpp14_code.cpp -o cpp14_app
    
  • -std=c++17: Compile using the C++17 standard.
    g++ -std=c++17 my_cpp17_code.cpp -o cpp17_app
    
  • -std=c++20: Compile using the C++20 standard.
    g++ -std=c++20 my_cpp20_code.cpp -o cpp20_app
    

Pre-processing and Intermediate Stages

  • -E: Stop after the pre-processing stage. Outputs the pre-processed code to standard output.
    gcc -E hello.c > hello.i
    
  • -S: Stop after the assembly stage. Outputs assembly code (.s file).
    gcc -S hello.c -o hello.s
    
  • -c: Compile or assemble the source files, but do not link. Produces object files (.o).
    gcc -c main.c utils.c -o
    # This creates main.o and utils.o
    
    Then you can link them:
    gcc main.o utils.o -o my_program
    

Include Paths

  • -I/path/to/include: Add a directory to the list of places to search for header files.
    gcc main.c -I/usr/local/mylib/include -o app
    

Output Control

  • -o output_file: Specify the name of the output file. If omitted, GCC defaults to a.out (or a.exe on Windows).
    gcc main.c -o my_executable
    
  • -v: Verbose output. Shows the compiler commands being executed.
    gcc -v main.c -o verbose_app
    

Other Useful Flags

  • -D MACRO[=VALUE]: Define a pre-processor macro.
    gcc -D DEBUG my_code.c -o debug_build
    # Equivalent to #define DEBUG in the source
    
    gcc -D VERSION="1.2.3" my_code.c -o versioned_app
    # Equivalent to #define VERSION "1.2.3"
    
  • -U MACRO: Undefine a pre-processor macro.
    gcc -U DEBUG my_code.c -o release_build
    # If DEBUG was defined elsewhere (e.g., by -DDEBUG), this removes it.
    
  • -pedantic: Issue all the warnings demanded by strict ISO C / ISO C++ conformance.
    gcc -Wall -pedantic my_code.c -o strict_app
    
  • -shared: Produce a shared object (dynamic library) which can be linked with other objects to create an executable, or with other shared objects.
    gcc -shared -fPIC my_lib.c -o libmylib.so
    

Common Patterns

  • Compile and link a simple program:
    gcc my_program.c -o my_program
    
  • Compile with debugging symbols and all warnings:
    gcc -g -Wall -Wextra my_app.c -o my_app_debug
    
  • Optimize for release, enable common warnings:
    gcc -O2 -Wall my_app.c -o my_app_release
    
  • Compile multiple files into an executable:
    gcc main.c module1.c module2.c -o my_application
    
  • Compile files individually into object files, then link:
    gcc -c main.c -o main.o
    gcc -c module1.c -o module1.o
    gcc -c module2.c -o module2.o
    gcc main.o module1.o module2.o -o my_application
    
    This is useful for large projects where you only want to recompile changed files.
  • Compile C++ code with C++17 standard and optimizations:
    g++ -std=c++17 -O3 main.cpp utils.cpp -o my_cpp_app
    
  • Create a static library:
    # Compile source files into object files
    gcc -c lib_part1.c lib_part2.c
    # Create the static library archive
    ar rcs libmy_static_lib.a lib_part1.o lib_part2.o
    # Link your program with the static library
    gcc main.c -L. -lmy_static_lib -o my_app
    
    (The -L. tells the linker to look in the current directory for libraries.)
  • Create a shared library:
    # Compile source files with position-independent code flag
    gcc -fPIC -c lib_part1.c lib_part2.c
    # Create the shared library
    gcc -shared -o libmy_shared_lib.so lib_part1.o lib_part2.o
    # Link your program with the shared library
    gcc main.c -L. -lmy_shared_lib -o my_app
    # You might need to set LD_LIBRARY_PATH or install the library correctly
    # to run the executable if it's not in a standard system path.
    # export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
    # ./my_app
    

Gotchas

  • a.out as default output: If you forget the -o flag, GCC will create an executable named a.out (or a.exe on Windows). This can be confusing if you compile multiple files without specifying output names.
  • g++ vs gcc for C++: While gcc can compile C++ code with the -x c++ flag, it’s best practice to use g++ for C++ projects. g++ automatically links the C++ standard library, which gcc does not. Forgetting this can lead to linker errors.
    # Correct for C++
    g++ main.cpp -o my_app
    # Incorrect for C++ (will likely fail to link std::cout, etc.)
    # gcc main.cpp -o my_app
    # Correct but verbose for C++
    # gcc -x c++ main.cpp -lstdc++ -o my_app
    
  • Order of source files and libraries: The linker processes libraries and object files in the order they appear. If library A depends on library B, you must list A before B.
    # Correct: lib_a depends on lib_b
    gcc main.o -L. -l_a -l_b -o my_app
    # Incorrect: lib_b is linked before lib_a, so dependencies might not be resolved
    # gcc main.o -L. -l_b -l_a -o my_app
    
  • Header file vs Library path: -I is for header files (.h), and -L is for library files (.so, .a). They are distinct.
  • make for larger projects: For anything more than a few files, manually invoking GCC becomes tedious. Tools like make are essential for managing the build process, automatically determining which files need recompilation.
  • Shared library runtime path (LD_LIBRARY_PATH): When you compile a program against a shared library that isn’t in a standard system location, you often need to tell the dynamic linker where to find it at runtime. This is commonly done by setting the LD_LIBRARY_PATH environment variable (on Linux/macOS).
    export LD_LIBRARY_PATH=/path/to/your/libs:$LD_LIBRARY_PATH
    ./your_executable
    
    On Windows, you’d typically place the DLL in the same directory as the executable or in a system-wide DLL directory.
  • Position-Independent Code (-fPIC): When creating shared libraries, you usually need to compile the object files with -fPIC (or -fpic) to ensure they can be loaded at any memory address.
  • Warning flags are crucial: Compiling without -Wall and -Wextra can hide subtle bugs. Treating warnings as errors with -Werror enforces code quality.