|
| 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