Error

"linker cc not found" — How to Fix on Linux

The 'linker cc not found' error means your Linux system has rustc but no system C linker. Learn what cc is, why Rust needs it, and how to install the right package on common distributions.

The first error nobody warns you about

You installed Rust on a fresh Linux box. rustc --version works, cargo new hello creates a project, you cd in and run cargo build and... it fails. Not a syntax error in your code. A linker error from Cargo:

error: linker `cc` not found
  |
  = note: No such file or directory (os error 2)

error: could not compile `hello` (bin "hello") due to previous error

It's frustrating because the error has nothing to do with Rust as a language. You wrote fn main() { println!("hello"); }, the only thing this file calls is the macro from std, and yet the compiler is shouting about something called cc. What's going on?

The short version: Rust compiles your code to object files, but the final step of producing a usable executable is linking those object files together (with libc, with the system loader, with whatever C libraries you depend on). Linking is done by an external program. On Linux, that program is by default the C compiler, named cc. If cc isn't installed, Rust has nothing to invoke for the link step, and you get the error above.

Why does Rust need a C linker at all?

Rust isn't a fully self-contained ecosystem at the binary level. When you build a typical Rust binary on Linux, the final executable links against:

  • glibc (or musl): the C standard library, used by Rust's std for things like malloc, syscalls, threads, env vars.
  • libpthread, libdl, libm, libc: various pieces the C runtime needs.
  • The dynamic loader (ld-linux-x86-64.so.2): the program that actually starts your binary.

Linking those together requires a linker. Rust's std and core ship as precompiled rlibs that already know how to call into these libraries, but the combining of all the pieces into one ELF executable is the job of ld, the system linker, typically driven by the C compiler frontend cc (which knows the right flags to pass).

So: rustc generates object code; cc glues it into a real binary. If cc isn't installed, the chain breaks at the last step. This is why the error shows up at the end of the build, after your code has already compiled successfully.

The fix on the major distributions

The cleanest fix is to install your distro's standard "basic build tools" meta-package, which always includes gcc (and sets up cc as a symlink) plus a few common bits like ld and make.

# Debian / Ubuntu / Linux Mint / Pop!_OS
sudo apt-get update
sudo apt-get install build-essential

# Fedora / RHEL 8+ / Rocky / Alma
sudo dnf install gcc

# Older RHEL / CentOS 7
sudo yum groupinstall "Development Tools"

# Arch Linux / Manjaro
sudo pacman -S base-devel

# Alpine (musl)
sudo apk add build-base

# openSUSE
sudo zypper install -t pattern devel_basis

After that, which cc should print /usr/bin/cc and cargo build should succeed. No restart, no shell reload needed.

A quick sanity check before and after:

# Before: should print nothing, or 'no cc'.
which cc || echo "no cc"

# After installing build tools.
cc --version
# gcc (Ubuntu 11.4.0) ... 

Why slim containers and minimal VMs hit this constantly

This error is rare on developer laptops because most distros ship with gcc either preinstalled or pulled in as a dependency by something else. It's very common in two specific environments:

  • Slim Docker images. Images like debian:bookworm-slim, alpine, ubuntu:noble deliberately strip everything that isn't strictly needed at runtime. They have no cc. If you RUN cargo build inside one of those, you'll hit this error. The fix is to install build tools as part of the build stage.
  • Minimal cloud VMs. Some "minimal" Ubuntu or Debian server images come without a C compiler. Same fix.

A typical Dockerfile that gets it right:

FROM rust:1.81-slim AS builder

# The rust:slim images don't include build-essential. Add it before cargo build.
RUN apt-get update && apt-get install -y --no-install-recommends \
    build-essential pkg-config \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /app
COPY . .
RUN cargo build --release

# Runtime image, doesn't need a compiler.
FROM debian:bookworm-slim
COPY --from=builder /app/target/release/myapp /usr/local/bin/myapp
CMD ["myapp"]

The pkg-config line saves you from a sibling error you're likely to hit next once cc is in place: native crates that wrap C libraries (like openssl-sys, libz-sys) ask pkg-config for compile and link flags. Without it, those crates fail with their own confusing messages.

What if I want a different linker?

Rust doesn't have to use cc. It just defaults to it on Linux. You can override the linker per target via ~/.cargo/config.toml:

# Use clang as the linker driver instead of cc.
[target.x86_64-unknown-linux-gnu]
linker = "clang"

# Or, popular for faster link times: use mold.
# (mold is a drop-in linker, much faster than ld for big projects.)
[target.x86_64-unknown-linux-gnu]
linker = "clang"
rustflags = ["-C", "link-arg=-fuse-ld=mold"]

If you set this and the binary you point to also isn't installed, you get the same kind of error with that name instead. So the troubleshooting pattern is: read the error, see what it says is missing (cc, clang, mold, lld), and install that.

Common pitfalls

You installed gcc but not cc. On most distros, cc is a symlink that's installed by the same package as gcc, but on a few minimal setups they get split. Try sudo apt-get install gcc or check if cc exists at /usr/bin/cc. If not, sudo ln -s /usr/bin/gcc /usr/bin/cc is a temporary workaround, though installing the right package is cleaner.

You installed build-essential and still get linker cc not found. Make sure you're running cargo as a user whose PATH includes /usr/bin. In containers, sometimes the build runs as a user with a stripped path. which cc will tell you.

You cross-compiled and got the error for a different linker, like aarch64-linux-gnu-gcc not found. That means you're trying to build for ARM but only have an x86 toolchain. Install the cross compiler: sudo apt-get install gcc-aarch64-linux-gnu, and also tell Cargo about it in ~/.cargo/config.toml:

[target.aarch64-unknown-linux-gnu]
linker = "aarch64-linux-gnu-gcc"

You switched to musl with --target x86_64-unknown-linux-musl and got an error about a different missing tool, like musl-gcc not found. Install musl-tools (Debian/Ubuntu) or the equivalent.

You tried to cargo install a binary on a system with no compiler. Same fix. cargo install builds from source by default. If you want a precompiled binary, look for a release artifact on the project's GitHub or use cargo binstall.

You see the error inside an environment that does have cc, but rustup has its own bundled toolchain set as default. That's almost never the problem; the linker is always pulled from PATH. But if which cc works in your shell and not in cargo build, double-check that you didn't override PATH in .cargo/config.toml.

When this comes up again

Think of "linker not found" errors as the system telling you a separate, OS-level dependency is missing. The fix is always: install the linker, or change which linker Cargo uses. The error rarely means anything is wrong with your Rust code.

Most Rust learners hit this exactly once, on a fresh dev box or in a CI image. After that, you'll recognize the shape immediately and the fix takes thirty seconds. The skill is recognizing the family of errors: any time the message mentions linker, cc, lld, mold, pkg-config, or cmake, you're looking at a missing system tool, not a Rust problem.

Where to go next

What Are the Stages of Rust Compilation? (Parsing, HIR, MIR, LLVM IR)

How to Create Static Binaries for Easy Deployment

How to Cache Cargo Builds in CI for Faster Pipelines