Comment by WhyNotHugo

6 months ago

Cargo is absolutely awful. It might be better than cmake, but it still the worst part about Rust. It’s completely opaque, and intermixes a huge pile of different functionality.

Distributing Rust software is the pain that it is mostly because of how Cargo works. It’s pretty much impossible to sanely distribute something that isn’t a headache for downstream to consume.

> Cargo is absolutely awful. It might be better than cmake, but it still the worst part about Rust. It’s completely opaque, and intermixes a huge pile of different functionality.

"Absolutely awful" strikes me as wild hyperbole -- you also meant it this way as well, right? What toolchains are not absolutely awful in your mind?

Cargo isn't perfect by any stretch of the imagination -- there are a few common complaints that people have and a bunch of sharp edges (most of which have a github issue that has been open for years), but... "absolutely awful" has to be hyperbole.

Can you expand on your reasoning? Because the opposite seems to be true when it comes to projects like uv. People love the single-file executable -- easy to just compile that for a platform and have your users download it. It seems like the uv project is having a good time with that model, so I think they show it's not "impossible". Maybe they're doing something different I'm not aware of? Or maybe your use case is different, so what's impossible about your situation?

That sounds a lot like the issues some Linux distros are running into, where they expect to be able to ship one single blessed pre-compiled version of every library, and have each app load it dynamically at runtime.

But that's just not how Rust works: it's trying to fit a square peg in a round hole, and it isn't Cargo's fault that you have trouble with it.

Can you say more?

I’ve found it a joy to use compared to CMake and friends. How does it make it harder to consume something downstream? Seems easy enough to me - just share the source crate.

Are you trying to distribute pre compiled code or something like that? I can see how that would be harder - cargo doesn’t really support that use case.

How would you improve cargo?

  • > just share the source crate

    That’s a nice concrete example of something that sounds simple but is a nightmare.

    Let’s be clear: the goal is to distribute a tarball which the receiver can build. Crates won’t be packaged in the target host (that’s part of Rust’s design), so we don’t have any choice but to include them too.

    But there’s no simple way of gathering all of these. “cargo vendor” fetches all transitive dependencies for all platforms. So if any dependency supports windows, you end up with 400MB(!) of windows-only dependencies, even if your project doesn’t target windows. This makes “cargo target” useless.

    There’s “cargo-vendor-filtered”, a huge hack around this bug, but it’s also broke in subtle ways.

    In the end, if you want to distribute a tarball which a downstream can build, you can’t. Cargo works online only.

    Like I said: cargo is too opaque. There’s no command to generate a list of files that it would download for a build. There’s no command to fetch all “real” dependencies. It too opaque an monolithic, doing everything in one indivisible way. This is a great experience for the developer, but awful for anyone else.

    • > Let’s be clear: the goal is to distribute a tarball which the receiver can build.

      Thanks for clearing that up. What problem does that solve? I've never tried to do that, but I can see how it would be a pain in the neck.

      I wonder how hard that would be to fix. It doesn't sound like a difficult feature to implement in cargo. I wonder how amenable the cargo devs would be to adding something like that?

Uuuh how so?

Cargo is a blessing for any source-available project. All bundled up, a `cargo build` away. Because don't you dare say CMake or autotools are better, that's just the stockholm syndrome kicking in because you're familiar with it.

Seriously, how a CMakeLists.txt can even be compared to a Cargo.toml file? One is imperative full of arcane conditions everywhere filled with boilerplate, while Cargo.toml is a declarative manifest of the package?

Though there is one very sore point when distributing software, and that is for distribution package maintainers, because the whole ecosystem has been built around the C model and dynamic linking. That is not even the fault of cargo, since Rust's ABI is not stable thus dynamic linking would not work most of the time. Another thorn is generic stuff, which needs to be monomorphized, and as such don't work with dynamic linking (without Box<dyn>); C++ actually has the same issue and is why there are so many "header only" libraries for it.