-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
RFC: Allow packages to specify a set of supported targets #3759
base: master
Are you sure you want to change the base?
Conversation
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
fixes
- fix GH ui bug (indented codeblocks)
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 |
This would be a godsend for crates that link against third party libraries, thus limiting supported targets. |
Indeed, and this is especially important since docs.rs needs to be able to generate the docs for all crates. I added it here. |
This comment was marked as off-topic.
This comment was marked as off-topic.
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. |
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. |
|
||
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. |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
`[dev-dependencies]` are checked the using the same method as regular `[dependencies]`. That is, the package's | ||
`supported-targets` must be a subset of every `[dev-dependencies]`'s `supported-targets`. The rationale is | ||
that an example, test, or benchmark has access to the package's library and binaries, and so it must respect the | ||
`supported-targets` of the package. |
There was a problem hiding this comment.
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 should be a requirement. It's sometimes reasonable for tests to only run on some targets.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But we'll try to build the dev-dependency on an unsupported target, independent of what cfg
is on the test, which will fail. The dev-dependency should be moved to a target.*.dev-dependencies
table, bypassing this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The dev-dependency should be moved to a
target.*.dev-dependencies
table, bypassing this.
The RFC does not do a good job of "teaching" how to use this feature (Could be added to guide-level explanation), but this is what I have in mind.
This looks excellent! |
Let's go ahead and start the process of asynchronously checking for consensus. @rfcbot merge |
Team member @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 concern should-crates-have-to-set-supported-targets-to-match-their-dependencies |
- `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). |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
@rfcbot concern field-name See https://github.com/rust-lang/rfcs/pull/3759/files#r1909195446 |
- Make this process part of the resolver. | ||
- Show which targets are supported on `docs.rs`. | ||
- Have search filters on `crates.io` for crates with support for specific targets. | ||
- Also add this field at the cargo-target level. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fact that the alternatives call this out I feel like this needs to be under its own heading with a bit more explanation behind it
### Allowing only target triples | ||
|
||
This is an even stricter version of the above. Being even simpler to implement, this alternative | ||
may not be expressive enough for the common use case. Packages rarely support specific target triples, | ||
rather they support/require specific target attributes. What would likely happen is that packages | ||
would copy and paste the target triple list matching their requirements from somewhere or someone else. | ||
Every time a new target with the same attribute is added, the whole ecosystem would have to be updated. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should call out the reason why it was originally proposed
- Easier, more exact relations logic
- Easier for the resolver to leverage this information
I think the chances that this whitelist is far too restrictive is incredibly high. I've experienced a bunch of cases where the author of a crate says "I only test for x86 and ARM so these are the only officially supported targets" when the crate works perfectly fine on many other architectures (the code doesn't use anything architecture specific, the author just doesn't care about setting up CI for e.g. PowerPC). I would want to see some fallback mechanism that the author of a crate can specify such that in the example x86 and ARM can be the "officially" supported targets but other targets can still build just fine, but possibly emit a warning that they are not officially supported by the author. Alternatively the documentation should strongly suggest not using the Update: I just noticed another example of this. I'm the author of a hotkey listening crate. It supports specific operating systems. However, there's a dummy implementation for all other targets. It compiles, but no hotkeys are ever triggered. Here it would also be great to advertise in the Cargo.toml that Windows, Linux and co. are the main supported targets, but that it's perfectly fine (with possibly a warning to the user) to just use the crate across all targets. |
Co-authored-by: Josh Triplett <[email protected]>
Co-authored-by: Josh Triplett <[email protected]>
Co-authored-by: Josh Triplett <[email protected]>
This comment was marked as duplicate.
This comment was marked as duplicate.
Co-authored-by: Ed Page <[email protected]>
`[dependencies]`. If the crate itself has no `supported-targets` specified, | ||
then all dependencies must support all targets. | ||
|
||
If a dependency does not respect this requirement (if it is not compatible), an error is raised and the build fails. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As per some non-threaded comments on this PR by @CryZe and @ahicks92: this feature has the risk that package authors will list a too narrow set of supported-targets
. They can already do this with a conditional compile_error!
, but I am particularly concerned that they might do so on the optimistic principle “filling in all of the metadata is good, right?”, whereas if the manifest field did not exist, they wouldn’t have thought to write a compile_error!
.
I think that, in order to reduce the risk of gratuitous breakage that requires users of a not-eagerly-maintained package to fork/vendor it or find an alternative, this should be advisory for dependents: it does not force a build to fail unconditionally, but causes a lint that might error by default but can be opted out of in some way (perhaps as a field in the [dependencies]
table).
(By “not eagerly maintained”, I mean: the code is generally good quality, but it takes weeks/months to get a PR in upstream, or for a release to happen after the PR. I think that it is an important virtue of Rust that you can usually successfully use such packages, rather than various kinds of churn making it hard.)
In order to support the “it’s UB to run this code on (not) this target” use case, there can be a way to require it to be a hard error (or at least, not bypassable by dependents, only by the build command configuration). But that should be opt-in, so that the feature can also be used for the softer use case of offering machine-readable requirements documentation and avoiding messes of “item/symbol not found” error messages.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the "it's UB to run this code on (not) this target" use cases, the existing tools of conditional compile_error!(...)
/ const { assert!(...); }
seems better than overloading the supported-targets
field. Putting each assumption right next to the unsafe
code that relies on it means:
- It's easier to audit the code because it's more localized -- even if the safety comment on a block justifies something by reference to Cargo.toml, I as reviewer have to check that.
- It's harder to forget about reviewing/updating the code when changing the required-targets definition. You could put a comment in the relevant part of the manifest, but that's further removed from the relevant code so it's easier for the comment to go out of sync.
- If I depend on a library that has (in my view) an overly restrictive
supported-targets
, I can try to work around this by patching it locally. Editing the manifest is easy, bypasses any "enforcement" by Cargo, and makes it easy to miss that someunsafe
code in the guts of the library actually relies on it for soundness. Having to dive into the source code and remove static assertions next tounsafe
blocks is higher friction, which is good when soundness hinges on it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One of unresolved questions is
- Some crates will inevitably have target requirements that are too strict, how
do we make users bypass the error (probably with some--ignore-**
flag)? Do we want to allow this?
The approach taken with package.rust-version
is the --ignore-rust-version
flag. We have approved but not implemented turning the hard error into a deny-by-default lint.
The problem with either situation is that one of the intended use cases is for this to trim down Cargo.lock
/ vendor/
. If its advisory only, then we can't do that anymore.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the opt-out is encoded in Cargo.toml, then Cargo can see that when generating the lockfile, right? So CLI flags do make it impossible to trim the lockfile, but explicit override (similar to how default / non-default features work in principle) seems doable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cargo resolves Cargo.lock
assuming all features of workspace members may be activated. It only trims features from transitive dependencies where there is no way to activate them through the command-line.
An --ignore-supported-targets
flag is a transient state and the lockfile generally would need to take into account all transient states in its creation so it doesn't change based on how Cargo commands invoke it. The only thing it could trim are transitive dependencies through target.*.dependencies
tables or artifact dependencies with a target
In the past, I have toyed with the idea that the lockfile could remember some types of resolution inputs to re-apply them in the future. This is a very dodgy area that would need a lot of detail to figure out and is questionable whether it would ever get approved. This is the type of thing that could slow down or derail the RFC and would ideally be split out into a future possibility to make this RFC go more smoothly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It sounds like in theory we could provide a non-transient force/override option in the manifest, which could then disable trimming the dependencies. But 👍 for not blocking on that in any case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I share the concern that people might write target requirements that are too strict, or that they might write target requirements that were correct at the time but things have changed and the crate hasn't been updated. I want to suggest that:
- When directly building a package (i.e. not as a dependency), attempting to build for a target that it declares it doesn't support should trigger a deny-by-default lint.
- When a package is being built as a dependency, attempting to build for a target that it declares it doesn't support should trigger an allow-by-default lint.
This is analogous to honoring Cargo.lock
for the package being directly built but not for its dependencies. If, hypothetically speaking, the io_uring
API becomes available on FreeBSD at some time in the future, but the maintainer of some io_uring
interface package neglects to add FreeBSD to the list of supported targets for that package, binary crates that use that package can still be built for FreeBSD despite the exclusion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- I think we need to keep in mind that the framing of this RFC can be improved which affects the conversation, e.g. RFC: Allow packages to specify a set of supported targets #3759 (comment)
- We need to make sure we are clear in communicating how this should be used, see RFC: Allow packages to specify a set of supported targets #3759 (comment)
That said, there are likely still times to override. I think we're being a bit limited in exploring our options
The discussed CLI override
- Affect the entire dependency tree
- Prevents
Cargo.lock
trimming - Every dependent must do it
Lint overrides
- See CLI
A single manifest override (bespoke version of lint override)
- See CLI
Switching to mutable metadata, see #3759 (comment)
- Whole new process that would need to be designed and explored
Other options
- Patching (existing)
- Requires copying the entire repo somewhere (maybe
cargo override
can help?) - Every dependent must do it
- Requires copying the entire repo somewhere (maybe
- Unidiff patch (proposed)
- More limited in what needs to be in your repo
- Has some design questions that need working out
- Every dependent must do it
- Manifest override on specific dependencies
- Every dependent must do it
- Some crates will inevitably have target requirements that are too strict, how | ||
do we make users bypass the error (probably with some `--ignore-**` flag)? Do we want to allow this? | ||
- Should we solve for this during dependency version resolution? (the current rationale is that we do not want | ||
targets to affect package version resolution). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As posted at #3759 (comment)
one of the intended use cases is for this to trim down
Cargo.lock
/vendor/
. If its advisory only, then we can't do that anymore.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@workingjubilee at #3759 (comment)
Maybe if we adopt this it should include a way to describe whether the use of the crate on an unsupported target is one of
actively dangerous (implementations depend on target-specific details that must be ported)
probably bad? but not automatically unsound (implementation depends on target-specific details that work if another target is similar enough)
maybe it works, maybe it doesn't? glwt (the common "I've only tested it on..." situation)
(moved here to move this off the main thread so the discussion can be followed)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at the Motivation section (and from my understanding of the problem), this is meant to help with
cargo check --workspace
when some packages aren't supported- Smaller
Cargo.lock
/vendor/
In those situations, the main reason for a package to limit the targets is
- a workspace member can't build on all targets
- An application will only ever be built for specific targets and they want dependencies stripped that aren't for that target
- A library is platform-specific (e.g.
windows-sys
) and they want to allow themselves to be stripped for the above.
imo this shouldn't be about "I only tested on this platform". I'm not even sure if we should get nuanced about the other two cases. I also don't think distinguishing these cases is worth the data format and end-user complexity.
I do think we should be clear in communicating abut this how this is intended to be used to reduce problems with it. For example, the name alone invites a lot of this kind of thinking which I noted at #3759 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps it should be clearer that it's allowed-targets
, i.e. that all others are implicitly banned.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe required-targets
makes it a bit more clear?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a more obtuse option that might make desired usage clearer would be to have known-broken-targets
and require specifying where it doesn't work, instead of where it works.
the same representation, and they are then compared. This process is done internally, and does not | ||
affect the `Cargo.toml` file. | ||
|
||
### Flattening `not`, `any`, and `all` in `cfg` specifications |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this section just describe conversion to disjunctive normal form? The array of strings is the top-level logical OR, and each entry is the AND of (possibly negated) atoms. If this correct, it would be helpful to make this explicit because it saves anyone who has encountered DNF before some reverse-engineering. This also makes it easier to see that this conversion can cause exponential blowup in the worst case (not a fatal problem, since dependency resolution is also NP-hard, but good to keep in mind).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have no clue what that is, I just decided on a representation that "felt right" (I have very little academic knowledge on SAT solving). I used this representation because I thought that no-one would ever have crazy nested cfg
specifications. I'll read up on it and link it there.
fix:whitespaces
Co-authored-by: Ed Page <[email protected]>
@workingjubilee I feel the need to push back on you (I believe it was you but GH won't let me see this?...) dismissing my previous comment as off topic. I am aware that you can technically do this today. I have now read the RFC in detail. The ability to do it today if you really want is not by itself a justification for encouraging doing so. Many targets are supersets of previous targets. I do not want crates.io to slowly build up this cruft. You can model this new metadata as effectively a gradual deletion of the package, and if you do so it's concerning. This kind of thing cascades to all downstream packages, without a good mechanism for direct control, and as far as I can tell introduces the first "blessed" mechanism into the language which in effect requires maintainers to remain around. Add this, encourage people to use it, decide that such things are good code, and the ecosystem is one popular package away from Rust not being able to easily get new targets anymore. Looking at the output of
Obviously the correct thing in such a case is to use cfg predicates to account for the entire groups..but will everyone do that in practice? I doubt it. What about Nintendo Switch? Who's going to even be able to test that one given that you need an SDK from Nintendo? There's targets like that in here where the original authors of packages literally cannot get access but their code might very well have been fine. That said this is way too noisy and you're the mod and I've made my viewpoint clear, so I'm unsubscribing for now. But I ask that if you still think I'm off topic, please give more of an explanation why this isn't a legitimate, important concern. I personally consider most of the rest of the RFC to have low relevance until this question is answered, and am quite surprised that it wasn't answered before posting it. I may check back in later once this has had a chance to settle, but the chances of me properly keeping up at this point are very low so it doesn't seem worth me trying to do so now given that the nature of this concern boils down to a yes-or-no question more than a long drawn-out discussion. |
|
This field consists of an array of strings, where each string is an explicit target-triple or a `cfg` specification | ||
(as for the `[target.'cfg(**)']` table). The supported `cfg` syntax is the same as the one for | ||
[platform-specific dependencies](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#platform-specific-dependencies) | ||
(i.e., `cfg(test)`, `cfg(debug_assertions)`, and `cfg(proc_macro)` are not supported). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How does this interact with crate features and optional dependencies? In some cases, these impose additional platform requirements, e.g., because the alloc::sync
types don't exist on platforms without atomics. How could this be modeled, if at all? Platform-specific dependencies aren't allowed to mention cfg(feature = "...")
, but that would be required to express e.g., "if the std
feature is enabled, I require cfg(target_has_atomic="ptr")
".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds like a good addition to future work, at a minimum: expressing requirements that vary by feature. There are a few possible designs I could imagine for that.
## Eliminating unused dependencies from `Cargo.lock` | ||
|
||
A package's dependencies may themselves have `[target.'cfg(..)'.dependencies]` tables, which may never be used because of the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As this affects dependency resolution, we'll also need to discuss the relevant changes to the Index.
For the existing schema, see https://doc.rust-lang.org/cargo/reference/registry-index.html#json-schema
## Misc | ||
|
||
- Have `cargo add` check the `supported-targets` before adding a dependency. | ||
- Make this process part of the resolver. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does this mean? If its affecting Cargo.lock
, then its affecting the resolver.
@rfcbot concern should-this-be-in-manifest-or-updatable-metadata We might want to consider the possibility of using the proposed mechanism for updatable crate metadata. That would allow updating this list without uploading a new version of the crate. On the other hand, that would be less convenient and less self-contained. |
If that metadata is update-able, what happens when some popular crate's maintainer suddenly decides to go rogue and they replace the set of supported targets with |
There are several comments here that suggest it might be a problem if a crate sets this metadata and someone wants to run the crate on an unsupported target. I think it's worth having some clear documentation about recommended usage of this mechanism. This should not, in general, be used for "I haven't tested this on other targets and I don't know if it works". This should be used for "I have good reason to believe it doesn't work as expected". |
"What happens if a crate maintainer goes rogue" is not a question in any way specific to this mechanism. A crate maintainer could also replace the entire code of a crate with a compilation error, or worse. |
except that currently they can't -- they can upload a new rogue version, but they can't do anything to existing versions except yank them (which afaik doesn't break users who have it already in their lockfile). update-able metadata allows them to break existing versions -- though if that metadata was also stored in the lockfile and wasn't updated unless running |
@programmerjake I would expect it to be tied to |
document how the feature should not eagerly be used. Co-authored-by: Josh Triplett <[email protected]>
I'm putting this as a top-level comment because there are some discussion threads above that might be talking about it but I'm not sure and I don't want to derail them if they aren't. As a crate author one of the most important reasons why I want this feature is because it might enable pruning of my crate's transitive dependencies. Concrete example: I'm working on a crate that is inherently Linux-specific (it provides an interface to a Linux-specific kernel API). This crate uses So, because of that experience, I really want At the same time, I also think it's very important for I bring these two things up at the same time because I see potential for a conflict between them. Cargo should prune the dependency tree early -- but it needs to do the pruning in a way that honors any override that is happening, and I'm not sure exactly what that turns out looking like. |
If a specific package is specified using `--package`, or if `cargo` is invoked on a single package, | ||
then an error is raised. | ||
|
||
## Eliminating unused dependencies from `Cargo.lock` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be moved to a future possibility to better focus this RFC?
Summary
The addition of
supported-targets
toCargo.toml
. This field is an array oftarget-triple
/cfg
specifications that restricts the set of targets which a package supports. Packages must meet thesupported-targets
of their dependencies, and they can only be built for targets that satisfy theirsupported-targets
.Rendered