Skip to content
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

Procedural macros in release mode rebuild all dependencies #929

Open
shepmaster opened this issue May 4, 2023 · 0 comments
Open

Procedural macros in release mode rebuild all dependencies #929

shepmaster opened this issue May 4, 2023 · 0 comments
Labels
enhancement Something new the playground could do

Comments

@shepmaster
Copy link
Member

While taking to @dtolnay about #928, we realized that release mode procedural macros are rebuilding dependencies (and may always have been). They had this as a suggestion:

The goal is to get cargo build --release when proc-macro = true to reuse artifacts that got built previously when cargo build and cargo build --release were previously run with proc-macro set to false.

The artifacts that got built previously are:

  • everything in dev mode: opt-level = 0 and debug = true
  • everything in release mode: opt-level = 3 and debug = false

This means [profile.release.build-override] debug = true is not the right thing because that's gonna make cargo look for artifacts with opt-level = 3 and debug = true, which is not something that got built previously.

The simplest fix is to make release proc-macros reuse artifacts from the release non-macro build, by doing this:

[profile.release.build-override]
codegen-units = 1
opt-level = 3

I confirmed that fixes the issue. However that is not my preferred fix because that slows down your up-front cargo build --release invocation; it will spend more time compiling things like serde_derive than it used to, and there is no benefit to users from having the macros be optimized.

Sadly you can't make release proc-macros reuse artifacts from the dev non-macro build. Naively you might try:

[profile.release.build-override]
codegen-units = 1
debug = true
debug-assertions = true
opt-level = 0
overflow-checks = true

which makes the entire profile line up correctly with what was previously built by cargo build. Yet Cargo will still not reuse the existing artifacts only because it wants --release artifacts to go under target/release/, and the existing ones were put under target/debug/, and instead of saying "oh I have these already in the other directory, let me copy them" it will just rebuild the same artifacts in the new location.

But here is my preferred fix:

[profile.playground]
inherits = "dev"  # mutates to "release"
codegen-units = 1
incremental = false

[profile.playground.build-override]
codegen-units = 1
opt-level = 0
debug = true
debug-assertions = true
overflow-checks = true

Now instead of cargo build + cargo build --release, your container will instead run cargo build --profile=playground twice, changing the "inherits" value in between. And the Debug/Release dropdown will set the same "inherits" value instead of a --release argument.

This speeds up your docker build compared to before, because the second cargo build --profile=playground will be faster than the current cargo build --release. You'll be building a total of 1 copy of serde_derive etc, instead of 2 separate copies. Your image will also be smaller.

On my machine, building your current Cargo.toml from the main branch produces a target directory that is 2.8 GB, whereas building my suggested fix produces 2.3 GB, which is 16.2% smaller

@shepmaster shepmaster added the enhancement Something new the playground could do label May 4, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Something new the playground could do
Projects
None yet
Development

No branches or pull requests

1 participant