-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Tracking Issue for proc_macro::{tracked_env, tracked_path} #99515
Comments
This feature is not in a great state. The original PRs were mostly about the implementation details, with almost no discussion on the public API. There's still many unanswered design questions, such as naming, whether Instead of discussing every single detail separately, it'd probably be best to start with a more complete proposal for how these APIs should look, and then discuss that. (Usually most of this happens before an unstable feature is merged and tracked, but this has already been merged, hence this tracking issue.) |
Considering these APIs effectively mirror the Right now the main reason you run into this issue is because someone already has functionality in a build script and wants to convert it into a |
I don't think that is a good argument. It is relatively common to forget to register interest with build scripts I believe. In addition it is pretty common to write helper functions that register interest and at the same time read the file/env var to prevent forgetting this. The reason that no such function exists by default for build scripts is because there is no way for cargo to provide a crate to build scripts with said functions. Furthermore returning the value is essential for making proc macros work with virtual filesystems and with compiler session local env vars. |
Maybe? But that is probably a very different argument to begin with. Today where I'm standing there is functionality available with
By coupling these things together this has a high change of turning into a never ending argument because there will always be a disagreement about how this should work. In fact, even today you will find no agreement on how to best use the build script equivalents and if we had to come to an agreement about his this should work there, we probably wouldn't have solution there today with build scripts. If there is a need for such an API it can always be added at a later point.
Of course there is. It would always have been possible for cargo to ship a utility library that is linked against build scripts the same way as
That same argument can be brought up for build scripts. |
The interest registering version can be trivially implemented in terms of the version that returns the value by discarding the return value, but not the other way around. In addition the interest registering versions may become entirely useless if we start sandboxing proc macros depending on the way we do this.
For build scripts it isn't all that important that changing a file in an editor without saving it reruns them. It is essential for proc macros. In addition rust-analyzer is already having a lot of trouble with proc macros going outside of their implied (unenforced) sandbox, while it doesn't have any issues with build scripts as those run in the same environment as with a regular cargo build due to rust-analyzer using cargo for invoking them. |
I want to leave another piece of input here that I believe are relevant:
If returning contents turns out to be useful it can always be added as an additional API. I think coupling these things will make this feature stay in not stable land for a lot longer than if those discussions are separated. |
I think |
Just a note here that the current implementation does not work with relative paths. It works if I use absolute ones though. |
@wdanilo Can you put together a reproduction? It seems to work fine for me. The path will be relative to cwd where rustc is run, which for Cargo is the workspace root (which matches the way a proc-macro would access relative paths). |
@ehuss Not this kind of relative path, sorry for not being clear enough here. In my case it was something along the lines of |
Yes, please create a minimal reproduction if you can. Also, please post it as a new issue (and cc me). Tracking issues are not a good way to discuss individual issues. |
Can I imitate the behaviors of these two APIs by adding |
first, second, afaict this would make rustc recompile the output of the proc-macro, not necessarily rerun the proc-macro itself. |
I'm pretty sure the macros get rerun if the file used for |
I wouldn't depend on that since rustc in incremental mode likes to cache stuff on disk and it's plausible to cache proc-macro outputs. |
I don't think we need to worry about that: rust/compiler/rustc_span/src/source_map.rs Line 238 in c0d6003
So as I understand it, the file is tracked for changes explicitly, and any relevant caches (if any) should be invalidated automatically. Everything else would break incremental builds fundamentally. |
the problem isn't that |
Ok, that may be true, I have no idea how the compiler tracks which files affect the results of a proc macro. Wouldn't that affect |
Apart from tracked_path and rustc does not track which files affect the proc macro output at all. It currently reruns all proc macros every time rustc runs, though in the future it will probably start to cache proc macros in the incremental compilation cache. And cargo reruns rustc only when any of the files mentioned in the dep info file change. tracked_path adds an entry for the given file to the dep info file. |
Do you know if this is tracked somewhere? Would be great to have. |
I don't know of a tracking issue for this, but #125356 would one step towards this (caching decl macros) There have been discussions in a variety of places including the internals forum and zulip. |
Hi, I have some time, and wanted to see if I can help out on this effort to cache proc macro expansions :) Having seen https://www.coderemote.dev/blog/faster-rust-compiler-macro-expansion-caching/ (their changes are closed source though), which found that up to 40% of incremental build times are sometimes due to proc macro expansion, I also did some profiling on a project of mine that uses bevy (which has a lot of custom derives), and found that proc macro expansion also makes up for 40% of my incremental build time. Additionally there was around 20% of time spent in codegen afterwards, which I thought might also go down a bit with proc macro caching, but I have not measured this(!). I think the 40% are worth it anyway, even if no additional (codegen) benefits show up in the end. Ongoing Progress I found:
Possible Progress I see:I did not yet see a way to "opt into" this dependency tracking feature for proc macros (please let me know if I missed it). Cargo has the common Maybe something like Given that this might substantially improve build times for incremental builds, I think it would make sense to try and drive a path forwards here, and would be happy to help/implement something for that :) |
What about macros like |
Ok, taking a closer look at proc-macro caching, it seems like #125356 (mentioned in #99515 (comment)) definitely makes sense as a first step, since the basic machinery for caching decl macros will probably also be relevant for proc-macro caching. So would be happy to help with that as well, but not sure about the PR status, so I'll inquire there 👍 |
@Skgland that's actually a good question. It's a limitation to the entire The issue is Maybe we should rename In classical unix terminology, directories are special types of "file"s, but we already have the |
Based on rust-lang/rfcs#3200 (comment) I would have though directories are handled as expected.
Also isn't this already something cargo needs to track e.g. Edit: I think that comment was referring to rust-lang/cargo#8973 though not sure how that effects tracked_path as I don't see a corresponding PR for rust itself. |
rustc outputs .d files ( Cargo then calls the So yeah, you are right, directories are handled (and handled recursively). |
This would need to be properly handled by rust as well in case proc macro outputs are cached in the future (#99515 (comment)), so that the cache is invalidated if the directory content changes. Doesn't help if cargo reruns rustc as it detects the change, but rustc doesn't detect the change and reuses a cached result. I think this might be a new case to handle for rustc as currently I don't know of anything that enumerates folders. There is |
Make declarative macro expansion a part of query system (cont. of rust-lang#125356) This is a continuation of the effort to make declarative macro expansion a part of the query system from rust-lang#125356 by `@SparrowLii.` #### Description from that PR: > This is an attempt to make the macro expansion a part of incremental compilation. > > Processing of procedural macros is difficult since they may involve interactions with the external environment. Declaring macros is a good start. > > **It is not yet possible to test the effect of this PR on incremental compilation since the new query is declared as eval_always.** #### Status of this PR: * It is rebased against a much more recent `master` commit * It contains the original commits from rust-lang#125356 (in a rebased form) * It adds the missing implementation for retrying macro matching that provides (better) error diagnostics * This was done by refactoring `rustc_expand::mbe::diagnostics::failed_to_match_macro()` to only require a `ParseSess` instead of an `ExtCtxt`. Otherwise, `ExtCtxt` would need to be in the interface of `TcxMacroExpander`, which is not possible, because `ExtCtxt` is part of `rustc_expand`, which depends on the crate that contains `TcxMacroExpander`, `rustc_middle`, and thus would introduce a circular dependency. * This refactoring moved the retrying down into the `impl TcxMacroExpander for MacroRulesMacroExpander` (this is just a change compared to the original PR, otherwise not important to know). * This PR passes `./x test tests/ui`, which produced errors before that were all due to the missing implementation of retry macro matching. * This PR does **not** yet contain changes for the open discussions from rust-lang#125356. I wanted to fix the tests first before tackling them, and I also need to figure out what the best solutions for them are. I'd welcome any help/support with this, e.g., opening up a corresponding discussion on this PR with a summary/the final decided fix if available :) In general, I'm new to working on rustc, so would be thankful for a bit more background/explanations in discussions and comments :) Thanks! :) (tangentially relevant: rust-lang#99515)
…ng, r=<try> Experimental: Add Derive Proc-Macro Caching # On-Disk Caching For Derive Proc-Macro Invocations This PR adds on-disk caching for derive proc-macro invocations using rustc's query system to speed up incremental compilation. The implementation is (intentionally) a bit rough/incomplete, as I wanted to see whether this helps with performance before fully implementing it/RFCing etc. I did some ad-hoc performance testing. ## Rough, Preliminary Eval Results: Using a version built through `DEPLOY=1 src/ci/docker/run.sh dist-x86_64-linux` (which I got from [here](https://rustc-dev-guide.rust-lang.org/building/optimized-build.html#profile-guided-optimization)). ### [Some Small Personal Project](https://github.com/futile/ultra-game): ```console # with -Zthreads=0 as well $ touch src/main.rs && cargo +dist check ``` Caused a re-check of 1 crate (the only one). Result: | Configuration | Time (avg. ~5 runs) | |--------|--------| | Uncached | ~0.54s | | Cached | ~0.54s | No visible difference. ### [Bevy](https://github.com/bevyengine/bevy): ```console $ touch crates/bevy_ecs/src/lib.rs && cargo +dist check ``` Caused a re-check of 29 crates. Result: | Configuration | Time (avg. ~5 runs) | |--------|--------| | Uncached | ~6.4s | | Cached | ~5.3s | Roughly 1s, or ~17% speedup. ### [Polkadot-Sdk](https://github.com/paritytech/polkadot-sdk): Basically this script (not mine): https://github.com/coderemotedotdev/rustc-profiles/blob/d61ad38c496459d82e35d8bdb0a154fbb83de903/scripts/benchmark_incremental_builds_polkadot_sdk.sh TL;DR: Two full `cargo check` runs to fill the incremental caches (for cached & uncached). Then 10 repetitions of `touch $some_file && cargo +uncached check && cargo +cached check`. ```console $ cargo update # `time` didn't build because compiler too new/dep too old $ ./benchmark_incremental_builds_polkadot_sdk.sh # see above ``` _Huge_ workspace with ~190 crates. Not sure how many were re-built/re-checkd on each invocation. Result: | Configuration | Time (avg. 10 runs) | |--------|--------| | Uncached | 99.4s | | Cached | 67.5s | Very visible speedup of 31.9s or ~32%. --- **-> Based on these results I think it makes sense to do a rustc-perf run and see what that reports.** --- ## Current Limitations/TODOs I left some `FIXME(pr-time)`s in the code for things I wanted to bring up/draw attention to in this PR. Usually when I wasn't sure if I found a (good) solution or when I knew that there might be a better way to do something; See the diff for these. ### High-Level Overview of What's Missing For "Real" Usage: * [ ] Add caching for `Bang`- and `Attr`-proc macros (currently only `Derive`). * Not a big change, I just focused on `derive`-proc macros for now, since I felt like these should be most cacheable and are used very often in practice. * [ ] Allow marking specific macros as "do not cache" (currently only all-or-nothing). * Extend the unstable option to support, e.g., `-Z cache-derive-macros=some_pm_crate::some_derive_macro_fn` for easy testing using the nightly compiler. * After Testing: Add a `#[proc_macro_cacheable]` annotation to allow proc-macro authors to "opt-in" to caching (or sth. similar). Would probably need an RFC? * Might make sense to try to combine this with rust-lang#99515, so that external dependencies can be picked up and be taken into account as well. --- So, just since you were in the loop on the attempt to cache declarative macro expansions: r? `@petrochenkov` Please feel free to re-/unassign! Finally: I hope this isn't too big a PR, I'll also show up in Zulip since I read that that is usually appreciated. Thanks a lot for taking a look! :) (Kind of related/very similar approach, old declarative macro caching PR: rust-lang#128747)
use tracked_path in rustc_fluent_macro According to comments in rust-lang#99515 (comment), the trick used in `rustc_fluent_macro` may be broken by caching decl macros. So use `proc_macro::tracked_path::path` to ensure it works.
Rollup merge of rust-lang#131932 - usamoi:tracked-path, r=Nadrieril use tracked_path in rustc_fluent_macro According to comments in rust-lang#99515 (comment), the trick used in `rustc_fluent_macro` may be broken by caching decl macros. So use `proc_macro::tracked_path::path` to ensure it works.
Feature gate:
#![feature(proc_macro_tracked_env, track_path)]
This is a tracking issue for
proc_macro::tracked*
, to allow adding files and environment variables to the build system's dependency tracking.Public API
Steps / History
tracked_env::var
: proc_macro: Add API for tracked access to environment variables #74653tracked_path::path
: addtrack_path::path
fn for usage inproc_macro
s #84029path
to acceptAsRef<Path>
instead ofAsRef<str>
Unresolved Questions
proc_macro
, but there's barely been any discussion on the public interface.The text was updated successfully, but these errors were encountered: