Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
Centril opened this issue Dec 18, 2017 · 14 comments
Open

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

Centril opened this issue Dec 18, 2017 · 14 comments
Labels
A-environment-variables Area: environment variables A-features Area: features — conditional compilation C-feature-request Category: proposal for a feature. Before PR, ping rust-lang/cargo if this is not `Feature accepted` S-propose-close Status: A team member has nominated this for closing, pending further input from the team

Comments

@Centril
Copy link

Centril commented Dec 18, 2017

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
@alexcrichton alexcrichton added the C-feature-request Category: proposal for a feature. Before PR, ping rust-lang/cargo if this is not `Feature accepted` label Dec 18, 2017
@Centril
Copy link
Author

Centril commented Jan 22, 2018

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.

@carols10cents carols10cents added A-features Area: features — conditional compilation A-environment-variables Area: environment variables labels Jan 22, 2018
@durka
Copy link
Contributor

durka commented Mar 19, 2018

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

@Centril
Copy link
Author

Centril commented Mar 19, 2018

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
Copy link
Contributor

durka commented Mar 19, 2018

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
Copy link
Member

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

@alexcrichton
Copy link
Member

I believe so!

@Centril
Copy link
Author

Centril commented Oct 30, 2018

@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
Copy link
Member

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

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

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.

weihanglo added a commit to weihanglo/git2-rs that referenced this issue Jul 11, 2023
Specify `LIBGIT2_NO_VENDOR` to force to use system libgit2.

Due to the additive nature of Cargo features, if some crate in the
dependency graph activates `vendored` feature, there is no way to
revert it back. This env var serves as a workaround for this purpose.

