Skip to content

Commit c09e805

Browse files
authored
Merge pull request #2196 from joshtriplett/metabuild
metabuild: semantic build scripts for Cargo
2 parents 9c1609f + 6532201 commit c09e805

File tree

1 file changed

+142
-0
lines changed

1 file changed

+142
-0
lines changed

text/2196-metabuild.md

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
- Feature Name: `metabuild`
2+
- Start Date: 2017-10-31
3+
- RFC PR: [rust-lang/rfcs#2196](https://github.com/rust-lang/rfcs/pull/2196)
4+
- Rust Issue: [rust-lang/rust#49803](https://github.com/rust-lang/rust/issues/49803)
5+
6+
# Summary
7+
8+
Introduce a mechanism for Cargo crates to make use of declarative build
9+
scripts, obtained from one or more of their dependencies rather than via a
10+
`build.rs` file. Support experimentation with declarative build scripts in the
11+
crates.io ecosystem.
12+
13+
# Motivation
14+
15+
Cargo has many potentially desirable enhancements planned for its build
16+
process, including integrating a Cargo build process with native dependencies,
17+
and integrating with broader build systems or projects, such as massive
18+
mono-repo build systems, or Linux distributions.
19+
20+
Right now, the biggest problem facing such systems involves `build.rs` scripts
21+
and the arbitrary things those scripts can do. Such build systems typically
22+
need more information about native dependencies that are embedded in
23+
`build.rs`, so that they can provide their own versions of those dependencies,
24+
or encode appropriate dependencies in another metadata format such as the
25+
dependencies of their packaging system or build system. Right now, such systems
26+
often have to override the `build.rs` script themselves, and do custom
27+
per-crate integration work, manually; there’s no way to introspect what
28+
`build.rs` does, or get a declarative semantic description of the build script.
29+
30+
At the same time, we don't yet have sufficiently precise information about the
31+
needs of such systems to design an ideal set of Cargo metadata on the first
32+
try. Rather than attempt to architect the perfect solution from the start, and
33+
potentially create an intermediate state that will require long-term support,
34+
we propose to allow experimentation with declarative build systems within the
35+
crates.io ecosystem, in crates supplying modular components similar to
36+
`build.rs` scripts. By convention, such scripts should typically read any
37+
parameters and metadata they need from `Cargo.toml`, in a form that other
38+
build-related software can read as well.
39+
40+
# Guide-level explanation
41+
42+
In the `[package]` section of `Cargo.toml`, you can specify a field
43+
`metabuild`, whose value should be a string or list of strings, each one
44+
exactly matching the name of a dependency specified in the
45+
`[build-dependencies]` section. If you specify `metabuild`, you must not
46+
specify `build`, and Cargo will ignore the `build.rs` file if any.
47+
48+
When Cargo builds a crate that specifies a `metabuild` field, at the point when
49+
it would have built and run `build.rs`, it will instead invoke the
50+
`metabuild()` function from each of the specified crates in order.
51+
52+
In effect, Cargo will act as though it had a `build.rs` file containing an
53+
`extern crate` line for each string, in order, as well as a `main` function
54+
that calls the `metabuild` function in each such crate, in order. For example,
55+
if the crate contains `metabuild = ["pkgc", "parsegen"]`, then the effective
56+
`build.rs` will look like this:
57+
58+
```rust
59+
extern crate pkgc;
60+
extern crate parsegen;
61+
62+
fn main() {
63+
pkgc::metabuild();
64+
parsegen::metabuild();
65+
}
66+
```
67+
68+
Note that the `metabuild` functions intentionally take no parameters; they
69+
should obtain any parameters they need from `Cargo.toml`. Various crates to
70+
parse `Cargo.toml` exist in the crates.io ecosystem.
71+
72+
Also note that the `metabuild` functions do not return an error type; if they
73+
fail, they should panic.
74+
75+
Future versions of this interface with higher integration into Cargo may
76+
incorporate ways for Cargo to pass pre-parsed data from `Cargo.toml`, or ways
77+
for the `metabuild` functions to return semantic error information. Metabuild
78+
interfaces may also wish to run scripts in parallel, provide dependencies
79+
between them, or orchestrate their execution in many other ways. This minimal
80+
specification allows for experimentation with such interfaces within the
81+
crates.io ecosystem, by providing an adapter from the raw metabuild interface.
82+
83+
# Reference-level explanation
84+
85+
Cargo's logic to invoke `build.rs` should check for the `metabuild` key, and if
86+
present, create and invoke a temporary `build.rs` as described above. For an
87+
initial implementation, Cargo can generate and cache that `build.rs` in the
88+
`target` directory when needed, alongside the built version of the script.
89+
90+
For Cargo schema versioning, using the `metabuild` key will result in the crate
91+
requiring a sufficiently new version of Cargo to understand `metabuild`. This
92+
should start out as an unstable Cargo feature; in the course of experimentation
93+
and stabilization, the implementation of this feature may change, requiring
94+
adaptation of experimental build scripts.
95+
96+
If any of the strings mentioned in `metabuild` do not match one of the
97+
build-dependencies, Cargo should produce an error (*before* attempting to
98+
generate and compile a `build.rs` script). However, if a string matches a
99+
conditional build-dependency, such as one conditional on a feature or target,
100+
then Cargo should only invoke that build-dependency's `metabuild` function when
101+
those conditions apply.
102+
103+
Cargo's documentation on `metabuild` should recommend a preferred crate for
104+
parsing data from `Cargo.toml`, to avoid every provider of a metabuild function
105+
from reimplementing it themselves.
106+
107+
As we develop other best practices for the development and implementation of
108+
metabuild crates, we should extract and standardize common code for those
109+
practices as crates.
110+
111+
# Drawbacks
112+
113+
While Cargo can change this interface arbitrarily while still unstable, one
114+
stabilized, Cargo will have to support it forever, even if we develop a new
115+
build/metabuild interface in the future.
116+
117+
# Rationale and Alternatives
118+
119+
`metabuild` could always point to a single crate, and not support a list of
120+
crate names; a crate in the crates.io ecosystem could easily provide the "list
121+
of crate names" functionality, along with more advanced flows of information
122+
from one such crate to another. However, many simple cases will only want to
123+
invoke a list of crates in order, and handling that one case within Cargo will
124+
simplify initial experimentation while still allowing implementation of more
125+
complex logic via other crates in the crates.io ecosystem.
126+
127+
`metabuild()` functions could take parameters, return errors, or make use of
128+
traits. However, this would require providing appropriate types and traits for
129+
all of those, as well as a helper crate providing those types and traits, and
130+
we do not yet know what interfaces we need or want. We propose experimenting
131+
via the crates.io ecosystem first, before considering such interfaces.
132+
133+
Cargo could compile and run a separate `build.rs`-like script to run each
134+
metabuild function independently, rather than a single script that invokes all
135+
of them.
136+
137+
We could avoid introducing an extensible mechanism, and instead introduce
138+
individual semantic build interfaces one-by-one within Cargo itself. However,
139+
this would drastically impair experimentation and development, and in
140+
particular this would make it more difficult to evaluate multiple potential
141+
approaches to any given piece of build functionality. Such an interface would
142+
also not provide an obvious path to support code generators.

0 commit comments

Comments
 (0)