FWIW, I would very much like to see this happen and am currently available as a freelancer. If you work for or know of some organization that would be interested in funding this, please contact me. (I have previously made several contributions to Cargo and wrote two accepted Rust RFCs.)
another usecase to consider: controlling what size of integer is used for a certain id type.
currently this can be implemented by having multiple features representing different integer widths, and using the largest value.
it's worth noting that this doesn't actually require any changes to rustc
. indeed, features themselves don't require rustc support. it's just a standardized case of the cfg
system.
It would be amazing if globals wasn't limited to enums. In the embedded world you might for example wrap an sdk that lets you configure the number of Bluetooth connections with a define in a c-header. I would like that to be configurable by the app crate and not the sdk-wrapper.
I would love to see for a proper support for configuration flags in Cargo.toml and tooling to be implemented, but I do not quite like the proposal in its current form.
I have 3 motivating examples which currently rely on configuration flags:
aes
crate uses tocfg
to force backend selection. It's useful for testing and to work around the lack of negative target features. Similarcfg
s are used in some other RustCrypto crates.getrandom
usescfg
to enable optional backends.- In private code we use
cfg
to switch between two different environments: one useful for testing purposes, but which introduces certain overheads, another for production which is more efficient, but introduces certain usage restrictions (the environment must be initialized only once during program execution).
I believe that "globals" should be crate-specfic. In other words, as an example I should be able to use static linking for git2
and dynamic linking for openssl
in one project even if both define sys
globals. It also should be possible to provide different globals for semver-incompatible versions of one crate. Finally, tooling should issue warnings (or maybe even opt-in compilation errors) when user set nonexistent globals.
The proposal is also not clear whether optional dependencies dependent on globals will be included in Cargo.lock or not. Some users are sensitive to lock file bloat, so it's worth to clarify this aspect.
I would prefer for globals to look roughly like this:
[package]
name = "git2"
version = "0.1.0"
[globals.sys]
values = ["static", "dyn", "auto"]
default = "auto"
[package]
name = "git2"
version = "0.2.0"
[globals.sys]
# renamed "dyn" to "dynamic", added "pure"
values = ["static", "dynamic", "pure"]
default = "pure"
[package]
name = "git2-user"
version = "0.0.0"
# if used in a library crate influences only tests, benhcmarks, examples, etc.
# and does not influences downstream users
[[set-globals]]
package = "git2"
# if both git2 v0.1 and v0.2 are included in the dependency tree,
# then this global value will be applied to both
name = "sys"
value = "static"
Alternative configurations:
[package]
name = "git2-user"
version = "0.0.0"
[[set-globals]]
package = "git2"
name = "sys"
# This value is pplied only to git2 v0.1,
# while v0.2 will use the default value "pure"
version = "0.1"
value = "dyn"
[package]
name = "git2-user"
version = "0.0.0"
[[set-globals]]
package = "git2"
name = "sys"
version = "0.1"
value = "static"
[[set-globals]]
package = "git2"
name = "sys"
version = "0.2"
value = "dynamic"
This approach may result in compiler warnings (or errors) on cargo update
(e.g. after update from git2 v0.1 to v0.2). On the first glance it looks like a drawback, but I believe it's an advantage, since users would be notified about changes in their dependencies on which they may rely.
One of recommendations for using globals would be that they should not influence public API of the crate. They may do it, but API changes should be additive and intended only for root-level crates.
I think it's a bad idea to use globals for these because they commonly influence public API. Library crates would need an ability to declare that they require a global to be set, which opens a big can of compatibility worms.
The existing crate features work mostly fine for these use cases. If we want improve ergonomics in this area, it's probably better to develop a separate feature for "shared" crate features.
The first two comments in this thread (at least) cover some of this topic. Global or per-crate each come with their own trade offs and would need to be explored in moving this forward.