Open withoutboats opened 7 years ago
Maybe it's useful to look at how this problem is approached in Haskell. Here are some relevant slides: https://wiki.haskell.org/wikiupload/b/b4/HIW2011-Talk-Loeh.pdf
Here is an example of a subtle issue that occurs with private dependencies:
Btw, I found it through this post: http://harry.garrood.me/blog/purescript-why-bower/
Would Rust2018 be a good opportunity to make the braking changes to Cargo.toml
?
Maybe. Though such changes should be designed and proposed soon, have an easy migration path, and preferably only affect a minority of existing crates.
Thought I just had related to ecosystems like futures
that provide a "core" stable crate along with less stable utilities re-exported from a "facade": items from a public dependency re-exported through a private dependency should be treated as public. (This is likely how the implementation would behave anyway, but having a testcase for this would be nice). Basically how I see using a tightly coupled ecosystem like that work is that you would declare both the "facade" crate and "core" crate as dependencies, but only the "core" crate as public:
[dependencies]
futures = { version = "10.17", public = false }
futures-core = { version = "1.2", public = true }
But then, in code you would never import items from the "core" crate, instead you would simply have public APIs that return types which have been re-exported through the "facade" from the "core" crate and rely on the compiler to warn you if you accidentally use something that didn't originate in the "core" crate.
I don't quite understand something about your example. Can you elaborate on what the Toml
and the code in the futures
crate look like?
@Eh2406 the setup's a little annoying to just explain, so here's a full compiling set of example crates: https://github.com/Nemo157/rust-44663-facade-example
In this example futures-core
exports a single trait Future
, futures
re-exports this trait from futures-core
along with a "utility" Foo
.
Now mylib
wants to use futures
, including returning some Future
s from its public API. But futures
itself intends to have breaking changes to update utilities, users that care about interoperability should only use types from futures-core
in their public APIs. Even as new major versions of futures
are released they will all link against the same version of futures-core
so the underlying traits will be interoperable.
So, to have the compiler enforce this restriction the developers of mylib
want to use the public/private dependencies feature, they have both futures
and futures-core
as dependency but only futures-core
marked as public. But for ergonomics it's nicer to just use the re-exports directly from futures
, instead of having to remember which parts of the API need to be imported from futures
and which from futures-core
.
I'd like to work on this.
Thanks for offering to work on this! @alexcrichton, do you have any mentoring advice?
I can at any time get a branch ready for the resolver part of cargo, it will be good enough to start experimentation, although not good enough to be ready to stabilize.
Sure! @Aaron1011 so this is split roughly into two features, one being rustc knowing what crates are in the "public interface" and a second being the support in Cargo's resolver to make various decisions differently. Are you interested in one of those in particular?
@alexcrichton: I've started working on the rustc part in a branch: https://github.com/Aaron1011/rust/commits/feature/pub-priv-dep, and I plan to submit a (WIP) PR soon. I might also be interested in working on the cargo part as well.
@Aaron1011 please cc me when you make that PR. I know nothing about the internals of Rust, so will be of no help, but I do want to follow the discussion.
I will redouble my efforts to get the Cargo's resolver part mergeable. I have been enjoying ( and hating ) it because it is the hardest algorithmic problem I have ever worked on. I would be happy for some help, perhaps a new perspective will get me un-stuck.
@Aaron1011 ok and it seems like you're off to a great start! I'd be up for reviewing that PR, and if you've got any questions along the way just let me know
There was another usecase for this mentioned on i.rl.o, if cargo doc
had a form of "local development" mode to build the documentation you care about when working on a crate, this would allow that mode to know exactly which dependencies it needs to produce the documentation for (all direct dependencies + their public dependencies).
Similarly, if you're self-hosting documentation for a crate somewhere you may want to be able to generate a documentation bundle including the crate and all its public dependencies so that it is fully self-contained.
The current command line syntax for passing private and public extern crates to rustc
is
--extern-private name=PATH
--extern name=PATH
(this differs from what was written in the RFC).
I think the syntax would benefit from being slightly more general
--extern:modifier name=PATH
with private and public extern crates being written like this
--extern:priv name=PATH
--extern:pub name=PATH
--extern name=PATH // OK, `pub` is the default
(We may also want other modifiers, or multiple modifiers (--extern:m1:m2
) in the future.)
@petrochenkov Do you want me to modify my PR to use that syntax instead?
@Aaron1011 A separate PR would probably be better, this is a novel syntax in general, it may require an FCP etc.
The Cargo frontend of the implementation has been merged
Things still left to do:
cargo public
(picking the minimal versions from Cargo.toml)The discussion of the first point is continuing at https://github.com/rust-lang/cargo/issues/6129#issuecomment-464845052
minimal versions is being tracked at https://github.com/rust-lang/cargo/issues/5657. It is implemented, but is not wide enough used to be stabilized as a cli flag. I doubt we can add it to cargo publish, without a magere rethink.
This is now available on the latest nightly (2019-05-07) if anyone wants to experiment with it (docs). Just add cargo-features = ["public-dependency"]
to the top of Cargo.toml
of your project to get things started. You can then look at the warnings produced by rustc to understand which dependencies are exposed in your public API.
I like this feature! The produced warning messages were very clear. In 1 out of 5 crates trialed, I decided based on the results to make 2 dependencies private that were needlessly public. This makes me think there is value and wonder if there is an opportunity to stabilize just the information collection part of this sooner (public dependency attribute, rustc warnings, uploads to the crates.io index) and the dependency resolution changes (warnings or any resolution errors) later? In particular, wouldn't that allow progress on information collection and utility without serializing on rust-lang/cargo#5657? Or perhaps the tracking details just need to be updated here?
Some additional minor feedback below:
% rustc --version
rustc 1.36.0-nightly (a784a8022 2019-05-09)
% cargo --version
cargo 1.36.0-nightly (759b6161a 2019-05-06)
If you label something public=true
that isn't actually publicly exposed, you currently don't get a warning. Would a warning or lint for that case be an appropriate future addition?
With the cargo feature enabled, cargo doc
currently fails, due to rustdoc
not understanding the --extern-private
flags as passed. Workaround is to temporarily remove the feature and all public
attributes from deps, or replace --extern-private
with --extern
and run rustdoc manually.
cargo doc --no-deps --open
Documenting barc v1.2.0 (/home/david/src/body-image/barc)
error: Unrecognized option: 'extern-private'
error: Could not document `barc`.
Caused by:
process didn't exit successfully: `rustdoc --edition=2018 --crate-name barc barc/src/lib.rs --color always -o /home/david/src/body-image/target/doc --cfg 'feature="body-image"' --cfg 'feature="brotli"' --cfg 'feature="default"' --cfg 'feature="memmap"' --cfg 'feature="mmap"' --cfg 'feature="olio"' -L dependency=/home/david/src/body-image/target/debug/deps --extern body_image=/home/david/src/body-image/target/debug/deps/libbody_image-f6307513eafde4da.rmeta --extern-private brotli=/home/david/src/body-image/target/debug/deps/libbrotli-914be93b87d00a74.rmeta --extern-private bytes=/home/david/src/body-image/target/debug/deps/libbytes-60c7a2c9551c05c4.rmeta --extern-private flate2=/home/david/src/body-image/target/debug/deps/libflate2-3410ad175205616a.rmeta --extern http=/home/david/src/body-image/target/debug/deps/libhttp-1bcf97f938c6fdd7.rmeta --extern-private httparse=/home/david/src/body-image/target/debug/deps/libhttparse-b04e539fbadba356.rmeta --extern-private memmap=/home/david/src/body-image/target/debug/deps/libmemmap-b29e83fdba55bd43.rmeta --extern-private mime=/home/david/src/body-image/target/debug/deps/libmime-df20e72307836353.rmeta --extern-private olio=/home/david/src/body-image/target/debug/deps/libolio-c7a6754af0be8b56.rmeta --extern-private tao_log=/home/david/src/body-image/target/debug/deps/libtao_log-7da4b359386cbcf7.rmeta --extern-private tempfile=/home/david/src/body-image/target/debug/deps/libtempfile-5c5a144b50e3000b.rmeta -Z unstable-options --cfg barc_std_try_from` (exit code: 1)
I'm happy to elaborate here or elsewhere if its useful.
If you label something public=true that isn't actually publicly exposed, you currently don't get a warning. Would a warning or lint for that case be an appropriate future addition?
That sounds like a good idea to me!
Implementing that will be a little tricky. Currently, rustc
isn't explicitly aware of the underlying public-dependency
feature - it simply treats all dependencies as public
by default. We would want to avoid showing 'unecessary public dependency' warnings to users who don't have the public-dependency
feature enabled, as these warnings would be both useless and unfixable.
We would probably need to add a -Z public-dependencies
flag to rustc
to ensure that we only enable the lint when the cargo feature is also enabled.
Is it necessary to make another RFC for something like this?
Or the alternative "--extern(:pub|:private)? name=PATH" syntax proposed by @petrochenkov could also get rustc
that detail, if it chose to preserve the distinction for this? It sounds like an implementation detail to me, but what do I know! ☺
I just tried enabling this feature on another lib crate (also for the purpose of collecting information on public deps) and noticed that examples/*.rs are another interesting edge case. If the examples define any pub
items (here really just for purpose of example) that reference the lib crate types, these will result in warnings of the pattern:
warning: type `Foo` from private dependency 'libcrate' in public interface
This is because each example is compiled, including as part of cargo test
, with --extern-private libcrate=...
Note this dependency isn't written in the Cargo.toml, its just implied for examples. Shouldn't examples be compiled with --extern:pub libcrate=...
instead (using newer proposed syntax just for clarity)?
Cc: @Eh2406 this last case (and possibly the one above about cargo doc
) might be more specific to cargo?
The feature's implementation doesn't currently work correctly with transitive dependencies.
If we load a crate named foo
as a transitive dependency, we still mark it private (or not) by looking at the --extern foo
option, even if refers to an unrelated crate and --extern
options in general are entirely irrelevant to transitive dependencies.
The dependency private-ness should be written into metadata and read from there for transitively loaded crates.
This brings a question - what if the same crate is private direct dependency and a public transitive dependency (or vice versa)? Should it be treated as private or public?
(I'm currently refactoring code in that area and may fix this issue as well.)
@Aaron1011
By the way, do you still have plans to implement the --extern:modifier
syntax from https://github.com/rust-lang/rust/issues/44663#issuecomment-475853173?
@petrochenkov I like the idea of the modifier syntax, but I'm curious how that would work with getopts
. If the intent would be to support multiple modifiers, would every permutation need to be registered as separate flags?
how that would work with getopts.
No idea :)
I didn't look into implementation details, only suggested a syntax that's more generic than --extern-private
.
I have posted a proposal for a new --extern
flag syntax at #67074.
I'm a bit confused about how re-exports are being treated. From the RFC: "Q: Can I export a type from a private dependency as my own?" says NO. However, it looks like various ways of re-exporting do not generate a warning:
pub extern crate private_crate;
or pub use private_crate;
pub use private_crate::some_item;
Is that intentional?
@Eh2406 in https://github.com/rust-lang/rfcs/pull/3146#issuecomment-881957976 wrote
The problem with "Public and private dependencies" is not the theory. It is fairly clear what we want it to mean. It is implementation that is the problem. In a SAT/SMT reduction of Dependency resolution it adds
O( (numbers of packages considered) ^ 2)
terms to the problem. More importantly in the Resolver as implemented it takes common use cases from sub second time to multiple hours time. There are a lot of changes to the Resolver that we can not stabilize because of limitations to performance or error messages even though we have a clear understanding of exactly what behavior we want and why.
Is more written about this? It definitely does make it harder, but I am surprised it is so bad in practice when Cabal etc. do this today. Were you ret-conning existing deps as public deps? (I thought the plan was to keep them private which I have my doubts about but which I thought would not suddenly increase the costs.)
I wrote that from memory, and wanted to go back and reread the records (mostly https://github.com/rust-lang/cargo/issues/6129) before expanding on it. It seems like my memory had lost some of the subtlety of the situation. Sorry.
There are some open question about behavior, best somerized at https://github.com/rust-lang/cargo/issues/6129#issuecomment-501783242. However, except for important surface level sintacs discussions, the available design space is pretty small. For various reasons there needs to be a "existing behavior" option in addition to "public" or "private" dependencies.
As to the runtime overhead for existing dependencies it is not large. As everything is marked "existing behavior", so it can create no conflicts. Even in the current implementation where everything is marked as private, which means that this can only add a conflict for the parent, conflicts tend to be small and simple. However the Resolver is a tricky and organically grown peace of code. I am not willing to stabilize new behavior for it that is not end-to-end property tested. If you turn on public & private dependencies
in our test case generator here, it will find a case where things take over 60 seconds to resolve. If you comment out that line or run the tests in release, it will find a case where our organically grown form of learned clauses has over simplified the problem, so the Resolver decided there is no valid solution, when there is one and the "Reduction to SAT" test can find it. I burnt myself out trying to find the sweet spot, a learned clause representation sparse enough for efficient back jumping with enough information to not miss cases.
Since then, I have been spending my time on the PubGrub project in the hope that by copying from the state of the art and rewriting from first principles, we will have a more solid foundation for adding these kinds of features.
The RFC pre dates the "Prior art" section. Do you have links to info about the corresponding features in "Cabal etc."?
@Eh2406 Sorry to leave your nice response hanging.
The RFC pre dates the "Prior art" section. Do you have links to info about the corresponding features in "Cabal etc."?
Off hand, just https://wiki.haskell.org/wikiupload/b/b4/HIW2011-Talk-Loeh.pdf linked in the other thread, and I found https://opam.ocaml.org/doc/External_solvers.html for OPAM which links some older research. But I would be happy to ask around to get more up to date info for Cabal.
Since then, I have been spending my time on the PubGrub project in the hope that by copying from the state of the art and rewriting from first principles, we will have a more solid foundation for adding these kinds of features.v
I read up a bit on that. Interesting and looks quite nice! It does seem the PubGrub algorithm out of the box is just for the all-public-deps case right? So if we switched to that it would be the solid foundation and the new features together?
PubGrub simplifies dependency resolution to a platonic ideal of it self. There is a lot of work to expand it to handle compatibility with all the gnarly details of Cargos resolver. A full discussion of each problem and are current thoughts for how to work around it is somewhat out of scope here, luckily @mpizenberg has written up a guide here with a section on "Advanced usage and limitations". We have a plan for how to reduce Cargo's "one per name and semver compatibility range" to PubGrub's "one per name". Figuring out how to extend that to also have "scoped goals" or "public dependencies", has not yet been figured out.
Despite having to do a lot of work to get back to where we are, I am hopeful that building off this base will work out better because PubGrub simplifications run deep. It has combined many different concepts (that Cargo's resolver has as different types) into one comparatively simple "incompatibility" type. All the different aspects of the problem (Error reporting, Conflict resolution, Unit propagation, ... ) share that vocabulary type. In Cargo's resolver adding a new "learned clause" kind involves interacting the new enum variant with all the moving parts, and thanks to the end-to-end property tests finding all the corner cases where they interact badly. I am hopeful that in PubGrub it is "express your property's as incompatibilities" (ether by reduction to the existing simplified problem, or by adding a new API) and then all the existing pieces will work with it.
Maybe someone will find a way to add it before the rebuilding compleats, but PubGrub is where I will be spending my time for now.
Maybe someone will find a way to add it before the rebuilding compleats, but PubGrub is where I will be spending my time for now.
Yes I definitely agree with this approach, to be clear.
We have a plan for how to reduce Cargo's "one per name and semver compatibility range" to PubGrub's "one per name". Figuring out how to extend that to also have "scoped goals" or "public dependencies", has not yet been figured out.
Heh that's the tricky bit. I would say "one per name" means all public dependencies. Cargo's "one per name and semver compatibility range" to me feel more like an optimization that all-private/unrestricted deps don't cause too much duplicative bloat -- I can't see how having multiple versions that that are semver compatible would actually break things, just cause a nuscience.
"scoped goals" sounds like private dependencies to me. Or rather, it's the combination of public and private deps that induces local non-global coherence issues. (All private means solving is trivial, all public means PubGrub as written works.)
I do see how one can turn foo = ">5"
into foo-6 = *
or foo-7 = *
or ..., but I worry it's a bit of a dead end. By all means, do something like that for now if you gets Cargo on PubGrub sooner, but I think changes will need to be made to PubGrub to actually track how packages are instantiated. Trying to defunctionalize something like foo ^>= 7 & bar(foo) ^>= 9
gets too messy.
Hi @Ericson2314 I'm just adding a few notes regarding PubGrub. We have to think more about the public/private feature, but I think it will be doable with a "proxy and bucket" scheme similar to the one presented in the guide. Anyway, we'll have a look at it and report how that goes.
@mpizenberg Thanks for that info! One thing I am slightly unclear on is how the "coherence" of public deps is maintained. I think you might need equality constraints, like a->c = a->b->c
for the case where a has a public dep on b and c, and b also has a public dep on c.
@Ericson2314 for more details, I've written a new section in the guide specifically about implementing public/private dependencies. It is currently under review with @Eh2406 so it's not published yet. But if you want to participate in the review of this section it lives here: https://github.com/pubgrub-rs/guide/pull/4
What is the status of this effort? Is someone working on implementing it? What's the next step? I just got bitten by this and would be willing to help out with the implementation.
@djc we have a working prototype for very similar public/private scheme in pubgrub presented here: https://pubgrub-rs-guide.netlify.app/limitations/public_private.html
So it will be on our radar with @Eh2406 as soon as we make progress on trying integrating pubgrub-rs with cargo, which will be the main focus of our effort in a couple months.
As for current cargo, I have no information.
I imagine that getting pubgrub-rs to stable Cargo might take relatively long...
This comment up thread still describes the current state of things.
Thanks! So I've read the RFC in more detail. It seems to me that a lot of the complexity in implementing this RFC is in the impact on the resolver/dependency resolution, but that the other parts of the RFC would be quite valuable on their own and would be substantially less complex to implement. How do people feel about starting with an MVP that's basically only:
Here's the angle I'm coming from: as the maintainer of a public library with fairly broad usage, exposing API types from a dependency publicly is a hazard because it means your semver-incompatible version bumps (which we generally like to avoid so as to avoid waste of downstream work) are coupled to your dependency's semver-incompatible bumps. Inclusion of duplicate downstream dependencies are something of a separate issue that's easier to diagnose nowadays than it was when the RFC was written (I usually use cargo deny for this).
In particular, I'm coming at this as the rustls maintainer. For rustls 0.20 we tried to make the webpki and ring dependencies private, and it turns out that I missed one case, meaning we now might need to force another semver-incompatible bump on a large number of downstream dependencies for this reason. While this case is silly because I could have found it by grepping the source code, in general auditing a largish crate for types/traits that appear in the public API is non-trivial, and AIUI the compiler already implements most of this analysis to warn about intra-crate privacy issues.
What about mandating every crate to explicitly depend on public dependencies of their dependencies? That is, if you depend on A which has B as its public dependency (export some B types) you should add B in your cargo.toml explicitly with a explicit version. In this way, problem of finding a solution for a SAT system will reduced to checking a particular solution for a SAT system, which can be done in linear time.
This is not perfect, but:
@HKalbasi this idea breaks for "facade crates," (like rand, futures, bevy, ...) where they reëxport all of the public dependency's types and you're expected to use them primarily, if not even exclusively, through the facade crate.
Especially for e.g. rand, where using rand_core is encouraged if you're a library just implementing rand_core traits, whereas consumers want to consume via rand. For rand, the facade is meant to be open, and not opaque to the outside world (as opposed to e.g. bevy, which is primarily only really intended to be consumed from the outside as a whole, through the facade, and the inner crates could be considered an implementation detail).
I question the assumption that "public/private" is the right indicator for whether deps should be duplicated.
It's easy to construct cases where public deps are nevertheless OK to duplicate. E.g. any time the final bin ends up publically depending on a lib at two different versions, but doesn't actually try to pass values between them.
Conversely, even if a dep is private, it's reasonable to want to avoid unnecessary copies to reduce binary size and compile time. This is mentioned as an aside in various other comments, but it's a real issue.
What I wish I had is a much simpler system, something like: dependencies never duplicated by default, but the final binary can explicitly allow duplicates in its Cargo.toml. (Or, for easier migration, allow by default but explicitly deny.) cargo update
barfs it it can't find a solution, tells you what crates would need duplicates, and you edit Cargo.toml
if that's what you want.
This doesn't change the requirements for the underlying constraint solver, but the input to it gets conceptually simpler.
Of course it would be better if intermediate libraries could also indicate which duplicates they cared about, but that starts adding complexities again. I'd much rather have a system where the final binary could just declare what to allow, than the current system where I'm fighting with Cargo that thinks it knows better.
It's easy to construct cases where public deps are nevertheless OK to duplicate. E.g. any time the final bin ends up publically depending on a lib at two different versions, but doesn't actually try to pass values between them.
And it's easy enough to allow the crate depending on two crates publicly exposing conflicting versions of a transitive dep to acknowledge and allow this.
Conversely, even if a dep is private, it's reasonable to want to avoid unnecessary copies to reduce binary size and compile time.
Everyone agrees that better controls over duplicated dependencies is a good thing. public/private dependencies is distinct from that, though; it's about allowing more things that should work to compile, and about controlling whether you expose a dependency or encapsulate it fully.
tells you what crates would need duplicates, and you edit
Cargo.toml
if that's what you want.This doesn't change the requirements for the underlying constraint solver, but the input to it gets conceptually simpler.
If it's still going to allow the cases where you've explicitly allowed duplicates (and notably, to determine what/how to duplicate), the constraint solver still needs to support working with said duplicates, so you don't simplify anything.
This is a good tool to have in order to control dependency duplication (it's in cargo deny
, in fact), but it doesn't influence what the constraint solver needs to be able to do.[^1]
[^1]: Well, actually, the constraint solver doesn't even support solving for "fewest duplicates" over the whole tree currently. In fact, that's a new thing to optimize for. It doesn't really add complexity to the existing system — you can just model it as making everything semver compatible — but it is "a new thing the solver would need to do."
Visiting during T-compiler backlog bonanza.
It would be nice if it had a S-tracking-* label that reflected its status.
Hey @rust-lang/cargo , do you think this can be tagged with S-tracking-unimplemented? Or should it be classified as S-tracking-design-concerns?
We might want to update cargo add
so that when it infers a dependency version, it checks from among its dependencies' public dependencies. This will make it more likely that a compatible version will be selected.
Some behaviour from the compiler lint that I'm not sure about. This code produces a public-in-private warning on use_advice
, even though that function is not accessible to the public. Is this intentional?
# Cargo.toml
cargo-features = ["public-dependency"]
[package]
name = "testfile"
version = "0.1.0"
edition = "2021"
[dependencies]
wasi = { version = "0.11", default-features = false }
// src/lib.rs
mod inner_private {
pub fn use_advice() -> wasi::Advice {
wasi::ADVICE_NORMAL
}
}
pub fn do_stuff() {
assert_eq!(wasi::ADVICE_NORMAL, inner_private::use_advice());
}
warning: type `Advice` from private dependency 'wasi' in public interface
--> src/lib.rs:4:5
|
4 | pub fn use_advice() -> wasi::Advice {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(exported_private_dependencies)]` on by default
warning: `testfile` (lib) generated 1 warning
This can be worked around by using pub(crate)
, as in ce607bbcb605944073185c287716adc738685d2e
We consider any pub
item to be public, even if not actually reachable. This is also why for example mod sealed { pub trait Sealed {} } pub trait MyTrait: Sealed {}
is allowed despite Sealed
not being reachable.
Summary
RFC (original, superseded): #1977 RFC: #3516 Cargo tracking issue: https://github.com/rust-lang/cargo/issues/6129 Issues: https://github.com/rust-lang/rust/issues?q=is%3Aissue+is%3Aopen+label%3AF-public_private_dependencies Cargo issues: https://github.com/rust-lang/cargo/issues?q=is%3Aopen+is%3Aissue+label%3AZ-public-dependency Documentation: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#public-dependency
This feature enables the ability to track which dependencies are publicly exposed through a library's interface. It has two sides to the implementation: rustc (lint and
--extern
flag), and cargo (Cargo.toml
syntax, and passing--extern
flags).This feature was originally specified in rust-lang/rfcs#1977, but was later down-scoped in rust-lang/rfcs#3516.
About tracking issues
Tracking issues are used to record the overall progress of implementation. They are also used as hubs connecting to other relevant issues, e.g., bugs or open design questions. A tracking issue is however not meant for large scale discussion, questions, or bug reports about a feature. Instead, open a dedicated issue for the specific matter and add the relevant feature gate label. Discussion comments will get marked as off-topic or deleted. Repeated discussions on the tracking issue may lead to the tracking issue getting locked.
Unresolved Questions
Steps
Command to update Cargo.lock to minimal versions (rust-lang/cargo#4100)Makecargo publish
use the minimal versions allowed by Cargo.tomlexported-private-dependencies
allow
-by-default pre-2024 anddeny
-by-default in 2024+ / in the 2024-compatibility lint groupallow
orwarn
(context from zulip)Non-blocking further improvements
Changes from RFC
cc @rust-lang/cargo @epage