|
| 1 | +- Feature Name: profile_dependencies |
| 2 | +- Start Date: 2018-01-08 |
| 3 | +- RFC PR: [rust-lang/rfcs#2282](https://github.com/rust-lang/rfcs/pull/2282) |
| 4 | +- Rust Issue: [rust-lang/rust#48683](https://github.com/rust-lang/rust/issues/48683) |
| 5 | + |
| 6 | + |
| 7 | +# Summary |
| 8 | +[summary]: #summary |
| 9 | + |
| 10 | +Allow overriding profile keys for certain dependencies, as well as providing a way to set profiles in `.cargo/config` |
| 11 | + |
| 12 | +# Motivation |
| 13 | +[motivation]: #motivation |
| 14 | + |
| 15 | +Currently the "stable" way to tweak build parameters like "debug symbols", "debug assertions", and "optimization level" is to edit Cargo.toml. |
| 16 | + |
| 17 | +This file is typically checked in tree, so for many projects overriding things involves making |
| 18 | +temporary changes to this, which feels hacky. On top of this, if Cargo is being called by an |
| 19 | +encompassing build system as what happens in Firefox, these changes can seem surprising. |
| 20 | + |
| 21 | +This also doesn't allow for much customization. For example, when trying to optimize for |
| 22 | +compilation speed by building in debug mode, build scripts will get built in debug mode as well. In |
| 23 | +case of complex build-time dependencies like bindgen, this can end up significantly slowing down |
| 24 | +compilation. It would be nice to be able to say "build in debug mode, but build build dependencies |
| 25 | +in release". Also, your program may have large dependencies that it doesn't use in critical paths, |
| 26 | +being able to ask for just these dependencies to be run in debug mode would be nice. |
| 27 | + |
| 28 | + |
| 29 | +# Guide-level explanation |
| 30 | +[guide-level-explanation]: #guide-level-explanation |
| 31 | + |
| 32 | + |
| 33 | +Currently, the [Cargo guide has a section on this](http://doc.crates.io/manifest.html#the-profile-sections). |
| 34 | + |
| 35 | +We amend this to add that you can override dependency configurations via `profile.foo.overrides`: |
| 36 | + |
| 37 | +```toml |
| 38 | +[profile.dev] |
| 39 | +opt-level = 0 |
| 40 | +debug = true |
| 41 | + |
| 42 | +# the `image` crate will be compiled with -Copt-level=3 |
| 43 | +[profile.dev.overrides.image] |
| 44 | +opt-level = 3 |
| 45 | + |
| 46 | +# All dependencies (but not this crate itself) will be compiled |
| 47 | +# with -Copt-level=2 . This includes build dependencies. |
| 48 | +[profile.dev.overrides."*"] |
| 49 | +opt-level = 2 |
| 50 | + |
| 51 | +# Build scripts and their dependencies will be compiled with -Copt-level=3 |
| 52 | +# By default, build scripts use the same rules as the rest of the profile |
| 53 | +[profile.dev.build_override] |
| 54 | +opt-level = 3 |
| 55 | +``` |
| 56 | + |
| 57 | +Additionally, profiles may be listed in `.cargo/config`. When building, cargo will calculate the |
| 58 | +current profile, and if it has changed, it will do a fresh/clean build. |
| 59 | + |
| 60 | +# Reference-level explanation |
| 61 | +[reference-level-explanation]: #reference-level-explanation |
| 62 | + |
| 63 | +In case of overlapping rules, the precedence order is that `overrides.foo` |
| 64 | +will win over `overrides."*"` and both will win over `build_override`. |
| 65 | + |
| 66 | +So if you specify `build_override` |
| 67 | +it will not affect the compilation of any dependencies which are both |
| 68 | +build-dependencies and regular dependencies. If you have |
| 69 | + |
| 70 | +```toml |
| 71 | +[profile.dev] |
| 72 | +opt-level = 0 |
| 73 | +[profile.dev.build_override] |
| 74 | +opt-level = 3 |
| 75 | +``` |
| 76 | + |
| 77 | +and the `image` crate is _both_ a build dependency and a regular dependency; it will be compiled |
| 78 | +as per the top level `opt-level=0` rule. If you wish it to be compiled as per the build_override rule, |
| 79 | +use a normal override rule: |
| 80 | + |
| 81 | +```toml |
| 82 | +[profile.dev] |
| 83 | +opt-level = 0 |
| 84 | +[profile.dev.build_override] |
| 85 | +opt-level = 3 |
| 86 | +[profile.dev.overrides.image] |
| 87 | +opt-level = 3 |
| 88 | +``` |
| 89 | + |
| 90 | +This clash may not occur whilst cross compiling since two separate versions of the crate will be compiled. |
| 91 | +(This RFC leaves the decision of whether or not to handle this up to the implementors) |
| 92 | + |
| 93 | +It is not possible to have the same crate compiled in different modes as a build dependency and a |
| 94 | +regular dependency within the same profile when not cross compiling. (This is a current limitation |
| 95 | +in Cargo, but it would be nice if we could fix this) |
| 96 | + |
| 97 | +Put succinctly, `build_override` is not able to affect anything compiled into the final binary. |
| 98 | + |
| 99 | +`cargo build --target foo` will fail to run if `foo` clashes with the name of a profile; so avoid |
| 100 | +giving profiles the same name as possible build targets. |
| 101 | + |
| 102 | +When in a workspace, `"*"` will apply to all dependencies that are _not_ workspace members, you can explicitly |
| 103 | +apply things to workspace members with `[profile.dev.overrides.membername]`. |
| 104 | + |
| 105 | +The `panic` key cannot be specified in an override; only in the top level of a profile. Rust does not allow |
| 106 | +the linking together of crates with different `panic` settings. |
| 107 | + |
| 108 | +# Drawbacks |
| 109 | +[drawbacks]: #drawbacks |
| 110 | + |
| 111 | +This complicates cargo. |
| 112 | + |
| 113 | +# Rationale and alternatives |
| 114 | +[alternatives]: #alternatives |
| 115 | + |
| 116 | +There are really two or three concerns here: |
| 117 | + |
| 118 | + - A stable interface for setting various profile keys (`cargo rustc -- -Clto` is not good, for example, and doesn't integrate into Cargo's target directories) |
| 119 | + - The ability to use a different profile for build scripts (usually, the ability to flip optimization modes; I don't think folks care as much about `-g` in build scripts) |
| 120 | + - The ability to use a different profile for specific dependencies |
| 121 | + |
| 122 | +The first one can be resolved partially by stabilizing `cargo` arguments for overriding these. It |
| 123 | +doesn't fix the target directory issue, but that might not be a major concern. Allowing profiles to |
| 124 | +come from `.cargo/config` is another minimal solution to this for use cases like Firefox, which |
| 125 | +wraps Cargo in another build system. |
| 126 | + |
| 127 | +The second one can be fixed with a specific `build-scripts = release` key for profiles. |
| 128 | + |
| 129 | +The third can't be as easily fixed, however it's not clear if that's a major need. |
| 130 | + |
| 131 | +The nice thing about this proposal is that it is able to handle all three of these concerns. However, separate RFCs for separate features could be introduced as well. |
| 132 | + |
| 133 | +In general there are plans for Cargo to support other build systems by making it more modular (so |
| 134 | +that you can ask it for a build plan and then execute it yourself). Such build systems would be able to |
| 135 | +provide the ability to override profiles themselves instead. It's unclear if the general Rust |
| 136 | +community needs the ability to override profiles. |
| 137 | + |
| 138 | +# Unresolved questions |
| 139 | +[unresolved]: #unresolved-questions |
| 140 | + |
| 141 | +- Bikeshedding the naming of the keys |
| 142 | +- The current proposal provides a way to say "special-case all build dependencies, even if they are regular dependencies as well", |
| 143 | + but not "special-case all build-only dependencies" (which can be solved with a `!build_override` thing, but that's weird and unweildy) |
| 144 | +- It would be nice to have a way for crates to _declare_ that they use a particular |
| 145 | + panic mode (something like `allow-panic=all` vs `allow-panic=abort`/`allow_panic=unwind`, with `all` as default) |
| 146 | + so that they can assume a panic mode and cargo will refuse to compile them with anything else |
0 commit comments