rust-lang / cargo

The Rust package manager
https://doc.rust-lang.org/cargo
Apache License 2.0
12.66k stars 2.41k forks source link

Feature request: Set cargo --features via environment variables #4829

Open Centril opened 6 years ago

Centril commented 6 years ago

Consider a Cargo.toml including

[features]
default = []
unstable = [] # Enables nightly features

Simply put, you'd now be able to enable unstable by setting CARGO_SET_FEATURE_UNSTABLE to "truthy". Alternatively, you'd be able to set CARGO_SET_FEATURES to a comma separated string of the features you wish to enable. This of course works for any number of features by setting more env vars or adding more to the comma separated string.

Having this capability would make .travis.yml files capable of enabling features very succinctly without relying on travis-cargo or other methods. An example:

language: rust
sudo: false
dist: trusty
rust:
- 1.22.1
- stable
- beta

matrix:
  allow_failures:
    - rust: nightly
  include:
    - rust: nightly
      env: CARGO_SET_FEATURE_UNSTABLE

cache: cargo
Centril commented 6 years ago

I think this should be fairly easily implementable by first appending a set of features to each subcommand's set of features. An example is: https://github.com/rust-lang/cargo/blob/master/src/bin/build.rs#L111

Which format would be most suitable wrt. env-vars tho? CARGO_SET_FEATURES="unstable, .." could have more flexibility in what features are allowed to be named while CARGO_SET_FEATURE_UNSTABLE could be easier to use to set different features with different independent conditions.

durka commented 6 years ago

Does this apply to dependencies or only the "top-level" crate?

Centril commented 6 years ago

Summarizing from chat on #rust-internals:

CARGO_SET_FEATURE_UNSTABLE (or if we use the other env var method) would be the same as cargo <task> --features unstable, and iirc that does not apply to dependencies directly, but the top level crate may propagate the features down if it wants to in Cargo.toml.

durka commented 6 years ago

I vaguely support this.

It feels a little strange that it only affects the top level, since other env vars, e.g. RUSTC=./hijacked_rustc.sh cargo build would apply to everything that gets compiled.

As to the question of CARGO_SET_FEATURE_$NAME vs CARGO_SET_FEATURES=$name,..., I don't know because to me it's a question of consistency vs. specificity. Other Cargo env vars, e.g. CARGO_CFG_* and CARGO_FEATURE_* (which are passed to build script), choose the first option. But the conversion from what you wrote in Cargo.toml to the environment variable name (namely, s/-/_/ and upcase), is lossy. So it would be more correct, at the cost of inconsistency, to go with the second encoding.

dwijnand commented 5 years ago

I wonder: would we want to sketch this out in an RFC in order to move this idea forward?

alexcrichton commented 5 years ago

I believe so!

Centril commented 5 years ago

@dwijnand @alexcrichton I'm a bit swamped with language design so I don't have the bandwidth to hash this out; might one of you be able to author such an RFC?

dwijnand commented 5 years ago

My bandwidth is stretched, so I would rather focus it on some higher impact changes.

(My goal here was just to help define the next steps, for any interested party.)

izderadicka commented 5 years ago

Hi I would need this feature, My use case is - I do have a cargo feature, which change compilation process for libavformat - it either uses shared library available on system (default) or download appropriate version, compiles and links statically.

On my development machine I need to use this feature always - for test, run, build etc. and it's bit annoying to always explicitly write it to commands. If tthere would be env. variable which will contain features to always use it would be nice.

I'm not experienced in you processes, but if you'll provide some basic guidance I can try to put together such RFC, I guess.

jamesmishra commented 2 years ago

Did anyone end up implementing this feature?

It would be extremely useful when compiling Rust code from language-agnostic build tools and CI servers.

For example, in a typical Python extension written in Rust, rustc/cargo is called by Maturin... which might be wrapped by the Python pip package manager... and then pip might be run by Docker, Bazel, or some other build tool.

If Cargo features can be specified via environment variables, then it would be easier to improve a Rust build without changing the API of build tools that weren't designed for Rust.

epage commented 12 months ago

The original motivation for this was when using travis and wanting to configure the implicit runs of cargo. That use case is dramatically reduced (haven't heard of anyone using travis lately).

However, the idea is more general than that: people wanting to control cargo through other layers, like the maturin example above. For myself, I'd prefer to have those build systems design the interaction, rather than us providing a bypass that may not match it (e.g. the original use case would justify a --no-default-features env variable but that could cause problems for the maturin case to not be additive).

In this thread, someone else also brought up the idea of effectively allowing per-user build parameters, including features. As this would be an environment variable, it would then apply to everything run within the context it sets, which seems like a bad take except for a gitignored .cargo/config.toml which might not be possible if the project already has one. A feature that should be always-on or always-off depending on the environment seems like a niche case. Contrast that with people doing this for development convenience for regularly testing a set of features but then that makes it difficult to test other combinations.

Based on that, I feel like there isn't enough value-add gained compared to some of the potential negative side effects that I'm going to propose to the cargo team that we close this.

alerque commented 12 months ago

Of course Travis isn't very relevant, but that's just one example of many. Maturin isn't the only other gig in town either, there are a plethera of build systems out there, whether project or distro oriented. ENV vars are are one of the most universal mechanism out there for passing options around between layers in almost all of them. I've recently been working on autotools based projects with some Rust component, and although I've found ways to make it work cargo deliberately not playing nicely is a constant source of frustration. The solutions are much more convoluted than they need to be if ENV vars could be used to set values like this.

An unrelated case with (I think) a similar outlook flaw is #6790. I know it adds a little complexity to Cargo, but it would make it so much easier to make it play nice with other tools, yet somehow gets put off and put off...

Please don't think that the onus should be on every other tool to come up with ways to work around Cargo's mono-culture approach.

maxburke commented 9 months ago

I'm running into a case where being able to set features through environment variables would be immensely useful as well.

Oppen commented 9 months ago

Same here. I'm using some meta-tool that builds several parts of a project that includes but is not limited to making cargo calls and it would be superb to have an easy way for the features defined at the top level to trickle down to all cargo calls as well as other related components that are not Rust. Otherwise, I'll need to make all of that more generic for adding a feature unrelated to the build system, which is kind of annoying.