Skip to content

/flags/cpp/gpp-c-compile-only

g++ -c: compile C++ to an object file without linking

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash)updated
tool
C++
command
g++
flag
-c
default
off: g++ compiles, assembles and links into an executable (a.out)

g++ -c file.cpp stops after compiling and assembling: it writes an object file (file.o, or file.obj with MSVC-style toolchains) and does not link, so the file does not need a main function and undefined functions are not an error yet. The objects are combined later with g++ a.o b.o -o app. This is how every build system compiles C++: one -c step per source file, then one link step. Clang (clang++ -c) behaves the same.

The example uses Clang 20 from the Zig 0.15.1 toolchain (installed from PyPI with uv); cxx below is that compiler, and g++ accepts the same options:

bash
cxx() { uv run -q --no-project --python 3.13 --with ziglang==0.15.1 python -m ziglang c++ -fno-color-diagnostics "$@"; }
cat > greet.h <<'EOF'
#pragma once
#include <string>
std::string greet(const std::string& name);
EOF
cat > greet.cpp <<'EOF'
#include "greet.h"
std::string greet(const std::string& name) { return "hello " + name; }
EOF
cat > main.cpp <<'EOF'
#include <iostream>
#include "greet.h"
int main() { std::cout << greet("c++") << '\n'; }
EOF
cxx -std=c++17 -Wall -c greet.cpp -o greet.o
cxx -std=c++17 -Wall -c main.cpp -o main.o
ls *.o
cxx main.o greet.o -o app && ./app
echo "== change greet.cpp: recompile one file, relink"
sed -i 's/hello /hi /' greet.cpp
cxx -std=c++17 -Wall -c greet.cpp -o greet.o
cxx main.o greet.o -o app2 && ./app2

Output

greet.o
main.o
hello c++
== change greet.cpp: recompile one file, relink
hi c++

greet.cpp has no main, which is fine with -c. After editing it, only greet.o is rebuilt; main.o is reused in the link. Build tools such as Make, Ninja and CMake automate exactly this, based on file timestamps and header dependencies.

OptionStops afterOutput
-EPreprocessingPreprocessed source on stdout
-SCompilationAssembly file (.s)
-cAssemblingObject file (.o)
(none)LinkingExecutable (a.out or the -o name)
-o file-Name of the output of the last stage
-MMD -MP-Also write a .d dependency file for Make, listing the headers

With GCC, g++ -c a.cpp b.cpp writes a.o and b.o in one call, and -o is then not allowed (cannot specify '-o' with '-c', '-S' or '-E' with multiple files). The Zig-packaged Clang used above, on Windows, rejects several files with -c altogether (coff does not support linking multiple objects into one), so the example compiles one file per call, which is what build systems do anyway.

Linking problems after -c

  • Undefined reference / undefined symbol: a function is declared in a header but its object file or library is missing from the link command. Add the .o or the -lname option; see undefined reference to.
  • Linking with gcc instead of g++: gcc main.o greet.o does not add the C++ standard library, which produces undefined references to std:: symbols. Use g++ (or clang++) for the link step.
  • Order of libraries: with GNU ld, -lfoo must come after the objects that use it: g++ main.o -lfoo, not g++ -lfoo main.o.
  • Mismatched flags: objects compiled with different -std levels usually link fine, but different ABI options (-D_GLIBCXX_USE_CXX11_ABI, -fsanitize, -m32) can cause link or run-time errors.

For one-command builds of small programs, see compile a C++ program.

FAQ

Why compile with -c instead of all files at once?

Separate compilation lets a build tool recompile only the files that changed and then relink. For a large project this turns minutes into seconds. It also allows mixing objects from different compilers or languages, such as C and C++, in one link step.

Do I need the same flags for compiling and linking?

Most -c flags (warnings, -I, -D) matter only when compiling. Options that change the ABI or runtime must be given in both steps: -pthread, -fsanitize=address, -static, -flto and -m32/-m64. Linking is best done with g++ (not gcc or ld) so the C++ standard library is added.

What is the difference between a .o file and a .a or .so?

A .o is one compiled translation unit. A static library (.a) is an archive of .o files made with ar, and a shared library (.so, .dylib, .dll) is a linked file loaded at run time. All three can be passed to the final g++ link command.

Sources