Skip to content

RFC: Allow packages to specify a set of supported targets - #3759

Closed
carloskiki wants to merge 65 commits into
rust-lang:mainfrom
carloskiki:master
Closed

carloskiki wants to merge 65 commits into
rust-lang:mainfrom
carloskiki:master

Conversation

@carloskiki

@carloskiki carloskiki commented Jan 8, 2025 •

Copy link
Copy Markdown

View all comments

Summary

The addition of supported-targets to Cargo.toml. This field is an array of target-triple/cfg specifications that restricts the set of targets which a package supports. Packages must meet the supported-targets of their dependencies, and they can only be built for targets that satisfy their supported-targets.

Rendered
FCP

Somtimes use "crate" instead of "cargo-target" for better readability

added section on handling cfgs

miscellaneous fixes

testing

fix dead links
fix links and typos

fix example

fix note

remove note

more fixes

fixes

minor fixes

Third draft

add note to cargo-target level

remove todo
- fix GH ui bug (indented codeblocks)
@Lokathor

Lokathor commented Jan 8, 2025

Copy link
Copy Markdown
Contributor

I think that there should be a little more explanation about how docs generation works with this. Specifically: Can I build docs for a target that's unsupported, such as if my host machine isn't supported, can i cargo doc to still just see the documentation?

@ehuss ehuss added the T-cargo Relevant to the Cargo team, which will review and decide on the RFC. label Jan 8, 2025
@opeik

opeik commented Jan 8, 2025 •

Copy link
Copy Markdown

This would be a godsend for crates that link against third party libraries, thus limiting supported targets.

@carloskiki

Copy link
Copy Markdown
Author

I think that there should be a little more explanation about how docs generation works with this. Specifically: Can I build docs for a target that's unsupported, such as if my host machine isn't supported, can i cargo doc to still just see the documentation?

Indeed, and this is especially important since docs.rs needs to be able to generate the docs for all crates. I added it here.

@ahicks92

This comment was marked as off-topic.

@Lokathor

Lokathor commented Jan 9, 2025

Copy link
Copy Markdown
Contributor

Crates assuming that they're running on one of several targets could even end up making unsafe code decisions based on that fact. Forcing the code to "just build anyway" would naturally lead to problems.

And crates can already force themselves to only build only on a specific target, this would not be a new ability, but instead it's only a way to better organize that information.

@workingjubilee

Copy link
Copy Markdown
Member

The author already mentions in the Prior art that the following Rust can be written:

