I proposed that approach quite intentionally, and you’re right, it isn’t compositional. My intent is that we don’t know yet precisely how we want to compose such build scripts; in the simplest case we just want to call all of them in some order, but in more complex cases, they might need to make information available to each other, or declare dependencies that constrain the order in a DAG, or run builds of dependencies in parallel, or expose the build steps to an external build system like bazel, or otherwise allow substituting the implementation of the composition method itself…
So, given that, my proposal is that we provide a simple interface to run one build script provided by a dependency, and then in the crates.io ecosystem, we can have a crates like metabuild that define a means of composing multiple such scripts. The first such crate can do the obvious “run a list in the order provided in Cargo.toml, and fail if any of them fail”. If we need to change or enhance the method of composition, we can just upgrade a metabuild-style crate or create a new one, rather than having to change what we’ve baked into Cargo. If we start out with a quick “good enough” way of aggregating build scripts, that raises the barrier to experimenting in that area.
If we converge on a single well-established way to aggregate build scripts, it might make sense to move that mechanism into Cargo natively, if doing so gives us some advantage. But taking a cue from the steps already baked into Cargo that we’ve talked about making more configurable and customizable, let’s not bake that in quite yet; instead, let’s minimize the surface area of the Cargo interface, and maximize the amount of experimentation we can do in the crates.io ecosystem.