-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Make uniqueify_with generate deterministic macro names, to fix build failures #2797
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
Conversation
|
The following code will fail to compile after this change, because we made two identical macro calls and they get hashed to the same value. Which makes me think we should just hash as many things as we can get our hands on -- until Span::source_file / line / column are stabilised. #[macro_use]
extern crate rocket;
#[get("/")]
fn index() -> &'static str {
"GET"
}
mod module {
#[get("/")]
pub fn index() -> &'static str {
"whatever"
}
}
#[launch]
fn rocket() -> _ {
rocket::build().mount("/", routes![index])
} |
|
One thing you can try is hashing the debug output of the relevant That being said, I'm not sure this is sufficient to avoid collisions. In particular, will this work if the route is generated by a declarative macro? |
cb9f324 to
8a1bb81
Compare
|
Good idea! It seems to have worked. That test case now compiles. I guess I should add it as an actual test case. |
|
Can you add both that test and a test that generates routes from a macro_rules macro? |
|
Done. I think that should cover it. |
core/codegen/src/syn_ext.rs
Outdated
| // Use rustc_hash because it's deterministic, whereas the DefaultHasher | ||
| // in std is nondeterministic. This prevents problems where compiling |
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 believe this is necessarily true. DefaultHasher::new() always returns a SipHasher with keys of 0, so it should always hash to the same values and should thus be deterministic.
Because of the usage of `include_str!`, we were baking paths to generated files in `lib.rs`. In setups where the build can be executed remotely (e.g. when building with Buck2), those paths would be different depending on whether the build ran locally or remotely. This difference propagates to `pyo3-macros`. Because Buck2 runs the metadata and codegen builds separately (for increased parallelism), they can have different contents due to the above, causing rustc to find two versions of the crate, and erroring out. This is not observable with Cargo because it runs both builds with the same rustc invocation. See facebook/buck2#1206 and rwf2/Rocket#2797 for more context. This commit fixes the issue by simply reading `OUT_DIR` at run-time, rather than compile-time, so that the content of `lib.rs` is fixed. Closes facebook/buck2#1206 Many thanks to https://github.com/cormacrelf for pointing out the root of the issue.
Because of the usage of `env!`, we were baking paths to generated files in `lib.rs`. In setups where the build can be executed remotely (e.g. when building with Buck2), those paths would be different depending on whether the build ran locally or remotely. This difference propagates to `pyo3-macros`. Because Buck2 runs the metadata and codegen builds separately (for increased parallelism), they can have different contents due to the above, causing rustc to find two versions of the crate, and erroring out. This is not observable with Cargo because it runs both builds with the same rustc invocation. See facebook/buck2#1206 and rwf2/Rocket#2797 for more context. This commit fixes the issue by simply reading `OUT_DIR` at run-time, rather than compile-time, so that the content of `lib.rs` is fixed. Closes facebook/buck2#1206 Many thanks to https://github.com/cormacrelf for pointing out the root of the issue.
Because of the usage of `env!`, we were baking paths to generated files in `lib.rs`. In setups where the build can be executed remotely (e.g. when building with Buck2), those paths would be different depending on whether the build ran locally or remotely. This difference propagates to `pyo3-macros`. Because Buck2 runs the metadata and codegen builds separately (for increased parallelism), they can have different contents due to the above, causing rustc to find two versions of the crate, and erroring out. This is not observable with Cargo because it runs both builds with the same rustc invocation. See facebook/buck2#1206 and rwf2/Rocket#2797 for more context. This commit fixes the issue by simply reading `OUT_DIR` at run-time, rather than compile-time, so that the content of `lib.rs` is fixed. Closes facebook/buck2#1206 Many thanks to https://github.com/cormacrelf for pointing out the root of the issue.
Overview
In a nutshell, some slightly exotic ways of compiling rocket with rustc fail due to nondeterminism in
rocket_codegenleading to rustc correctly noticing that you've compiled two incompatible versions ofrocket. The nondeterminsim is inIdentExt::uniqueify_with.I believe you can fix this by just doing it deterministically. I don't think it needs to be random. Reviewers please help determine if the things that are hashed for the route macro are enough to avoid collisions in the generated code. Specifically these. My gut feeling is you will also want the HTTP method to be hashed.
Rocket/core/codegen/src/attribute/route/mod.rs
Lines 211 to 215 in 2a1afd1
Background -- rocket
See this for why random identifiers are being generated at all. #964
It currently does so using a combination of
and some deterministic ones
#[route]macrorocket_codegen::export! { macro_rules! name {... } }The randomness seems like someone tried really hard to make it as random as possible. I don't think anything but the DefaultHasher's initialization was necessary to achieve that, and I put it to you that no randomness is required at all.
Background -- rustc
--cfgflag,--Cmetadataflag, all the dependencies, or something like that.My particular circumstances that led to experiencing this issue are:
rustcon every crate -- one for metadata only, and one for codegen.cargo checkmetadata is not reused forcargo buildand when you do runcargo build, the metadata + codegen outputs are produced during the same rustc invocation. (Incidentally this is why runningcargo checkdoes not make a subsequentcargo buildany faster.)The build errors you get look like
found possibly newer version of crate rocket which thing depends on. Almost all of the mentions of this error online are due to people compiling libstd / libcore from scratch and linking the wrong version, or compiler developers mixing different stages. Rustc does very reliably compute SVH, so generally when it's telling you this, it's not lying.Side note
Apart from the build failure, not ever being able to build identical copies of rocket / rocket applications is a problem if your build tool does caching and yeets the build products off to be used on other machines. That's a whole other can of beans.
Illustration
Not a repro because too many steps and buck2 is complicated. But I reduced rocket down to a few lines of code to discover the cause of the build failure, so may as well show you.
Notable compile steps:
And the binary build fails as below: