Motivation
It is not uncommon that proc macros introduce build dependency to non-Rust files. For example, pest reads the grammar file, graphql-client reads schema file and query file.
Currently there is no direct way for those proc macro to inform compiler about the dependency. One workaround is to use include_str!
or include_bytes!
macro and assign its result to a const. This isn’t ideal as the generated program doesn’t necessarily need such content, while including all the data into generated source file may slow down build time and bloat memory usage, especially when the file is large.
The largest example I can find right now is GitHub’s GraphQL schema file, which is ~256KiB. It isn’t too bad to include. But proc macro may at some point want to read larger files like archive files, system images, and so on, at which point, using include_str!
or include_bytes!
may not be an option.
Cargo build scripts can output rerun-if-changed=
to inform Cargo about such dependency, but proc macro has no way to do so at the moment.
Detailed design
Introduce a new compiler built-in macro depends_on
(name to be bikesheded) which takes a file name as argument (either absolute path or relative path to current file?). It informs the compiler that when the specified file is modified, the current file should be re-compiled.
For example:
depends_on!("../grammar.pest");
Alternatives
There are several possible alternatives:
Add opt-in parameter to proc macro
For example, we can pass an additional, for example, &mut Context
parameter to proc macro function, via which the function can add new dependencies. To avoid breaking change, this may be controlled by an additional parameter to #[proc_macro]
and #[proc_macro_derive]
for whether such argument should be passed in.
Allow proc macro to return more than just TokenStream
Convert return type of proc macro to something like impl Into<ProcMacroResult>
, and have ProcMacroResult
contain the current TokenStream
as well as dependency information. Then we just have impl From<TokenStream> for ProcMacroResult
.
This way we don’t break any existing proc macro, but make it possible to extend what can be returned from proc macro.
Have the compiler not actually import file content in certain case
This was suggested below by CAD97.
Either the compiler don’t read the content when include_str!
or include_bytes!
is assigned to an underscore const, or an attribute can be added to communicate that.
Have compiler track file open in proc macro
This was suggested below by josh.
Have the standard file functions track file opens when called from a proc macro, and emit dependencies accordingly.
Do nothing
Just have proc macros generate include_bytes!
for that purpose.
What do you think?
(Edit: added several proposals below to alternatives.)