Cargo: Conditional compilation of dependency feature based on target doesn't work

Created on 27 Mar 2016  路  20Comments  路  Source: rust-lang/cargo

Here is my use case:
The crate hyper can be compiled with or without SSL.
The target_env _gnu_ compiles fine with SSL whereas _musl_ (for static linking) doesn't.

Here is what I'd like to do:

# By default compile hyper with SSL except when target_env is musl
[target.'cfg(not(target_env = "musl"))'.dependencies]
hyper = {version="*", features=["ssl"], default-features = false}

# When target_env is musl, compile hyper without SSL
[target.'cfg(target_env = "musl")'.dependencies]
hyper = {version="*", default-features = false}

It doesn't work as intented, the hyper/ssl feature compilation is tried whatever the target platform.
I'm using cargo 0.10.0-nightly (4e6434d 2016-03-24).

A-features C-bug E-hard

Most helpful comment

Target-specific features for dependencies has been implemented and is available as a nightly-only feature on the latest nightly 2020-02-23. See the tracking issue at #7914.

If people following this issue could try it out, and leave your feedback on the tracking issue (#7914), I would appreciate it. Particularly we'd like to know if it helps your project and does it cause any breakage?

All 20 comments

Hm this is indeed surprising!

I think that this can work, but it doesn't lend itself well to the current implementation. We currently record "activated features" in resolve, but we probably need to delay what was actually activated until the very end when we're compiling crates as that's where the filtering of target-specific dependencies and such actually happens.

Are there any news on this issue?
I have the exact same problem with the "blas" crate. I want to disable its default features on Windows (since they break the build) but use the default features on Linux. My current setup:

[target.'cfg(not(windows))'.dependencies.blas]
version = "0.15.4" # We use the standard options on Linux (meaning building OpenBLAS during compilation)

[target.'cfg(windows)'.dependencies.blas]
version = "0.15.4"
default-features = false # We take care of linking a BLAS implementation on Windows ourselves (see build.rs)

Is there a workaround or do I have to modify Cargo.toml manually according to my target?

I believe I have the same problem, while trying to use specific feature in x11 crate only if a specific feature in my crate is set:

[target.'cfg(feature="my_xss")'.dependencies]
x11 = {version = "2.14", features = ["xlib", "xss"]}
[target.'cfg(not(feature="my_xss"))'.dependencies]
x11 = {version = "2.14", features = ["xlib"]}

[features]
my_xss = []

No matter what features the crate is compiled with, it always compiles x11 with xss feature. Is this supposed to be happening?

I'm also unable to cross-compile my project to both raspberry and x86_64 for testing due to this not working:

[target.'cfg(not(target_arch = "arm"))'.dependencies]
wiringpi = { version = '0.2.4' }

[target.'cfg(target_arch = "arm")'.dependencies]
wiringpi = { version = '0.2.4', features = ["development"] }

The latter would stub the wiringpi libary and just log the usage, which should be good for testing it on my development machine... Currently it doesn't compile because it's looking for a .so file that does not exist for anything other than an arm

I have the same problem depending on a path-addressed crate with features determined by target_arch.

Same problem here with nom with default features or not depending of the target.

Any news on this issue? I am encountering the exact same problem as @axos88 and @fuine. If not, is there maybe a workaround to solve the issue temporarily?

Joining, any updates?

Bumping this as well

+

I have, probably related problem with cargo for which I can't find an issue.
So my crate A has 2 dependencies B and C, both of them depend on D.
B enables a feature F in D.
B cannot be built when target_arch = "wasm32"
Same for D if feature F is enabled.

In A's Cargo.toml I write:

[dependencies]
C = "*"

[target.'cfg(not(target_arch = "wasm32"))'. dependencies]
B = "*"

In hope that it would work fine.
But B enables F in D even when target_arch = "wasm32", although it won't be built. And D fails to compile.

Does this mean I have to ensure that all my dependencies can be built with all features enabled for any platforms I want to support?
Or I have to make B optional and manually enable it for non-wasm target? And force downstream crates have a feature for B and their dependent crates and on and on until the binary?

I think that this can work, but it doesn't lend itself well to the current implementation. We currently record "activated features" in resolve, but we probably need to delay what was actually activated until the very end when we're compiling crates as that's where the filtering of target-specific dependencies and such actually happens.

@alexcrichton Is there a reason why target-specific dependencies are filtered out that late? Would it make sense and be feasible to roll that into resolution? That would seem to make this problem a lot easier to solve.

Unfortunately fixing this is likely to require intrusive fixes to how [features] works in Cargo, especially with respect to resolution of activated features. Moving feature resolution out of the resolution phase of Cargo is the most likely solution to this problem, but this is going to be difficult to solve no matter what.

How cfg dependencies filtering happens? Maybe we could make it happen immediatelly when cargo parses next Cargo.toml?

I seem to have the exact same issue when trying to get SDL2 to build properly on MacOS and Windows.

[target.'cfg(target_os = "macos")'.dependencies]
sdl2 =  { version = "0.32.2", features = ["bundled"]}

[target.'cfg(target_os = "windows")'.dependencies]
sdl2 =  { version = "0.32.2", features = ["bundled", "static-link"]}

But my Mac OS device still fails to build SDL2, since it's trying to use the static-link feature. Any suggestion on how to solve this?

Same issue.

[target.'cfg(target_arch = "wasm32")'.dependencies]
near-vm-logic = {version = "0.3.1", features = [], default-features = false }

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
near-vm-logic = {version = "0.3.1", features = ["mocks"], default-features = false }
lazy_static = "1.4.0"

@johanlindfors a workaround could be:

[dependencies]
sdl2 =  { version = "0.32.2", default-features = false }

[features]
default = []
sdl2_windows = ["sdl2/bundled", "sdl2/static-link"]
sdl2_mac = ["sdl2/bundled"]

But it would require you to explicitly specify the features when building

Thanks, that workaround will help. I guess this is still considered a bug, because the documented behavior clearly doesn't seem to work.

[target.'cfg(windows)'.build-dependencies]
winreg = "0.6"

Fails to detect debian in a docker container, using image: FROM rust:1.36.0 AS builder and executing RUN cargo build-deps --release. This causes winreg to be built which obviously fails. Can we please get a fix!?

This is the suggested rustc docker image using the suggested conditional compilation feature. IMHO this should either be fixed immediately or the official documentation ammended/removed.

EDIT: apparently build-deps does not respect the cfg tag at all. Switching to cargo build works. !?!?

Target-specific features for dependencies has been implemented and is available as a nightly-only feature on the latest nightly 2020-02-23. See the tracking issue at #7914.

If people following this issue could try it out, and leave your feedback on the tracking issue (#7914), I would appreciate it. Particularly we'd like to know if it helps your project and does it cause any breakage?

Was this page helpful?
0 / 5 - 0 ratings