An alternative is having `no_vendored` feature. we still need to
modify `build.rs` to make both `vendored` and `no_vendored` play
nice with each other (or bail out as they are mutual-exclusive).
However, therer is no way to activate a Cargo feature via environment
variable (see rust-lang/cargo#4829). Altering environment variables
may be the only way to interact with some external build systems.

Some prior arts:

* `OPENSSL_NO_VENDOR` in `openssl` crate, which serves the exact
  purpose of `LIBGIT2_NO_VENDOR` [^1].
* Crate `ssh2` has a similar `LIBSSH2_SYS_USE_PKG_CONFIG`, but it
  doesn't force to do so. It still falls back to vendored lib [^2].

[^1]: https://github.com/sfackler/rust-openssl/blob/50787ed35bf9efa9dd3cbb1993a2564014b67489/openssl/src/lib.rs#L65
[^2]: https://github.com/alexcrichton/ssh2-rs/blob/d9a1dfac4b8c09c5437eb477606b82aa4f67b092/libssh2-sys/build.rs#L22-L33
weihanglo added a commit to weihanglo/git2-rs that referenced this issue Jul 11, 2023
Specify `LIBGIT2_NO_VENDOR` to force to use system libgit2.

Due to the additive nature of Cargo features, if some crate in the
dependency graph activates `vendored` feature, there is no way to
revert it back. This env var serves as a workaround for this purpose.

An alternative is having `no_vendored` feature. We still need to
modify `build.rs` to make both `vendored` and `no_vendored` play
nice with each other (or bail out as they are mutual-exclusive).
However, there is no way to activate a Cargo feature via environment
variable (see rust-lang/cargo#4829). Altering environment variables
may be the only way to interact with some external build systems.

It is also pretty common that people don't want to vendor anything and
rather to see the build fail than vendoring.

Some prior arts:

* `OPENSSL_NO_VENDOR` in `openssl` crate, which serves the exact
  purpose of `LIBGIT2_NO_VENDOR` [^1].
* Crate `ssh2` has a similar `LIBSSH2_SYS_USE_PKG_CONFIG`, but it
  doesn't force to do so. It still falls back to vendored lib [^2].

[^1]: https://github.com/sfackler/rust-openssl/blob/50787ed35bf9efa9dd3cbb1993a2564014b67489/openssl/src/lib.rs#L65
[^2]: https://github.com/alexcrichton/ssh2-rs/blob/d9a1dfac4b8c09c5437eb477606b82aa4f67b092/libssh2-sys/build.rs#L22-L33
weihanglo added a commit to weihanglo/git2-rs that referenced this issue Jul 11, 2023
Specify `LIBGIT2_NO_VENDOR` to force to use system libgit2.

Due to the additive nature of Cargo features, if some crate in the
dependency graph activates `vendored` feature, there is no way to
revert it back. This env var serves as a workaround for this purpose.

An alternative is having `no_vendored` feature. We still need to
modify `build.rs` to make both `vendored` and `no_vendored` play
nice with each other (or bail out as they are mutual-exclusive).
However, there is no way to activate a Cargo feature via environment
variable (see rust-lang/cargo#4829). Altering environment variables
may be the only way to interact with some external build systems.

It is also pretty common that people don't want to vendor anything and
rather to see the build fail than vendoring.

Some prior arts:

* `OPENSSL_NO_VENDOR` in `openssl` crate, which serves the exact
  purpose of `LIBGIT2_NO_VENDOR` [^1].
* Crate `ssh2` has a similar `LIBSSH2_SYS_USE_PKG_CONFIG`, but it
  doesn't force to do so. It still falls back to vendored lib [^2].
* Crate `curl` has a feature `force-system-lib-on-osx` to trump all
  others features. It was created primarily for Rust releases [^3].

[^1]: https://github.com/sfackler/rust-openssl/blob/50787ed35bf9efa9dd3cbb1993a2564014b67489/openssl/src/lib.rs#L65
[^2]: https://github.com/alexcrichton/ssh2-rs/blob/d9a1dfac4b8c09c5437eb477606b82aa4f67b092/libssh2-sys/build.rs#L22-L33
[^3]: https://github.com/alexcrichton/curl-rust/blob/431babf1dffe205641793353d3d57fdd36fe8534/curl-sys/build.rs#L15-L20
weihanglo added a commit to weihanglo/git2-rs that referenced this issue Jul 11, 2023
Specify `LIBGIT2_NO_VENDOR` to force to use system libgit2.

Due to the additive nature of Cargo features, if some crate in the
dependency graph activates `vendored` feature, there is no way to
revert it back. This env var serves as a workaround for this purpose.

An alternative is having `no_vendored` feature. We still need to
modify `build.rs` to make both `vendored` and `no_vendored` play
nice with each other (or bail out as they are mutual-exclusive).
However, there is no way to activate a Cargo feature via environment
variable (see rust-lang/cargo#4829). Altering environment variables
may be the only way to interact with some external build systems.

It is also pretty common that people don't want to vendor anything and
rather to see the build fail than vendoring.

Some prior arts:

* `OPENSSL_NO_VENDOR` in `openssl` crate, which serves the exact
  purpose of `LIBGIT2_NO_VENDOR` [^1].
* Crate `ssh2` has a similar `LIBSSH2_SYS_USE_PKG_CONFIG`, but it
  doesn't force to do so. It still falls back to vendored lib [^2].
* Crate `curl` has a feature `force-system-lib-on-osx` to trump all
  others features. It was created primarily for Rust releases [^3].

[^1]: https://github.com/sfackler/rust-openssl/blob/50787ed35bf9efa9dd3cbb1993a2564014b67489/openssl/src/lib.rs#L65
[^2]: https://github.com/alexcrichton/ssh2-rs/blob/d9a1dfac4b8c09c5437eb477606b82aa4f67b092/libssh2-sys/build.rs#L22-L33
[^3]: https://github.com/alexcrichton/curl-rust/blob/431babf1dffe205641793353d3d57fdd36fe8534/curl-sys/build.rs#L15-L20
weihanglo added a commit to weihanglo/git2-rs that referenced this issue Jul 29, 2023
Specify `LIBGIT2_NO_VENDOR` to force to use system libgit2.

Due to the additive nature of Cargo features, if some crate in the
dependency graph activates `vendored` feature, there is no way to
revert it back. This env var serves as a workaround for this purpose.

An alternative is having `no_vendored` feature. We still need to
modify `build.rs` to make both `vendored` and `no_vendored` play
nice with each other (or bail out as they are mutual-exclusive).
However, there is no way to activate a Cargo feature via environment
variable (see rust-lang/cargo#4829). Altering environment variables
may be the only way to interact with some external build systems.

It is also pretty common that people don't want to vendor anything and
rather to see the build fail than vendoring.

Some prior arts:

* `OPENSSL_NO_VENDOR` in `openssl` crate, which serves the exact
  purpose of `LIBGIT2_NO_VENDOR` [^1].
* Crate `ssh2` has a similar `LIBSSH2_SYS_USE_PKG_CONFIG`, but it
  doesn't force to do so. It still falls back to vendored lib [^2].
* Crate `curl` has a feature `force-system-lib-on-osx` to trump all
  others features. It was created primarily for Rust releases [^3].

More motivations why this is something we want:

* We have no control over transitive dependencies that accidentally
  activate the vendored feature. And there is no way to turn it off.
* If the build environment has the wrong system libgit2, we want
  build to always fail because that is a real mistake. For example,
  libgit2 expects a range 1.6.4..1.7.0 and it silently goes vendoring
  if nothing found. We may want an explicit error like "your system
  needs a newer libgit2 to proceed".

[^1]: https://github.com/sfackler/rust-openssl/blob/50787ed35bf9efa9dd3cbb1993a2564014b67489/openssl/src/lib.rs#L65
[^2]: https://github.com/alexcrichton/ssh2-rs/blob/d9a1dfac4b8c09c5437eb477606b82aa4f67b092/libssh2-sys/build.rs#L22-L33
[^3]: https://github.com/alexcrichton/curl-rust/blob/431babf1dffe205641793353d3d57fdd36fe8534/curl-sys/build.rs#L15-L20
@epage
Copy link
Contributor

epage commented Oct 17, 2023

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.

@epage epage added the S-propose-close Status: A team member has nominated this for closing, pending further input from the team label Oct 17, 2023
@alerque
Copy link
Contributor

alerque commented Oct 17, 2023

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

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

@Oppen
Copy link

Oppen commented Jan 11, 2024

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-environment-variables Area: environment variables A-features Area: features — conditional compilation C-feature-request Category: proposal for a feature. Before PR, ping rust-lang/cargo if this is not `Feature accepted` S-propose-close Status: A team member has nominated this for closing, pending further input from the team
Projects
None yet
Development

No branches or pull requests