Open luser opened 6 years ago
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
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.
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.
cc @Eh2406, we were just talking about this!
We talked a bit in person about this and envisioned something like:
[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)--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!
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?
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.
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
.
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.
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.
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",
]
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 dependencybin.required-features
which means "if these features aren't active, skip this bin".cfg
in this initial example
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)cfg
in package.required-targets
and in a target dependencyPlease include some escape hatch that lets you ignore a requirement in a crate you depend on if it's incorrectly too strict.
I expect people will get this wrong with the design suggested above which uses a full target triple by failing to enumerate every possible triple it works on. Something like an option to exclude all windows targets without then enumerating all unixy targets would encourage people to restrict correctly/allow for future new target triples to work.
Something like an option to exclude all windows targets without then enumerating all unixy targets would encourage people to restrict correctly/allow for future new target triples to work.
I think the exclude-targets
option may well be best. Currently there are two scenarios for myself where I might want this:
Perhaps it would be wise to allow wild-carding of parts of a triple like *-apple-darwin
, aarch64-*
?
btw there is #9208 for doing this on the build-target / crate level
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.
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.
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?
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 https://github.com/rust-lang/cargo/issues/6179#issuecomment-1736090525
In just having the field,
package.required-targets
is a list of target tuples
--workspace
would skip those targets on an unsupported platform
--package
and implicitly selected packages, should it do so as well?target.<cfg>
tables
cfg
to see if one matchesdeny
)
target.<cfg>.dependencies
, also check that the intersection of your and the dependencies targets can match the cfg
target
field against the dependencyRisks:
In using the field during resolution
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
Risks:
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.
Spun off from the specific proposal in https://github.com/rust-lang/cargo/issues/4544#issuecomment-357371733 "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
12260 for specifying build target configuration per platform
9208 for specifying supported platform targets for build targets