I am trying to find a way to prohibit introducing non-Rust dependencies into my Rust project. E.g. if one of my direct or transitive dependencies is a non-Rust, I want to stop compilation process with some error. I am mostly interested in prohibiting C and C++ deps (usually packed as a *-sys package) but prohibiting all non-Rust deps (like D, Zig, etc.) is a final goal.
I didn't find such functionality in Cargo itself. I've also checked cargo-deny but no success too. Maximum what I can do with cargo-deny is maintain my own list of non-Rust deps and "ban" them explicitly. It's not a viable option in my case since at any time new non-Rust dependency can be introduced into my dependency tree mistakenly by me or just by one of my Rust dependency. Maintaining an allowed list of "good" dependencies is also is not an option since it requires a ridiculous amount of efforts. Looking only into a crate name (like *-sys pattern) is not a robust solution since anyone can name a non-Rust package without this suffix.
Why do I want to do it? There are several reasons:
Cybersecurity government recommendations. In some cases, any C or C++ dependency can be considered as an additional vector attack during cybersec evaluation/certification, etc. (remember US CISA articles about non-memory safe languages). I have at least one use case, where it can become a business problem.
Compiler optimizations. When any of my dependencies is non-Rust, I get an additional bunch of problems during applying LTO and PGO, because in this case I need to do cross-lang LTO and cross-lang PGO. it's much more difficult thing to maintain compared to Rust-only LTO and PGO. I want to use all of these optimizations for the whole application, and don't care about cross-lang stuff.
I have several ideas about how it could be implemented like checking the whole cargo tree, finding all build.rs scripts, and banning all things with invoking cc-rs or something like that (btw this way also has its own flaws). But now I am looking for something ready-to-use.
One rough way to do this would be to set up PATH so that it does not include a C compiler, or so that well-known C compiler names (cc, gcc, clang) are actually stubs that always fail. The more thorough version would be to use a container/sandbox which does not include access to a C compiler (or any other compiler or assembler) at all.
This does not prevent the package from linking to an object file distributed as part of the package, however.
It is impractical to make a program that runs on an OS like Linux, Windows or MacOS without involving C code st the layer you talk to tjr OS. On Unixes and Linux you have libc, on Windows you still need to talk to user32.dll, ntdll.dll etc. Rust std depend on these.
Now, if you are doing microcontroller stuff, that is another matter.
Rustc uses the system C compiler to invoke the linker, so that will not work.
That doesn't mean you can't avoid including any C code in the executable itself. You could dynamically link against system libraries but avoid any other C code.
You can rename gcc/clang to a different name that cc can't find it and then point -Clinker to it. Or if you only have gcc, you can keep just the gcc executable (the driver that coordinates all subtools) and throw away cc1 (the actual C compiler) and possibly as (the assembler) and cpp (the C preprocessor). cc, as and cpp aren't necessary when only using gcc as linker driver.
Yes, I was thinking about this way too But wanted to find something a bit less invasive. Dynamic linking to system libraries is okay (at least in my case), so it won't be a big deal. Complete sandboxing is ofc will work, but it's not a viable option for me.
Yeah, I was thinking about prohibiting deps with build.rs too but considered that this way could be with a bit too many false positives since build.rs can be used actually for anything, not only building C deps. However, I didn't check this hypothesis in practice like "How many percents of Rust crates use build.rs for something besides building a C dependency". So I don't know how "painful" would be maintaining this "allow-build-scripts" list and updating it per cargo update/adding a new dependency to a Rust projects, etc. Anyway, could be a good motivation to collect such statistics in practice