>_cmd.script

gcc

GNU C compiler front end

Development

By CMD Script Team · 5 min read · Last updated

SYNTAX
gcc [OPTIONS] FILE...

Options

Command options and flags
FlagDescription
-o FILEWrite the compiled output to FILE instead of the default a.out
-cCompile and assemble into an object file (.o) without linking
-WallEnable a broad set of commonly useful compiler warnings
-gInclude debugging symbols in the output, needed for source-level debugging with gdb
-O0 / -O1 / -O2 / -O3Set the optimization level; -O0 (default) disables optimization for faster, more debuggable builds, -O2/-O3 optimize for speed at compile-time cost
-I DIRAdd DIR to the list of directories searched for #include header files
-l NAMELink against library libNAME (e.g. -lm links libm, the math library)
-std=STANDARDSelect 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 named a.out
  • gcc -o app main.c — compile and link, naming the output app
  • gcc -c main.c — compile to an object file main.o without linking
  • gcc -Wall -o app main.c — compile with common warnings enabled
  • gcc -g -o app main.c — compile with debug symbols for use with gdb
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 -o and being confused when the output is silently named a.out instead of something meaningful.
  • Compiling without -Wall during development, missing warnings (like implicit function declarations or type mismatches) that often point to real bugs.
  • Using -O2 while actively debugging — optimized code can reorder and inline instructions in ways that make stepping through source in a debugger confusing or misleading; use -O0 -g while debugging instead.
  • Forgetting to link required libraries (e.g. omitting -lm when calling sqrt() or pow()), producing "undefined reference" linker errors.
  • Mixing -c (compile-only) into a one-shot build command and expecting an executable — -c explicitly stops before linking, producing only an object file.

Tips

  • Make -Wall -Wextra your default during development; treat warnings as bugs to fix, not noise to ignore.
  • Use -g -O0 while actively debugging, and switch to -O2 (without -g, or with -g if you need optimized-build debugging) for release builds.
  • When a link fails with "undefined reference," check whether you're missing a -l flag for the library that defines the missing symbol (use nm to 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 with make so only changed files recompile.
  • Keep debug (-g -O0) and release (-O2, no -g or 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 -O0 to step through a crash in gdb.
  • Producing an optimized release build with -O2 for 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.