#[cfg(target_arch = "lol"))]
compile_error!("experience bij)";

Please do not make comments on the RFC which do not engage with the RFC's content.

Comment thread text/3759-cargo-supported-targets.md Outdated
Comment thread text/3759-cargo-supported-targets.md Outdated
Comment thread text/3759-cargo-supported-targets.md Outdated
Comment thread text/3759-cargo-supported-targets.md Outdated

User experience is enhanced by raising an error that fails compilation when the supported targets
of a package are not satisfied by the selected target. A package's `supported-targets` must be a subset
of its dependencies' `supported-targets`, otherwise the build also fails.

@joshtriplett joshtriplett Jan 9, 2025 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems helpful, but at the same time, it may prove annoying to have to copy these across, if a dependency has a very specific list. And it may be non-trivial to enforce.

I think we should downgrade this to a lint, and say that it's best-effort, not mandatory.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also seems complicated by the fact that I might have a dependency that only supports (say) wasm, but I'm using it solely as a dev-dep (e.g., in tests). I don't think that case merits also setting supported targets on the containing package as a whole, since downstream consumers might not care about that limitation for running on tests.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's just a lint then unsafe coders can't depend on this, and they will still need to just use a compile_error! or something if they're really trying to avoid unsoundness.

@epage epage Jan 9, 2025 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is effectively saying that if you have a dependency that can't build on a target you claim to support, the build will fail and you should instead move it to a target.*.dependencies table.

imo that seems like something that should be a hard error to me.

I could see loosening the restriction on

When supported-targets is not specified, any target is accepted, so all dependencies must support all targets.

To me "we don't check", like package.rust-version, requiring supported-targets = ["cfg(true)"] to get the checking.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I totally agree with @epage here.

Using the same logic as package.rust-version is also something I have not thought of but is a great idea.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A problem I could see however is that if a package foo does not use supported-targets but one of its dependencies does, then when depending on foo errors of incompatible targets can be hard to solve since they come from transitive dependencies.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not quiet sure the problem. When building foo, you are building for a specific target and the error would be for that target. With package.rust-version, we check what all packages aren't compatible with the current toolchain and provide a single error message, see https://github.com/rust-lang/cargo/blob/9589831f61a8259919e64c6d68c1a36efc6efd20/src/cargo/ops/cargo_compile/mod.rs#L494-L543

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's just a lint then unsafe coders can't depend on this, and they will still need to just use a compile_error! or something if they're really trying to avoid unsoundness.

supported-targets would still be enforced (modulo some kind of force option); I'm talking about softening the enforcement that a crate's supported-targets is a subset of its dependencies.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI this has moved to a Future Possibility

Comment thread text/3759-cargo-supported-targets.md Outdated
@joshtriplett

Copy link
Copy Markdown
Member

This looks excellent!

@joshtriplett

Copy link
Copy Markdown
Member

Let's go ahead and start the process of asynchronously checking for consensus.

@rfcbot merge

@rfcbot

rfcbot commented Jan 9, 2025 •

Copy link
Copy Markdown

@joshtriplett has proposed to merge this. The next step is review by the rest of the tagged team members:

Concerns:

Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

See this document for info about what commands tagged team members can give me.

@rfcbot rfcbot added proposed-final-comment-period Currently awaiting signoff of all team members in order to enter the final comment period. disposition-merge This RFC is in PFCP or FCP with a disposition to merge it. labels Jan 9, 2025
@joshtriplett

Copy link
Copy Markdown
Member

@rfcbot concern should-crates-have-to-set-supported-targets-to-match-their-dependencies

Comment thread text/3759-cargo-supported-targets.md Outdated
Comment on lines +353 to +355
- `required-targets`. Pro: it matches with the naming of `required-features`. Con: `required-features` is a list of features
that must _all_ be enabled (conjunction), whereas `supported-targets` is a list of targets
where _any_ is allowed (disjunction).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me the important precedence is that the field means "skip if the qualification is not met" and for that reason I favor using this name.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apparently, this is different than required-features as this errors, rather than skips.

I raised this at https://github.com/rust-lang/rfcs/pull/3759/files#r1909208702

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also feel like using the word "support" carries a lot of unnecessary connotations that complicate the conversation. For example, with MSRV, the Cargo team has been leaning in the direction that "support" is an active process that gets tested. However, applying that here would lead to people over-constraining their targets.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The difference with this and required-features is that supported-targets is at the package level, not at the cargo-target level.

So if I run cargo build in a package with a binary foo which does not have its required-features met, then cargo can still possibly "do work" if there is another cargo-target which has its required-features met (for instance a library cannot have any required-features).

However if the supported-targets are not met for a package, then there is no chance of cargo doing compilation work for that package. That is why the packages are skipped when in a workspace, but an error is raised in a single package. This is just how if I ran cargo build --bin foo in the previous example, then cargo errors instead of skipping.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not have a preference for the name, I kept it as is to not confuse people who had read the Pre-RFC. I would not be against changing it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this being at the package or build-target level makes much of a difference. The RFC is starting at the package level and has build-target as a future possibility. In that case, we can treat this as the package is providing the default for all build-targets like package.edition

@epage epage Jan 28, 2025 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@epage

epage commented Jan 9, 2025

Copy link
Copy Markdown
Contributor

Comment thread text/3759-cargo-supported-targets.md Outdated
Comment thread text/3759-cargo-supported-targets.md Outdated
`supported-targets`, like any other dependency.


## Eliminating unused dependencies from `Cargo.lock`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should not have cargo vendor filtering use supported-targets but instead a new resolver.targets .cargo/config.toml field.

Most of the rest of the RFC works equally for application and library developers. This section is almost exclusively for application developers as they are the ones most likely to use cargo vendor. These vendored dependencies are meant for upstream pre-built binaries. They will be dealing with specific --target <platform>. Any downstream-built binaries that might be beyond this set will likely also exclude the vendored dependencies.

So if we provide a different mechanism for this feature focused on target tuples

  • Application developers are already coupled to target tuple specifics so this does not make their use of volatile target tuples any worse
  • By being able to use target tuples, this removes the largest piece of volatility / complication
  • Being further out of the way and in an already a volatile situation (target tuples) might mean its ok for any remaining volatility in the set relation logic?
  • However, Cargo.lock would become dependent on transient / environment configuration. We may want to record the targets used for resolving in Cargo.lock so they show up in any diffs
  • However, cargo publish would include a Cargo.lock that is not intended for all platforms and cargo install --locked may fail. Maybe cargo publish could resolve the published Cargo.lock for all platforms (unless --locked is specified for which it would error) and it would be ok?

So the question then is if this RFC is justifiable enough on its own without the expectation of this future possibility building on it. I think so because the workarounds for cargo check --workspace with platform-specific packages is quite annoying, it could be useful for documentation purposes, and the future possibility of the lints could help people better manage their dependencies.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the question then is if this RFC is justifiable enough on its own without the expectation of this future possibility building on it.

Tried to get input from WG-embedded but didn't get much of a response

#wg-embedded > Supported Targets RFC @ 💬

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, Cargo.lock would become dependent on transient / environment configuration.

a Cargo.lock that is not intended for all platforms

Please learn from the disaster that npm went through and do not repeat their mistake: npm/cli#4828

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It sounds like that was a default behavior while this is an opt-in buried in the config. We'd be particularly intending this for applications that only support specific platforms.

@taladar

taladar commented Feb 28, 2025

Copy link
Copy Markdown

I haven't seen it mentioned here yet in the discussion so I would just like to add that the information on supported targets might also be useful for tools checking for security issues to allow them to not mention issues in platform-specific dependencies only affecting targets not supported by the application (e.g. a lot of Linux only applications do not need to worry about Windows-specific security holes in indirect dependencies).

I would also suggest that epage brings up an important point when he mentions host and deployment targets. This should probably be split to avoid later painful changes for cross compilation, especially since that is becoming more common with WASM and embedded targets.

Comment on lines +14 to +24
# Summary

The addition of `supported-targets` to `Cargo.toml`. This field is a `cfg` string that restricts the
set of targets which a package supports. Packages can only be built for targets that satisfy their
`supported-targets`.

```toml
[package]
name = "hello_cargo"
supported-targets = 'cfg(any(target_os = "linux", target_os = "macos"))'
```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you update the summary to clarify this is for filtering dependencies during local development?

Maybe something like:

Suggested change
# Summary
The addition of `supported-targets` to `Cargo.toml`. This field is a `cfg` string that restricts the
set of targets which a package supports. Packages can only be built for targets that satisfy their
`supported-targets`.
```toml
[package]
name = "hello_cargo"
supported-targets = 'cfg(any(target_os = "linux", target_os = "macos"))'
```
# Summary
Workspace members will be able to specify their `supported-targets` in `Cargo.toml`, using `cfg` syntax, to avoid building those packages when using `--workspace`, much like `required-features` avoids building build-targets when the feature is not activated.
```toml
[package]
name = "hello_cargo"
supported-targets = 'cfg(any(target_os = "linux", target_os = "macos"))'
```
```console
$ cargo check --workspace --target x86_64-pc-windows-msvc
```

Comment on lines +71 to +82
Here, only targets with the `linux` OS or the `macos` OS, are allowed to build the package. User
experience is enhanced by raising an error that fails compilation when the supported targets of a
package are not satisfied by the selected target.

This feature should be used when a package clearly does not support all targets. For example:
`io-uring` requires `cfg(target_os = "linux")`, `gloo` requires `cfg(target_family = "wasm")`, and
`riscv` requires `cfg(any(target_arch = "riscv32", target_arch = "riscv64"))`.

This feature increases cargo's knowledge of a package. For example, when working in a workspace
where some packages are for a platform with `target_os = "none"`, and some others are tools that
require a desktop OS, using `supported-targets` makes `cargo <command>` ignore packages which have
`supported-targets` that are not satisfied by the selected target.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also comes across as affecting people depending on this package, including warning against over use.

@istankovic

Copy link
Copy Markdown

I would very much like to see this. :-)

