Skip to content

Commit 6214e77

Browse files
authored
Merge pull request #3176 from joshtriplett/multidep
Multiple artifact deps on the same crate with different names, for different targets
2 parents a6f67c3 + 5a5a79a commit 6214e77

File tree

2 files changed

+187
-2
lines changed

2 files changed

+187
-2
lines changed

text/3028-cargo-binary-dependencies.md

+4-2
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,9 @@ For each kind of dependency, these variables are supplied to the same part of th
107107

108108
Similar to features, if other crates in your dependencies also depend on the same binary crate, and request different binaries, Cargo will build the union of all binaries requested.
109109

110-
Cargo will unify features and versions across all kinds of dependencies, including artifact dependencies, just as it does for multiple dependencies on the same crate throughout a dependency tree.
110+
Cargo will unify versions across all kinds of dependencies, including artifact dependencies, just as it does for multiple dependencies on the same crate throughout a dependency tree.
111+
112+
Cargo will not unify features across dependencies for different targets. One dependency tree may have both ordinary dependencies and artifact dependencies on the same crate, with different features for the ordinary dependency and for artifact depenencies for different targets.
111113

112114
`artifact` may be a string, or a list of strings; in the latter case, this specifies a dependency on the crate with each of those artifact types, and is equivalent to specifying multiple dependencies with different `artifact` values. For instance, you may specify a build dependency on both a binary and a cdylib from the same crate. You may also specify separate dependencies with different `artifact` values, as well as dependencies on the same crate without `artifact` specified; for instance, you may have a build dependency on the binary of a crate and a normal dependency on the Rust library of the same crate.
113115

@@ -171,7 +173,7 @@ How easily can Cargo handle a dependency with a different target specified? How
171173

172174
Currently, there's no mechanism to obtain an environment variable's value at compile time if that value is not valid UTF-8. In the future, we may want macros like `env_os!` or `env_path!`, which return a `&'static OsStr` or `&'static Path` respectively, rather than a `&'static str`. This is already an issue for existing environment variables supplied to the build that contain file paths.
173175

174-
In some cases, a crate may want to depend on a binary without unifying features or dependency versions with that binary. A future extension to this mechanism could allow cargo to build a binary crate in isolation, without attempting to do any unification.
176+
In some cases, a crate may want to depend on a binary without unifying dependency versions with that binary. A future extension to this mechanism could allow cargo to build a binary crate in isolation, without attempting to unify versions.
175177

176178
Just as a `-sys` crate can supply additional artifacts other than the built binary, this mechanism could potentially expand in the future to allow building artifacts other than the built binary, such as C-compatible include files, various types of interface definition or protocol definition files, or arbitrary data files.
177179

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

0 commit comments

Comments
 (0)