cc-rs declares a 2022 minimum Rust and lints itself hard on raw pointers
Rust library for build scripts to compile C/C++ code into a Rust library
At a glance
- What is it?
- The crate nearly every Rust project with native code depends on, and the manifest is unusually candid about what that means: a deliberately old compiler floor, three of six workspace lints aimed at pointer conversions, an optional dependency on the C standard library with its standard-library feature switched off, and a published sibling crate just to find Microsoft's build tools on Windows.
- Who is it for?
- Use cc when your crate contains native code, which in practice means if you have bindings to a C library you did not write. You are not choosing an approach so much as accepting one, and the crate's job is to absorb the platform differences so you do not have to.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.
Star history
- rust-lang/cc-rs2,170 ★ · +27
| Repository | 2026-08-01 | 2026-11-14 |
|---|---|---|
| rust-lang/cc-rs | 2.1k | 2.2k |
27 Stars in the last 105 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
It compiles nothing itself, it invokes your compiler
The framing sentence in the README is the one to keep in mind: this crate does not compile code, it calls out to the default compiler for the platform.
What it produces is a static archive for Cargo to link into the crate being built, from a set of C, C++, assembly or CUDA files. What it adds over running the compiler yourself is detection: it notices cross-compilation situations and reads environment variables, then builds the command line appropriately.
The dependency list explains exactly what that involves, and it is a short one. A shell-word splitter, because compiler flags arrive as environment variables that have to be split into arguments correctly and quoting mistakes here produce confusing build failures. An optional client for Cargo's job server, so a build script running the compiler participates in Cargo's own parallelism instead of serialising against it. And a published sibling crate whose only job is locating Microsoft's build tools on Windows.
So the crate is a command-line builder with platform awareness, not a compiler front end, and every dependency serves that one job.
Half the workspace lints are about pointer safety
The workspace lint configuration is short enough to read in full, and its composition is the most informative thing in the manifest.
Six lints are enabled at warning level. One is about documentation formatting. One is a general method denylist. One prefers a specific control-flow idiom. And three are about raw pointers: one flagging a reference borrowed as a pointer, one flagging a pointer cast to a pointer, and one flagging a cast that drops or adds constness.
Three out of six being pointer conversions is not a coincidence. This crate's public surface deals in pointers into compiled code, so that is where its bugs live, and the project has decided to encode that belief in its configuration rather than in review comments.
Alongside them the workspace requires documentation on items, at warning level rather than deny. That is a softer setting, which for a library of this size is a deliberate balance: the lint exists so gaps accumulate visibly instead of being frozen in, without blocking a patch release.
The compiler floor is from 2022 on purpose
The workspace declares a minimum supported Rust version and an edition, and the version is old enough to be a statement rather than an oversight.
It is paired with the 2021 edition, and it is far below what the toolchain in the repository is almost certainly using to build itself. A crate that tracked current tooling would be easier to write.
The reason is reach. This is a build dependency, so it is pulled in by anything that compiles native code, including crates that are otherwise entirely pure Rust apart from a small binding. Raising the floor here does not inconvenience one project; it breaks the build of every downstream crate that has not also raised its own floor, transitively, across the whole dependency graph.
That is why the floor appears in the workspace rather than the package. Every crate in this repository inherits it, including the sibling that finds Windows build tools and the four development tools. So the constraint is uniform by construction and cannot drift between members.
It is also why the package metadata is almost entirely inherited: edition, version floor, repository, licence, keywords and categories are all declared once in the workspace.
One repository publishes two crates
The workspace lists five members, and one of them is a library rather than a tool.
The four development tools are a test harness, a generator for target information, a generator for Windows API bindings, and a test for the WebAssembly system interface. The fifth member is the sibling crate for locating Microsoft's build tools, and it appears twice in the manifest: once as a workspace member and once as a path dependency of the main crate, with a version attached.
That version is the tell. A path dependency with a version means the crate is published and the path exists so it can be developed and tested locally against the same source.
The practical consequence is that a Windows build resolves two crates where a Linux build resolves one, and the second one is doing something very narrow: finding a compiler. Whether that is the right shape is arguable; the alternative would be doing the search inside the main crate. Splitting it means the search logic can be versioned independently, and it also means a Windows user has a second dependency to understand.
Release tags carry the crate name as a prefix, so the release list mixes two crates' versions and reads as a single stream unless you notice the prefixes.
A dependency is pinned with its standard library switched off
There is one dependency declaration with a comment attached, and the comment is more interesting than the dependency.
On Unix, the C standard library binding is an optional dependency with its standard library feature deliberately disabled, and the comment links an upstream Cargo issue that is still open, saying the problem persists for anything using the older feature resolver.
So this is a workaround for a resolver limitation that has been open long enough to be considered settled context. Turning that feature on changes what gets linked for consumers who have not opted into the newer resolution behaviour, and the crate is choosing the conservative side at the cost of a slightly worse dependency.
It is a small entry that tells you something about the constraints this project operates under. The consumers are not just the projects you can see; they include every project on an older resolution mode, and a change that is invisible locally can be a link failure somewhere else.
The other declarations use the same pattern of care. A development dependency on a temporary-directory crate, and the job server and standard library bindings both marked optional so a consumer who does not need them does not pay for them.
The repository generates its own Windows bindings
One of the four development tools is a generator, and it is generating something a reader would expect to be a dependency.
There is a tool whose job is to produce Windows API bindings. That is an unusual thing to find in a build-script crate's repository, and the implication is that this project would rather generate the surface it needs than depend on somebody else's.
The likely reasons are practical. Generated bindings can be shaped to exactly the calls required, they do not inherit an upstream project's version cadence, and for a crate with a compiler floor measured in years, controlling that surface is worth more than reusing one.
The other three tools are conventional: a test harness, a generator for target metadata, and a WebAssembly interface test. That last one is worth noticing because it is not a platform most build scripts target.
So the workspace is not just the published crate plus a helper. It contains four internal programs that generate, test and verify, which is why the repository is bigger than a 133-word README would suggest.
The published package excludes its own tests
There is one line in the package configuration that quietly saves every downstream user a download.
The package excludes a directory of workflow files, a binary target, and the test directory. The comment attached explains the middle one: the binary target exists only to be used by tests.
So the tests are built during development and never shipped. The generated binaries and the fixtures they need are excluded too.
For a build dependency this matters more than it would for an ordinary library, because build dependencies are resolved and compiled on every machine that builds the crate, often in constrained environments and often in layers. A few hundred kilobytes of test fixtures multiplied across every downstream build is a real cost, and the fix is one line that a project can easily forget.
It also tells you something about the repository's discipline. The same manifest that inherits its metadata from the workspace, pins an old compiler floor and excludes its tests is not a manifest that has drifted.
The published package is smaller than the repository, which is the correct relationship, and it is deliberate rather than incidental.
Editorial conclusion
Use cc when your crate contains native code, which in practice means if you have bindings to a C library you did not write. You are not choosing an approach so much as accepting one, and the crate's job is to absorb the platform differences so you do not have to. Two things worth knowing. The compiler floor is deliberately ancient, so if you maintain something that pulls this in, raising it is a breaking change for your whole downstream, not just for you. And on Windows the crate depends on a separately published sibling to locate the toolchain, which means a Windows build resolves two crates rather than one.
Frequently asked questions
What is CC RS?
The crate is named cc, and it is a library for Cargo build scripts that compiles a set of C, C++, assembly or CUDA files into a static archive for Cargo to link into the crate being built. It does not compile code itself; it calls out to the default compiler for the platform and automatically detects cross-compilation situations and relevant environment variables.
Can you compile Rust to C?
Not with this crate. The direction is the other way: it is for build scripts that compile native code into a static archive to be linked into a Rust library. Its description frames it as a build-time dependency for invoking the native C compiler, not as a translator between the two languages.
What are the dependencies of cc-rs?
Three direct ones: a published sibling crate that locates Microsoft build tools on Windows, an optional client for Cargo's job server, and a shell-word splitter. There is also an optional Unix-only dependency on the C standard library binding, declared with its standard library feature deliberately disabled to work around an upstream resolver issue.
What Rust version does cc-rs support?
The workspace declares a minimum of 1.65 paired with the 2021 edition, which is deliberately old. Because this is a build dependency pulled in by anything compiling native code, raising the floor would break downstream crates transitively, so the constraint is declared once in the workspace and inherited by every member.
Why does cc-rs lint itself on raw pointers?
Three of the six workspace lints that are enabled flag raw pointer conversions: borrowing a reference as a pointer, casting a pointer to a pointer, and a cast that changes constness. That reflects what the crate actually does, handing out pointers into compiled code, and the project encodes that belief in configuration rather than in review comments.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/rust-lang-cc-rs)Star history chart for your README
[](https://hysenlabs.com/projects/rust-lang-cc-rs)Was this useful?