cc-rs
A Cargo build-script library that compiles C, C++, assembly, and CUDA into static libraries for Rust.
Repository Health
Technical Analysis
cc is the de facto standard build-script dependency in the Rust ecosystem for compiling native C, C++, assembly, and CUDA source files into a static archive that Cargo links into the final crate. Instead of hand-rolling calls to make or cmake, a build.rs script constructs a cc::Build, registers source files and flags, and calls .compile() — the crate handles compiler discovery, cross-compilation target detection, and platform-specific flag selection so C interop works across macOS, Linux, Windows (MSVC and MinGW), Android, iOS, WASI, and dozens of embedded targets.
Maintained under the rust-lang GitHub organization, cc is a transitive build dependency of thousands of crates that wrap C libraries, underlying FFI bindings across the ecosystem. Recent releases split MSVC toolchain discovery into a companion find-msvc-tools crate and hardened environment-variable override handling for reproducible builds.
What You Get
- Cross-platform compiler discovery - Locates MSVC, GCC, Clang, and other toolchains automatically based on the target triple, including MSVC probing split out into the find-msvc-tools crate.
- Fluent Build API -
cc::Build::new()lets you register source files, include paths, defines, and flags, then call.compile()to produce a linkable static library. - C++ and CUDA support - Toggle
.cpp(true)for C++ sources with configurable standard library linkage, or.cuda(true)for CUDA compilation via nvcc. - Environment variable overrides - Respects
CC,CXX,AR,CFLAGS, and target-scoped variants (e.g.CC_x86_64-unknown-linux-gnu) so downstream users can override toolchains without patching build scripts. - Parallel compilation - Compiles multiple source files concurrently using Cargo’s jobserver protocol to avoid oversubscribing CPU cores during a workspace build.
Common Use Cases
- Wrapping a C library for Rust FFI - Crate authors vendor a C library’s sources and use cc to compile and statically link it instead of requiring users to install the library system-wide.
- Building C++ interop shims - Projects wrap C++ APIs (e.g. via cxx or manual FFI) and use cc to compile the C++ glue code alongside Rust.
- Compiling CUDA kernels - GPU-accelerated crates compile
.cukernel files with cc’s CUDA support before linking them into the Rust build. - Cross-compiling native code for embedded/mobile targets - Build scripts targeting Android, iOS, or bare-metal architectures rely on cc’s target-detection and flag logic to select the right compiler and flags per target triple.
Under The Hood
Architecture
cc centers on a single Build struct (src/lib.rs) that accumulates configuration — files, includes, defines, flags — through chainable setters, then dispatches to platform-specific compiler-detection logic in src/tool.rs and target-triple parsing in src/target/ (with src/target/apple.rs and src/target/llvm.rs handling Apple- and LLVM-specific target quirks). Actual command execution and output capture are isolated in src/command_helpers.rs and the src/parallel/ module, which runs compilation jobs concurrently through a jobserver-aware executor (src/parallel/job_token.rs, command_runner.rs) so .compile() scales across CPU cores without violating Cargo’s build concurrency budget. This layered separation — configuration, compiler/target detection, and execution — means adding a new target or compiler quirk touches tool.rs/target/ without altering the public Build API surface.
Tech Stack Written in Rust 2021 edition (MSRV 1.65), cc depends on the sibling find-msvc-tools crate for Windows toolchain discovery, an optional jobserver crate (default-features disabled) for Cargo-aware parallelism, and shlex for shell-style flag parsing; dev-dependencies bring in tempfile for test fixtures. The workspace also bundles internal dev-tools crates (cc-test, gen-target-info, gen-windows-sys-binding, wasi-test) used to regenerate target metadata and exercise the crate against real toolchains, rather than shipping any application framework — this is a pure build-time library with no runtime dependencies of its own.
Code Quality
The tests/ directory holds targeted integration suites (archiver.rs, cc_env.rs, cflags.rs, cxxflags.rs, env.rs, rustflags.rs, trim_paths.rs) alongside a tests/support helper module, and CI (.github/workflows/main.yml) runs the suite across a wide matrix — stable/beta/nightly Rust, 32-bit Linux, multiple macOS and iOS ABIs, Windows 32/64-bit, and more — which is unusually thorough for verifying compiler-invocation correctness across real platforms rather than mocks. Workspace-level Clippy lints (borrow_as_ptr, ptr_as_ptr, doc_markdown, manual_let_else) and a missing_docs warning are enforced repo-wide, and errors are represented through a dedicated Error type rather than panics or silent failures.
What Makes It Unique
cc’s differentiator is the depth of its environment-variable override protocol — a prioritized cascade of target-triple-specific, host/target-kind-specific, and plain variable names (CC_<target>, HOST_CC, CC) plus recognition of known compiler wrappers (sccache, ccache, distcc, icecc, cachepot, buildcache, kache) — letting downstream consumers redirect compilation without patching build scripts. Combined with flag_if_supported capability probing and jobserver-aware parallelism, it solves cross-toolchain C interop correctness at a level few comparable build helpers attempt, which is why it has become the near-universal choice for the Rust ecosystem’s native-code build scripts rather than a niche alternative.