In general I’m looking for solutions for the motivations of this RFC, this is a strawman proposal that solves these problems, however other ideas would be good too (and I’ve mentioned some in the RFC). In general I’m not sure what the best way to approach this problem is, there are multiple possible ways of solving it, and it would be good to have some rough consensus on which direction to go in before I write a proper RFC.
Summary
Add the ability to create custom profiles in Cargo.toml, to provide further control over how the project is built. Allow overriding profiles for certain dependency trees.
Motivation
Currently the “stable” way to tweak build parameters like “debug symbols”, “debug assertions”, and “optimization level” is to edit Cargo.toml.
This file is typically checked in tree, so for many projects overriding things involves making temporary changes to this, which feels hacky. On top of this, if Cargo is being called by an encompassing build system as what happens in Firefox, these changes can seem surprising. There are currently two main profiles in Cargo (“dev” and “release”), and we’re forced to fit everything we need into these two categories. This isn’t really enough.
Furthermore, this doesn’t allow for much customization. For example, when trying to optimize for compilation speed by building in debug mode, build scripts will get built in debug mode as well. In case of complex build-time dependencies like bindgen, this can end up significantly slowing down compilation. It would be nice to be able to say “build in debug mode, but build build dependencies in release”. Also, your program may have large dependencies that it doesn’t use in critical paths, being able to ask for just these dependencies to be run in debug mode would be nice.
Guide-level explanation
Currently, the Cargo guide has a section on this.
We amend this to add that you can define custom profiles with the profile.foo
key syntax. These can be invoked via
cargo build --profile foo
. The dev
/doc
/bench
/etc profiles remain special.
Custom profiles can also be “included” into other profiles. This can be done with an include
key:
[profile.dev]
debug = true
include = my_custom_profile # implies opt-level = 4, lto = false
[profile.my_custom_profile]
opt-level = 2
lto = false
The include
key can scope where it gets included.
[profile.dev]
debug = true
opt-level = 0
[profile.dev.include]
profile = my_custom_profile
type = ["build"] # can be "build", "direct", or both, default is both
[profile.my_custom_profile]
opt-level = 2
This will mean that build scripts and all dependencies of build scripts will be built with my_custom_profile
.
You can also scope to specific crates:
[profile.dev]
debug = true
opt-level = 0
[profile.dev.include]
profile = my_custom_profile
crates = ["syn", "regex=0.0.4"] # can specify dependencies or full semver dependency specs
[profile.my_custom_profile]
opt-level = 2
which will mean that only the listed crates will inherit this specification.
Reference-level explanation
(Unsure if there’s much more that can go here)
In case of conflicting requirements imposed by multiple includes
, the one mentioned latest in the include tree (preorder) is used.
You can mention multiple includes at once, using the TOML [[key]]
syntax:
[profile.dev]
debug = true
opt-level = 0
[[profile.dev.include]]
profile = foo
crates = ["foo"]
[[profile.dev.include]]
profile = bar
crates = ["bar"]
Drawbacks
This complicates cargo.
Rationale and alternatives
There are really two or three concerns here:
- 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) - 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) - The ability to use a different profile for specific dependencies
The first one can be resolved partially by stabilizing cargo
arguments for overriding these. It doesn’t fix the target directory issue, but that might not be a major concern.
The second one can be fixed with a specific build-scripts = release
key for profiles.
The third can’t be as easily fixed, however it’s not clear if that’s a major need.
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.
In general there are plans for Cargo to support other build systems by making it more modular (so that you can ask it for a build plan and then execute it yourself). Such build systems would be able to provide the ability to override profiles themselves instead. It’s unclear if the general Rust community needs the ability to override profiles.
Unresolved questions
- Bikeshedding the naming of the keys
- The priority order when doing resolution
- What should be done with dependencies that are both build and regular dependencies