What needs to be done to make it happen?

@epage

epage commented Dec 19, 2025

Copy link
Copy Markdown
Contributor

Depends on which part you are wanting to see. The cargo team discussed this RFC and had concerns about coupling all of these use cases together. I raised most of these as comments on the RFC.

The smaller, most likely route to move forward is cargo vendor filtering as talked about in #3759 (comment). If @carloskiki isn't interested in driving that conversation forward, then someone else will need to pick it up.

@istankovic

Copy link
Copy Markdown

Depends on which part you are wanting to see. The cargo team discussed this RFC and had concerns about coupling all of these use cases together.

Personally, I see build-target filtering as the most important one and the one that would increase quality-of-life considerably. Having to sprinkle a bunch of #[cfg] across one's code is something that becomes annoying very quickly.

Having errors on incorrect use is nice to have, but IMO not as important as build-target filtering.

@carloskiki

carloskiki commented Dec 22, 2025 •

Copy link
Copy Markdown
Author

I am sadly not able to push this RFC to completion currently, and this situation will remain at least for the next few months.

However, I would be happy to add someone else as collaborator on this RFC if there is interest.

@epage

epage commented Dec 26, 2025

Copy link
Copy Markdown
Contributor

Scope and approach are different enough, it might be worth starting from scratch with a new Pre-RFC and RFC.

@epage

epage commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

For anyone considering picking up "skip this package/crate if it doesn't match a target-tuple/cfg", rust-lang/cargo#17383 is an interesting request on the flip side (forced-target) where they want ... a tier 1 target? a std target? Would use do this with host-tuple, a --cfg, or something else? If host-tuple, how do we compose that with other conditionals? Speaking of, I guess you can't name a platform-tuple and use other conditionals?

@Sakib25800

Copy link
Copy Markdown
Member

@carloskiki would you be happy for me to pick this up and make revisions?

@carloskiki

Copy link
Copy Markdown
Author

Yes, I'd be very open to that. I don't know what the best course of action is here, but as @epage mentioned and since I don't have a lot of time to allocate to this, you may be better off writing a new RFC. You can of course reuse what's in here as much as you want!

@carloskiki

Copy link
Copy Markdown
Author

I will close this RFC in favour of #4013.

@carloskiki carloskiki closed this Oct 6, 2026
@rust-rfcbot rust-rfcbot removed proposed-final-comment-period Currently awaiting signoff of all team members in order to enter the final comment period. disposition-merge This RFC is in PFCP or FCP with a disposition to merge it. labels Oct 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

T-cargo Relevant to the Cargo team, which will review and decide on the RFC.

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.