gcc
GNU C compiler front end
By CMD Script Team · 5 min read · Last updated
gcc [OPTIONS] FILE...Options
| Flag | Description |
|---|---|
-o FILE | Write the compiled output to FILE instead of the default a.out |
-c | Compile and assemble into an object file (.o) without linking |
-Wall | Enable a broad set of commonly useful compiler warnings |
-g | Include debugging symbols in the output, needed for source-level debugging with gdb |
-O0 / -O1 / -O2 / -O3 | Set the optimization level; -O0 (default) disables optimization for faster, more debuggable builds, -O2/-O3 optimize for speed at compile-time cost |
-I DIR | Add DIR to the list of directories searched for #include header files |
-l NAME | Link against library libNAME (e.g. -lm links libm, the math library) |
-std=STANDARD | Select the C language standard to compile against, e.g. -std=c11 or -std=c99 |
Distribution compatibility
- Ubuntu
- Debian
- Fedora
- Arch
- macOS (gcc is often aliased to Clang via Xcode Command Line Tools; install real GCC via Homebrew for full GCC behavior)
What it does
gcc is the GNU Compiler Collection's front end for compiling C (and, via file
extension or explicit invocation, several other languages) — it drives the full
pipeline of preprocessing, compiling to assembly, assembling to object code, and
invoking the linker to produce a final executable or object file. It's the default C
compiler on most Linux distributions and a foundational tool for building nearly
anything written in C, from small utilities to the Linux kernel itself.
Beginner examples
gcc main.c— compile and link into a default executable nameda.outgcc -o app main.c— compile and link, naming the outputappgcc -c main.c— compile to an object filemain.owithout linkinggcc -Wall -o app main.c— compile with common warnings enabledgcc -g -o app main.c— compile with debug symbols for use withgdb
gcc -Wall -o hello hello.c
Advanced examples
- Build a multi-file project by compiling each translation unit separately, then linking:
gcc -c a.c b.c && gcc -o app a.o b.o - Optimize for release while still catching warnings:
gcc -O2 -Wall -o app main.c - Add an include search path for headers in a non-standard location:
gcc -I./include -o app main.c - Link against an external library, e.g. the math library:
gcc calc.c -lm -o calc - Target a specific C standard explicitly:
gcc -std=c11 -Wall -o app main.c - Combine warnings-as-errors to enforce a clean build in CI:
gcc -Wall -Werror -o app main.c
gcc -std=c11 -Wall -Wextra -g -O0 -o app main.c
Common mistakes
- Forgetting
-oand being confused when the output is silently nameda.outinstead of something meaningful. - Compiling without
-Wallduring development, missing warnings (like implicit function declarations or type mismatches) that often point to real bugs. - Using
-O2while actively debugging — optimized code can reorder and inline instructions in ways that make stepping through source in a debugger confusing or misleading; use-O0 -gwhile debugging instead. - Forgetting to link required libraries (e.g. omitting
-lmwhen callingsqrt()orpow()), producing "undefined reference" linker errors. - Mixing
-c(compile-only) into a one-shot build command and expecting an executable —-cexplicitly stops before linking, producing only an object file.
Tips
- Make
-Wall -Wextrayour default during development; treat warnings as bugs to fix, not noise to ignore. - Use
-g -O0while actively debugging, and switch to-O2(without-g, or with-gif you need optimized-build debugging) for release builds. - When a link fails with "undefined reference," check whether you're missing a
-lflag for the library that defines the missing symbol (usenmto confirm). - Use
-std=explicitly rather than relying on the compiler's default standard, so builds behave consistently across gcc versions and systems.
Best practices
- Always compile with
-Wall(and often-Wextra) enabled, and treat the warnings seriously — most flag genuine correctness issues. - Separate compile and link steps (
-c, then a final link) for multi-file projects, or better, drive the whole process withmakeso only changed files recompile. - Keep debug (
-g -O0) and release (-O2, no-gor split debug info) build configurations distinct rather than using one flag set for both. - Pin a specific
-std=value in your build configuration so language-standard behavior doesn't silently shift between compiler versions.
Try it yourself
A simulated shell with a sample home directory — experiment freely, nothing leaves your browser. Type help to list supported commands.
Real-world use cases
- Compiling a C project's source files into object files and linking them into a final executable, usually orchestrated by a Makefile.
- Building a debug build with
-g -O0to step through a crash ingdb. - Producing an optimized release build with
-O2for a performance-sensitive tool. - Cross-referencing compiler warnings (
-Wall -Wextra) as part of a CI quality gate before merging code.
Common interview questions
- What's the difference between gcc -c and a full gcc build? -c stops after producing an object file, without linking; a full build (no -c) compiles and links in one step to produce a runnable executable.
- Why is -Wall considered essential? It surfaces a broad set of warnings for legal-but-suspicious C constructs (uninitialized variables, signed/unsigned comparisons, etc.) that frequently indicate real bugs, catching them at compile time.
- Why avoid -O2 while debugging? Optimizations can reorder, inline, or eliminate code in ways that make source-level debugging confusing or inaccurate; -O0 keeps the generated code closely mapped to the source.
- What causes an 'undefined reference' error at link time, and how do you fix it? It means the linker can't find the definition of a referenced symbol, often because a required library wasn't linked (e.g. missing -lm) or an object file wasn't included in the link command; nm can help confirm which symbol and library are involved.
Frequently Asked Questions
What's the difference between gcc -c and just gcc?
gcc -c compiles source into an object file (.o) without running the linker, useful for building multi-file projects incrementally. Plain gcc file.c compiles and links in one step, producing a runnable executable (a.out by default, or the name given with -o).
Why should I always use -Wall?
-Wall enables a large set of warnings for constructs that are legal C but often indicate bugs, such as using an uninitialized variable or comparing signed and unsigned values. Compiling clean under -Wall catches many mistakes at compile time instead of as runtime crashes.
What does -O2 actually change?
It tells gcc to apply a broader set of optimization passes (inlining, loop optimizations, instruction scheduling, etc.) to produce faster code, at the cost of longer compile times and code that's harder to step through in a debugger. -O0 (no optimization) is preferred during active development and debugging.
How do I compile a program that uses math functions like sqrt()?
Include -lm at the end of the compile command, e.g. gcc prog.c -o prog -lm, since the math library isn't linked by default on many systems.
Cheat sheet
Download a quick-reference cheat sheet for gcc.