You also bet on wrong languages. M4 is battle-tested, stood the test of time, and is much more stable.
Or more precisely, as a result of that monoculture there is a single implementation of build.rs and it cannot interoperate with anything else. If cargo could optionally generate a build.ninja file or some JSON with the command it runs, it would be so much easier.
However, the experience when doing pure Rust is night and day compared with stuff like CMake. And even in a polyglot build, the Cargo manifest is a reasonably good starting point, as argued recently by matklad[1].
Obviously, build systems and package managers at large scale are very challenging to get right, otherwise we'd have a good solution by now. I personally think Bazel is a pretty good step in the right direction, but it's very clunky and awkward for smaller projects. I found Neil Mitchell's classification[2] useful. Cargo is best-in-class for the "small" and arguably "medium" cases, but starts showing its limitations beyond that. Bazel is the reverse, one of the few really workable choices for "huge" but not a great experience otherwise.
[1]: https://matklad.github.io/2023/03/28/rust-is-a-scalable-lang...
[2]: https://neilmitchell.blogspot.com/2021/09/small-project-buil...
https://fuchsia.googlesource.com/fuchsia/+/master/tools/carg...
I like the Meson model where the meta-build system is opinionated (not as much as cargo in the case of Meson, but still quite a bit) but, at the same time, it doesn't itself take care of the build. The build is done via build.ninja, static analysis and other tools use compile_commands.json. There is no reason why cargo couldn't work this way and even preserve the same command line interface.