For those who haven't read the post: this is about the difficulty of bootstrapping Rust and not about cargo. I was confused at first because cargo is pretty straightforward.
cargo is pretty straightforward for 95% of the cases, inconvenient for 3% of the cases, too limited for 1% of the cases, and extremely frustrating for the remaining cases. I pulled the percentages out of thin air, but this is my experience. If your use case is straightforward, it's a breeze. Otherwise, welcome to some level of hell.
I'm not them, but usually stuff around FFI. Technically you can do whatever you need via build.rs, but imperative languages like Rust aren't really good for complex dependency resolution the way declarative languages like CMake and Bazel and Nix are. So as your dependency graph gets more complex (turns from a tree into a directed acyclic graph to a directed cyclic graph) Cargo loses the ability to sequence the operations properly without destroying your sanity. Dedicated build languages tend to be easier to use for these cases (though still not easy).
I’m not sure I agree that cmake is declarative.. look at complex builds with it and it looks a lot more like a badly designed scripting language with global state everywhere
CMake can be used in a declarative fashion. So-called "Modern CMake" is declarative except for the "find" scripts which try to find the paths to various libraries on the user's system (since C has a dozen competing standards on where to put them).
Gotcha, interesting. Maybe there's a missing DAG library where you could define your build steps as functions and then express the dependencies &c in a neighboring TOML or YAML file, and it solves your DAG and executes the right functions in the right order. Sprinkle some rayon on there to parallelize tasks that are independent.
The usual way to do that is just to use a more general build system to call Cargo (or to call rustc directly) and whatever other language(s) compilers you need. Cargo is a Rust-specific build system, it's not really designed to build other language's code easily (and doing so isn't a priority).
> it's not really designed to build other language's code easily
That's quite funny to read, when the most low level crates rely on the cc crate to build C code (dependent of cc with the most downloads is backtrace, used by libstd, following that, openssl-sys, ring, libz-sys, you'll see those close to everywhere). But I see what you mean.
I guess the clearer way to state my point is that possibility and convenience are different things.
`build.rs` scripts are Turing complete, and you can make syscalls, so you can call arbitrary other build systems. The difference in difficulty varies from language to language: C usually has few dependencies (because dependency management is fragmented and thus difficult) and so is often straightforward to compile, but other languages aren't always as easy.
With a tangled mess of FFI dependencies Cargo stops being the best tool for the job.
Here's one tiny example:
Want to link a static library that is also built from rust code? Yeah, you can make that work somehow by spawning another cargo from build.rs. Oh, you wanted to do that in a workspace? Ah no sorry, cargo is going to dead lock.
The locking is super frustrating, I have cargo & rust-analyzer wrestle for it all the time, and my hacky solution for it so engrained that I just forgot it even happens until you mentioned.
Corollary of my example: when some hacky things rely on cargo to work (like some crate that does magic by using the output of cargo metadata (that actually exists, IIRC, or if not exactly that, something along those lines)), you better hope that the crate using those hacky things doesn't end up in your dependencies when you're using a workspace.