-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
Can't generate feature gated code from a proc macro in a reliable way when used by both normal/build dependencies with resolver="2"
#14415
Comments
resolver="2"
does make it impossible to generate feature gated code from a proc macro in a relaiable wayresolver="2"
makes it impossible to generate feature gated code from a proc macro in a relaiable way
resolver="2"
makes it impossible to generate feature gated code from a proc macro in a relaiable wayresolver="2"
resolver="2"
resolver="2"
proc-macros are in an unfortunate situation where the main crate depends on them but they generate code for the main crate, requiring them to know what is in the main crate. Another problem that crops up due to this cyclic relationship is that the proc-macro can generate code that is "too new" for the main crate if work isn't done by the end-user or the maintainer to keep them in lockstep (e.g. using |
See also some past discussion at rust-lang/rust#88903 |
Would this be addressed by providing some way for proc macro crates to get information about the fully resolved crate graph at runtime? That way the proc macro crate could generate code based on the features actually enabled for the consuming crate, and might not even need features itself (potentially improving compile times...) It would also allow the proc macro crate to error if the consuming crate has an incompatible version. |
Another idea I had brought up at one point was that we expose what features are enabled for dependencies, see #9094 (comment) This would allow a proc-macro to generate code with cfg's like This assumes that the user is directly depending on This then gets into package name vs dependency name. If its package name, we can't predict it (true also for code without |
We currently tell build scripts about what of your own features are enabled, see We could use this or a similar mechanism to tell proc macros and build scripts about dependency features like my idea for |
I feel It's probably gonna make me unpopular, but is there a chance to default back to resolver=1 and leave resolver=2 for use cases that need it, like the mentioned no_std builds? Otherwise, another workaround I'd like to propose is to enable patching the feature list of dependencies. That's not going to help with diametrically opposed features like Example: there's a proc macro crate [dependencies]
A = { features = [] } There's the main app which depends on both the proc macro crate [dependencies]
P = { }
A = { features = [ "additional_feature" ] }
# what I'd like to to is force unify A between main crate (this toml) and P
[patch.P.dependencies.A]
features = [ "additional_feature" ] That's still a clunky hack, and really non-obvious, but would at least offer a path to solve this situation for some cases. |
Changing the default for I doubt we'd want to roll back to v1's unification behavior because it also affects target dependency unification and normal/dev dependency unification which I've not seen concern raised over, see https://doc.rust-lang.org/nightly/cargo/reference/resolver.html#feature-resolver-version-2 As for reverting host/target unification in a v4 resolver (edition 2024 includes a v3 resolver), we'd need to weigh these proc-macro use cases against the other use cases affected and the other potential solutions we'd have for proc-macros. Looking at the history we've pieced together for this issue,
In going 3 years before the problem is reported as affecting people, its hard to see this as a pressing concern that would outweigh the users who benefit from host/target unification. We are also still exploring other solutions that might benefit both proc-macro authors and people needing v2 resolver.. btw we will be exposing more knobs for the resolver with rust-lang/rfcs#3692 and there is a future possibility of giving more control over the parts of resolver v2. There are a lot more questions about doing that than there was for rust-lang/rfcs#3692 though. |
I would like again to firmly disagree that changing the default feature resolver is something that's allowed at an edition boundary. The cargo team shouldn't even consider that. See here for the extended reasoning
I need to strongly disagree here that this is not a pressing concern. Given that this still is a behavior regression caused by the resolver 2 switch this alone should make this a high priority issue for the cargo team. I already pointed that out several times back then. I cannot force the team to take this kind of issues seriously, but just stating that it doesn't seem to be pressing misrepresents the facts.
You explicitly stated in RFC-3692 that this won't have any feature to control host-target feature unification, so it cannot help for this issue. As pointed out there several times it only makes this problem worse, without providing a solution. So please do not bring it up as solution here. As for the actual issue: At least for the diesel usecase any solution that would just expose the feature flags of the consuming crate (diesel in that case) to the proc-macro crate (diesel_derives in that case) would be sufficient. If that's via an explicit API or via side channels like environment variables doesn't really matter much for the consuming crate, as long as these information are tracked by the cargo and sufficient rebuilds are triggered in case these values change. I think that might be a better solution than tweaking feature unification as it completely sidesteps the problem. After all my main point of frustration here is not that the unification might change, but that I cannot do anything to migrate the issues that this can cause for my users. |
Maybe put a different way, this isn't worth talking about for a couple of years, including whether we are allowed to make that change or not.
I understand you feel this is a high severity issue. You've explained the issue in the past. What is missing is helping us understand why you feel it is high severity. Being a regression is not enough. We have other regressions and we will continue to have them. There are also many "features" that are blocking people from what they are trying to accomplish and the delineation between feature and regression is just semantics to them. In helping us understand why this is important, it would help to illustrate the impact and likelihood. Impact is fairly well understood, the build fails. How severe that is is dependent on available mitigations. It would be good for us to explore in this issue what workarounds could exist and what their limitations are. For example, what is the negative impact of the user enabling extra features on normal dependencies? As for likelihood, its hard to feel like hitting this is a likely occurrence based on the information we've collected so far. For example, can you help point to places where users have hit this? I've actually was wanting to look at what these user reports are like and tried to find them in diesel's repo but I only found the initial issue without any discussion since then of users running into this or backlinks from duplicate issues being closed.
I didn't say RFC 3692 would help with this issue. I was pointing out a future possibility from it. |
I consider this as high severity because this:
The later never happened for whatever reason, but now you as a team instead try to make that situation even worse.
Honestly from my point of view this all does not really matter, as you as a cargo team decided to break that old behaviour. That's your bug and therefore your responsibility to fix that. That written: I'm aware of at least two occurrences of this (or a really similar issue) in the last week:
Given that frequency I wouldn't call that a very rare issue.
As written already several times before: Enabling additional features might be not an option as that can pull in undesirable dependencies, like native libraries.
See the examples given above. That are only reports from the last seven days that I'm aware of without a larger search. I would like at least to claim that you significantly underestimate the impact of that if you only concentrate on diesel here. Also there is always a significant number of unreported occurrences of such behaviour as people might dismiss it as strange interaction or whatever. |
Problem
Consider the following example:
Assuming that host and target match:
Given this situation: How do I resolve that while supporting both resolver versions. If the answer is: You cannot, then resolver = "2" is a breaking change and should have been marked as such (== shipping rust 2.0). I fully understand that it is far to late to roll back that change but I would like to see the cargo team to at least acknowledge that they broke something and that they should prioritizing working on a fix (and maybe more than working on implementing new features!).
Steps
For a real word example try to build the following crate:
This breaks diesel as we cannot encapsulate the proc-macros and the main crate as "one" unit.
Possible Solution(s)
resolver="1"
behavior.)Notes
See the offtopic part of #14406 for more discussion on this topic
Version
The text was updated successfully, but these errors were encountered: