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

Allow specifying a set of supported target platforms in Cargo.toml #6179

Open
Tracked by #41
luser opened this issue Oct 16, 2018 · 18 comments
Open
Tracked by #41

Allow specifying a set of supported target platforms in Cargo.toml #6179

luser opened this issue Oct 16, 2018 · 18 comments
Labels
A-cargo-targets Area: selection and definition of targets (lib, bins, examples, tests, benches) A-lockfile Area: Cargo.lock issues A-manifest Area: Cargo.toml issues A-workspaces Area: workspaces C-feature-request Category: proposal for a feature. Before PR, ping rust-lang/cargo if this is not `Feature accepted` Command-vendor S-needs-rfc Status: Needs an RFC to make progress.

Comments

@luser
Copy link
Contributor

luser commented Oct 16, 2018

Spun off from the specific proposal in #4544 (comment)
"A random solution which may help solve this though is to perhaps list the valid targets for a project in a workspace root Cargo.toml. That way Cargo could be smarter and just vendor dependencies for those targets (and alter resolution so it won't include winapi in the lock file)"

This would help projects like Firefox and Fuchsia that vendor their dependencies by allowing them to avoid vendoring crates that are only necessary for platforms that the project does not support (see also #7058).

cc @cramertj

See also

@alexcrichton
Copy link
Member

This seems plausible to me! Cargo has to execute rustc to learn about cfg information for targets, so that may be one roadblock to getting this working but otherwise I think it in theory shouldn't be too too hard to plumb through what we've got today

@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 Oct 17, 2018
@cramertj
Copy link
Member

Similarly, it seems like you could also plumb through the set of features with which each library will be built, so that there's no need to pull in optional dependencies.

@luser
Copy link
Contributor Author

luser commented Oct 17, 2018

I poked around that a bit and that already seems to work. If you have a dependency on crate A and A has an optional dependency on B, you won't wind up with B in your Cargo.lock unless you enable that feature.

@alexcrichton
Copy link
Member

cc @Eh2406, we were just talking about this!

We talked a bit in person about this and envisioned something like:

  • Each workspace has a default set of targets and a default set of features used to generate a lock file. These both default to "everything"
  • You can configure a [workspace] to either change the default set of features or the default set of targets. This affects lock file resolution. It also would be documented with lots of warnings about the effects of doing this (like thrashing lock files on builds)
  • Finally, --minimal-cargo-lock would be a CLI flag to say "ignore configuration, do the minimal thing"

We've already basically got the support for all of this, it'd just need some wiring up and stabilization!

@mankinskin
Copy link

mankinskin commented Aug 24, 2020

I had another use-case for this #8645

Problem:
It is difficult to recognize what targets a crate is compatible with. With WASM coming about, it has become more important to know if a crate is WASM-compatible or not, i.e. builds and runs on a wasm32 architecture. One has to try building the crate for the target manually, and if there are issues one needs to find the dependency which may be causing incompatibility by recursing down the dependency tree, following the compiler errors.

Solution:

[build]
targets = [
    "wasm32-unknown-unknown",
    "wasm32-wasi",
    "x86_64-unknown-linux-gnu",
    "i586-pc-windows-msvc",
]
  • Allow crate authors to define compatible targets in the crate configuration
  • check those targets when publishing the crate
  • let cargo make a suggestion to add a target to the list, after target has been checked successfully
  • check the compatible targets of dependencies and point out compatibility conflicts

This would make the compatibility visible in the crate, and make it easier to find compatibility issues.
Another idea is to show the compatible targets in the documentation on docs.rs, to make it even easier to see what targets a crate can be run on.

@alexcrichton I don't understand why this should be bound to workspaces though? Wouldn't this make sense for any crate?

@mankinskin
Copy link

Another idea is to declare something like non-targets to explicitly exclude targets from compatibility for a crate. This could for example be useful when you never intend a crate to target something special like Wasm.

@kvark
Copy link

kvark commented Aug 19, 2021

This would help a problem we have in Firefox, where some of the dependencies may have WASM-specific dependencies (https://github.com/grovesNL/glow), which are dragged into the 3rd party sources by cargo vendor.

@flukejones
Copy link

I've just recently hit on a circumstance where this functionality would be very useful: preventing cargo (and vendoring by extension) from pulling in crates that will never be built on the intended target.

Or at least that would be my hope.

An example is that I build and maintain a particular project, and this project has many dependencies. Various of these dependencies have winapi as a dependency themselves. This in itself is not an issue really, as the winapi crate is behind a target.cfg flag, so it never gets built on Linux or Macos.

However! winapi and its own chain of dependencies pulls in close to 350MB of stuff for Windows. Stuff that will never ever be built (on my target). The side effect of this is that when I do vendoring and compress the artifacts, the result with this is a 17MB archive - if I remove the windows crates, it's 3.5MB. It has an impact all the way down the distribution chain where a Linux distro might be using vendoring, and now has to account for 13.5MB of wasted space.

My hope for this issue is that by specifying a a target that the crate is for it would prevent the above scenario by never resolving the windows target. With a default of no target specified defaulting back to current behaviour.

@weihanglo weihanglo added the S-needs-design Status: Needs someone to work further on the design for the feature or fix. NOT YET accepted. label Jun 13, 2023
@weihanglo weihanglo changed the title Allow specifying a set of supported targets in Cargo.toml Allow specifying a set of supported target platforms in Cargo.toml Jun 13, 2023
@weihanglo weihanglo added the E-hard Experience: Hard label Jun 13, 2023
@scottlamb
Copy link

Just came here from #5220, which was closed in favor of this issue.

Do the supported targets need to be workspace-wide (as suggested by the initial comment here), or could they apply crate-by-crate? Currently e.g. https://github.com/sportsball-ai/av-rs has one workspace with some crates that are portable, some that are macOS-only, and some that are Linux-only. I was following #5220 because I was hoping to be able to just have cargo build do the right thing on the workspace. That seems possible via #6179 if the intended state is you can set supported targets for each crate, but not if you can only do it at the workspace level.

@epage
Copy link
Contributor

epage commented Sep 26, 2023

My expectation is we'd have something like

[package]
name = "cargo-credential-macos-keychain"
# ...
required-targets = [
  "aarch64-apple-darwin",
  "aarch64-apple-ios",
  "aarch64-apple-ios-sim",
  "x86_64-apple-darwin",
  "x86_64-apple-ios",
]
  • Ideally we put this in the Index Summary and you can't depend on a package with required-targets unless your required-targets is the same or a superset or you use it in a target-specific dependency
  • I chose "required" in the name to be similar to bin.required-features which means "if these features aren't active, skip this bin".
  • I left off cfg in this initial example
    • I suspect there are corner cases that could lead to Cargo.lock being modified just by building on another system (newer rustc with a new target and a dependency already supports that target with a conditional dependency)
    • I suspect this gets even more complicated if we try to find the intersection between cfg in package.required-targets and in a target dependency
  • We'd need to figure out what validation can or should be done on the target list (maybe just a lint?)
  • I question whether workspace inheritance would be useful but then it might just be good to do just for consistency

@epage epage removed the S-needs-design Status: Needs someone to work further on the design for the feature or fix. NOT YET accepted. label Oct 19, 2023
@epage
Copy link
Contributor

epage commented Oct 19, 2023

btw there is #9208 for doing this on the build-target / crate level

@stormshield-guillaumed
Copy link
Contributor

We open sourced a tool that allows you to specify the supported targets of a crate in the Cargo.toml named cargo-ft. Unfortunately, it doesn't solve the Cargo.lock problem which is probably only reasonably doable in cargo directly. Nevertheless, it simplifies building, checking and testing your code when your workspace consist of multiple binary crates with various target platform support. Hope it can help at least a few other people than us.

@hishamhm
Copy link

hishamhm commented Mar 6, 2024

Perhaps it would be wise to allow wild-carding of parts of a triple like -apple-darwin, aarch64-?

Ergonomically specifying that a crate is Wasm-incompatible would require both this and exclude-targets, to allow for something like exclude-targets = [ "wasm32-*" ], as positive lists would be very hard to maintain (and often end up incorrect).

That feature would be most welcome since Wasm-incompatible crates often build but fail at runtime in ways that aren't obviously a platform incompatibility — in the case of typetag, for example, one has to dig down the errors they get in the runtime logs until they find discussions that ultimately mention that the crate doesn't actually work on Wasm.

scottlamb added a commit to sportsball-ai/av-rs that referenced this issue Apr 16, 2024
I'm looking forward to <rust-lang/cargo#6179>;
making an entire crate empty or not based on platform is an awkward
workaround.
Xaeroxe pushed a commit to sportsball-ai/av-rs that referenced this issue Apr 16, 2024
* test and fix logging callback

* `cstr` import

* test `xcoder-*-sys` crates on CI

* satisfy clippy

* gate xcoder tests behind target_os linux

I'm looking forward to <rust-lang/cargo#6179>;
making an entire crate empty or not based on platform is an awkward
workaround.
@epage epage added the A-lockfile Area: Cargo.lock issues label Jun 12, 2024
@decryphe
Copy link

decryphe commented Nov 1, 2024

As this is an issue I regularly run into while maintaining a Linux-only application built for a specific embedded device, and vendoring its dependencies - what's the current state of this issue?

I've recently started contributing to clippy, and would be willing to contribute on this issue as well. Would someone in the cargo team be interested in being a little bit of a mentor, so I can move this issue forward?

@epage
Copy link
Contributor

epage commented Nov 1, 2024

The next step for this is likely be shopping around a Pre-RFC for getting some in-the-small feedback before posting an RFC.

While I know a lot of people are interested in this for Cargo.lock and vendoring, I would actually recommend that be split that out into a future possibility / second phase as that adds a lot of its own design and implementation complexity that being able to focus on a smaller set of questions will make the process go a lot more smoothly and get people both phases of this work faster than doing it all at once.

Some considerations that build off of my previous comment at #6179 (comment)

In just having the field,

  • package.required-targets is a list of target tuples
    • Challenge: what about custom targets?
    • Validate the target tuples are supported?
      • Challenge: this would be rustc version dependent. Maybe if this just starts off as a warning?
  • --workspace would skip those targets on an unsupported platform
    • for --package and implicitly selected packages, should it do so as well?
  • Lint for unused target.<cfg> tables
    • Implementation: would require calling into rustc for each required target and evaluating the cfg to see if one matches
  • Lint for compatible dependencies (default: deny)
    • If this should cause backtracking in the resolver, then this needs to be taken into account during dependency resolution and needs to be in the Index. Otherwise this can be done later.
      • Personally, I would lean towards doing it later. If someone makes a breaking change by removing a target then that should be reported, rather than implicitly worked around by picking an older version (I feel similar about removing of features)
    • If its a general dependency, the dependency has to be a superset of your own targets
    • If its a target.<cfg>.dependencies, also check that the intersection of your and the dependencies targets can match the cfg
    • Exception: if a dependency specification has a target field for which we'd need to instead check the target field against the dependency

Risks:

  • Performance: this is a lot of extra calls to rustc. Hopefully these are all compatible with our rustc cache so they won't make things too bad

In using the field during resolution

  • We'd need to track what package.required-targets we used to reach each dependency, unifying the targets as we reach a dependency from different workspace members, and re-evaluate the dependency tree of that dependency, if needed
    • Exception: if dependency specification has a target field, then we instead use that

Risks:

  • Again, performance
  • Unsure how practical this is to support in the resolver now or in the PubGrub resolver that is being worked on.

@flukejones
Copy link

For anyone coming to this issue who needs an immediate interim solution, use https://github.com/coreos/cargo-vendor-filterer, for example cargo vendor-filterer --all-features --platform x86_64-unknown-linux-gnu vendor

This dramatically reduces vendoring size, which is pretty much critical for Linux distro packaging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-cargo-targets Area: selection and definition of targets (lib, bins, examples, tests, benches) A-lockfile Area: Cargo.lock issues A-manifest Area: Cargo.toml issues A-workspaces Area: workspaces C-feature-request Category: proposal for a feature. Before PR, ping rust-lang/cargo if this is not `Feature accepted` Command-vendor S-needs-rfc Status: Needs an RFC to make progress.
Projects
None yet
Development

No branches or pull requests