Multi-File Projects
The One-Step (Naive) Way
The simplest approach is to hand every source file to gcc at once and let it do everything in a single command.
gcc main.c stack.c queue.c -o program
This works, but it has a hidden cost: every single file gets recompiled every time, even if you only changed one line in one file. For a project with dozens or hundreds of source files, that becomes painfully slow.
The Two-Step Process: Compile, Then Link
GCC (like essentially all C toolchains) actually performs two distinct steps under the hood:
Compilation — each
.cfile is translated independently into an object file (.o), using the-cflag. Object files contain machine code, but with unresolved references to functions/variables defined elsewhere.Linking — the object files (and any needed libraries) are combined into a single executable. The linker resolves all the cross-file references, matching each call to its definition.
# Step 1: compile each source file into an object file, independently gcc -c main.c -o main.o gcc -c stack.c -o stack.o gcc -c queue.c -o queue.o # Step 2: link the object files together into the final executable gcc main.o stack.o queue.o -o program
Why This Is Faster for Large Projects
The key insight: if you only edit stack.c, you only need to recompile stack.c into a fresh stack.o. The already-compiled main.o and queue.o are untouched and can be reused as-is — only the final, comparatively cheap linking step needs to rerun.
# You edited only stack.c. Recompile just that file... gcc -c stack.c -o stack.o # ...then relink using the existing object files. gcc main.o stack.o queue.o -o program
On a project with 3 files this saves little time. On a project with 300 files, where a full rebuild might take minutes, incremental compilation like this can turn a multi-minute rebuild into a near-instant one.
Compilation vs Linking at a Glance
Step | Input | Output | Flag |
|---|---|---|---|
Compile | One | One |
|
Link | Multiple | One executable | (none — default gcc behavior) |
Common Linker Errors
If the linker can't find the definition of something a .o file references, you'll see an "undefined reference" error — usually meaning you forgot to include that object file (or library) in the final link command, or you have a typo in a function name between the header declaration and its implementation.