Specifying build-dependency for different target

Hi, I'm building a library crate and it needs to be built as x86_64-unknown-linux-gnu and wasm32-unknown-unknown. Here's the Cargo.toml.

[package]
name = "xxxx"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib", "rlib"]

[dependencies]
thiserror = "1"
prost = "0.13"

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
tonic = { version = "0.12.3", default-features = false, features = [
        "prost",
        "codegen",
        "channel",
]}

[target.'cfg(target_arch = "wasm32")'.dependencies]
tonic = { version = "0.12.3", default-features = false, features = [
        "prost",
        "codegen",
]}

[target.'cfg(not(target_arch = "wasm32"))'.build-dependencies]
tonic-build = "0.12"

[target.'cfg(target_arch = "wasm32")'.build-dependencies]
tonic-build = { version = "0.12", default-features = false, features = [
    "prost",
] }

I need different features for tonic-build, but it seems that cargo only recognizes the not(target_arch = "wasm32") branch. cargo tree --target=wasm32-unknown-unknown shows the same build-dependencies features as the x86 target.

build.rs

fn main() -> Result<(), Box<dyn std::error::Error>> {
    tonic_build::configure().compile_protos(&["../proto/xxx.proto"], &[".."])?;
    Ok(())
}

So how to specify them correctly?

Cargo’s documentation doesn’t seem to specify, but I imagine that it’s not working as you intend because the target in question is the host — the platform that the build script is being built for. You will have to enable features suitable for both cases, and use env("TARGET") to check what the main compilation target is.

I've checked the main compilation target is wasm32-unknown-unknown inside the build script, not the platform where the build script will run.

You will have to enable features suitable for both cases

Do you mean creating target-specific features for both targets? That seems not working.

[features]
target_not_wasm32 = []
target_wasm32 = []

[target.'cfg(not(target_arch = "wasm32"))'.features]
default = ["target_not_wasm32"]

[target.'cfg(target_arch = "wasm32")'.features]
default = ["target_wasm32"]

[target.'cfg(feature = "target_not_wasm32")'.build-dependencies]
tonic-build = "0.12"

[target.'cfg(feature = "target_wasm32")'.build-dependencies]
tonic-build = { version = "0.12", default-features = false, features = [
    "prost",
] }

No, I meant that your build-dependencies must include whatever dependencies, and features of those dependencies, are needed to be able to build in both cases, without attempting to make them conditional.

tonic-build is used to generate code for RPC protocols that will be compiled to the final target. But the default feature transport (which is needed in x86) of tonic-build will generate code that cannot compile in wasm32. That's why I need to turn off the default features of tonic-build in wasm32.

If so, then that is a flaw in the design of tonic-build. Features should be “additive” — enabling a feature should never make a library unable to be used in ways that would work with the feature disabled.

The only practical workaround I can offer is that you can make two packages — one dedicated to wasm32 and one not.

1 Like

I see. Thank you very much.