Skip to content

Commit 5640161

Browse files
joshtriplettehuss
authored andcommitted
Multiple artifact deps on the same crate with different names, for different targets
1 parent a6f67c3 commit 5640161

File tree

1 file changed

+184
-0
lines changed

1 file changed

+184
-0
lines changed
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
- Feature Name: (`multidep`)
2+
- Start Date: 2021-09-14
3+
- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000)
4+
- Tracking Issue: [rust-lang/cargo#0000](https://github.com/rust-lang/cargo/issues/0000)
5+
6+
# Summary
7+
[summary]: #summary
8+
9+
Allow Cargo packages to depend on the same crate multiple times with different
10+
dependency names, to support artifact dependencies for multiple targets.
11+
12+
# Motivation
13+
[motivation]: #motivation
14+
15+
[RFC 3028](https://github.com/rust-lang/rfcs/blob/HEAD/text/3028-cargo-binary-dependencies.md)
16+
specified "artifact dependencies", allowing crates to depend on a compiled
17+
binary provided by another crate, for a specified target.
18+
19+
Some crates need to depend on binaries for multiple targets; for instance, a
20+
virtual machine that supports running multiple targets may need firmware for
21+
each target platform. Sometimes these binaries may come from different crates,
22+
but sometimes these binaries may come from the same crate compiled for
23+
different targets.
24+
25+
This RFC enables that use case, by allowing multiple dependencies on the same
26+
crate with the same version, as long as they're each renamed to a different
27+
name. This allows multiple artifact dependencies on the same crate for
28+
different targets.
29+
30+
Note that this RFC still does not allow dependencies on different
31+
semver-compatible versions of the same crate, only multiple dependencies on
32+
exactly the same version of the same crate.
33+
34+
# Guide-level explanation
35+
[guide-level-explanation]: #guide-level-explanation
36+
37+
Normally, you may only have one dependency on a given crate with the same
38+
version. You may depend on different incompatible versions of the same crate
39+
(for instance, versions `0.1.7` and `1.2.4`), but if you specify two or more
40+
dependencies on a crate with the same version, Cargo will treat this as an
41+
error.
42+
43+
However, Cargo allows [renaming
44+
dependencies](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#renaming-dependencies-in-cargotoml),
45+
to refer to a crate by a different name than the one it was published under. If
46+
you use this feature, you may have multiple dependencies on exactly the same
47+
version of the same crate, as long as the dependencies have different names.
48+
For example:
49+
50+
```toml
51+
[dependencies]
52+
example1 = { package = "example", version = "1.2.3" }
53+
example2 = { package = "example", version = "1.2.3" }
54+
```
55+
56+
This can be useful if you need to refer to the same crate by two different
57+
names in different portions of your code.
58+
59+
This feature provides particular value in specifying artifact dependencies for
60+
different targets. You may specify multiple artifact dependencies on the same
61+
crate for different targets, as long as those dependencies have different
62+
names:
63+
64+
```toml
65+
[dependencies]
66+
example_arm = { package = "example", version = "1.2.3", artifact = "bin", target = "aarch64-unknown-none" }
67+
example_riscv = { package = "example", version = "1.2.3", artifact = "bin", target = "riscv64imac-unknown-none-elf" }
68+
example_x86 = { package = "example", version = "1.2.3", artifact = "bin", target = "x86_64-unknown-none" }
69+
```
70+
71+
Cargo will make the binaries from each of these artifacts available under the
72+
specified name. For instance, in this example, binaries from `example` built
73+
for `riscv64imac_unknown_none_elf` will appear in the directory specified by
74+
the environment variable `CARGO_BIN_DIR_EXAMPLE_RISCV`, while binaries from
75+
`example` built for `aarch64-unknown-none` will appear in the directory
76+
specified by `CARGO_BIN_DIR_EXAMPLE_ARM`.
77+
78+
# Reference-level explanation
79+
[reference-level-explanation]: #reference-level-explanation
80+
81+
Cargo allows specifying multiple dependencies on the same crate, as long as all
82+
such dependencies unify to the same version with the same features, and have
83+
different dependency names specified. Cargo will make the dependency available
84+
under each specified name.
85+
86+
Multiple artifact dependencies on the same crate may have different `target`
87+
fields. In this case, cargo will build the dependency for each specified
88+
`target`, and make each build available via the corresponding dependency name.
89+
90+
Cargo provides your crate with the standard set of environment variables for
91+
each artifact dependency: `CARGO_<ARTIFACT-TYPE>_DIR_<DEP>` for the directory
92+
containing the artifacts (e.g. `CARGO_BIN_DIR_EXAMPLE`) and
93+
`CARGO_<ARTIFACT-TYPE>_FILE_<DEP>_<NAME>` for each artifact by name (e.g.
94+
`CARGO_BIN_FILE_EXAMPLE_mybin`). Note that the name you give to the dependency
95+
determines the `<DEP>`, but does not affect the `<NAME>` of each artifact
96+
within that dependency.
97+
98+
Cargo will unify features and versions across all kinds of dependencies,
99+
including multiple artifact dependencies, just as it does for multiple
100+
dependencies on the same crate throughout a dependency tree. A dependency tree
101+
may only include one semver-compatible version of a given crate, but may
102+
include multiple semver-incompatible versions of a given crate.
103+
104+
Building an artifact dependency for multiple targets may entail building
105+
multiple copies of other dependencies, which must similarly unify within a
106+
dependency tree.
107+
108+
Multiple dependencies on the same crate may specify different values for
109+
`artifact` (e.g. to build a library and/or multiple specific binaries), as well
110+
as different values for `target`. Cargo will combine all the entries for a
111+
given `target`, and build all the specified artifacts for that target.
112+
Requesting a specific artifact for one target will not affect the artifacts
113+
built for another target.
114+
115+
[Profile
116+
overrides](https://doc.rust-lang.org/cargo/reference/profiles.html#overrides)
117+
are specified in terms of the original crate name, not the dependency name;
118+
thus, Cargo does not currently support overriding profile settings differently
119+
for different artifact dependencies.
120+
121+
Until this feature is stabilized, it will require specifying the nightly-only
122+
option `-Z multidep` to `cargo`. If `cargo` encounters multiple dependencies on
123+
the same crate and does not have this option specified, it will continue to
124+
emit an error.
125+
126+
# Drawbacks
127+
[drawbacks]: #drawbacks
128+
129+
This feature will require Cargo to handle multiple copies of the same crate
130+
within the dependencies of a single crate. While Cargo already has support for
131+
handling multiple copies of the same crate within a full dependency tree, Cargo
132+
currently rejects multiple copies of the same crate within the dependencies of
133+
a single crate, and changing that may require reworking assumptions made within
134+
some portions of the Cargo codebase.
135+
136+
# Rationale and alternatives
137+
[rationale-and-alternatives]: #rationale-and-alternatives
138+
139+
Cargo already allows a dependency tree to contain multiple dependencies on the
140+
same crate (whether as an artifact dependency or otherwise), by introducing an
141+
intermediate crate. This feature provides that capability within the
142+
dependencies of a single crate, which should avoid the multiplicative
143+
introduction (and potentially publication) of trivial intermediate crates for
144+
each target.
145+
146+
This RFC handles building an artifact dependency for multiple targets by
147+
requiring a different name for the dependency on each target. As an
148+
alternative, we could instead allow specifying a list of targets in the
149+
`target` field. This would provide a more brief syntax, but it would require
150+
Cargo to incorporate the target name into the environment variables provided
151+
for the artifact dependency. Doing so would complicate artifact dependencies
152+
significantly, and would also complicate the internals of Cargo. Separating
153+
these dependencies under different names makes them easier to manage and
154+
reference, both within Cargo and within the code of the crate specifying the
155+
dependencies.
156+
157+
While this RFC has artifact dependencies as a primary use case, it also allows
158+
specifying multiple non-artifact dependencies on the same crate with different
159+
names. This seems like a harmless extension, equivalent to `use name1 as
160+
name2;` and similar. However, if it adds any substantive complexity, we could
161+
easily restrict this feature exclusively to artifact dependencies, without any
162+
harm to the primary use case.
163+
164+
# Future possibilities
165+
[future-possibilities]: #future-possibilities
166+
167+
In some cases, a crate may want to depend on a binary without unifying features
168+
or dependency versions with that binary. A future extension to this mechanism
169+
could allow cargo to build multiple copies of a binary crate for different
170+
targets without attempting to do any unification. This would allow enabling
171+
different sets of features for different targets.
172+
173+
This RFC does not provide a means of specifying different profile overrides for
174+
different dependencies on the same crate. A future extension to this mechanism
175+
could take the dependency name or target into account and allow specifying
176+
different profile overrides for each dependency.
177+
178+
When building an artifact dependency for a target, the depending crate may wish
179+
to specify more details of how the crate gets built, including target-specific
180+
options (e.g. target features or target-specific binary layout options). Cargo
181+
currently exposes such options via `.cargo/config.toml`, but not via
182+
`Cargo.toml`. If and when we provide a means to specify such options via
183+
`Cargo.toml`, we need to allow specifying those options not just by dependency
184+
name but also by target.

0 commit comments

Comments
 (0)