dtolnay / dtolnay/macro-string
`env!` / `include!` / `include_str!` do not end up in dep-info entries resulting in stale artifacts under rustc-wrapper caches like sccache
- Dominant language
- Rust
- Stars
- 44
- Forks
- 2
- PR merge metrics
- No merged PRs in 30d
Description
I've been debugging a situation with a procmacro that uses `macro-string` where changes to an environment variable used in it via `env!` and passed through a macro-string resulted in stale build artifacts rather than the latest environment value being embedded.
```rust
pub const GIT_REVISION: &str = mymacrolib::baked!(env!("GIT_REVISION"));
```
I created a Docker image that reproduces the problem with sccache setup, and a repo with a procmacro using macro-string:
- https://github.com/leighmcculloch/rust-sccache-env-proc-macro-cache-collision
My understanding so far is that this is happening because macro-string evaluates and expands the env! within the procmacro meaning that rustc never sees the `env!` in the crate and so is unaware that it is a dependency and the env value doesn't get included in the build artifact's `dep-info`. When rebuilding the build artifact with a different `env!` sccache will return the earlier cached artifact because it cannot distinguish between them since the env is not included in the `dep-info`.
As a work-around I've found that having my procmacro emit a `const { let _ = #input }` can resurface the `env!` back in the context of the crate unexpanded. For example:
```rust
#[proc_macro]
pub fn baked(input: TokenStream) -> TokenStream {
let raw = proc_macro2::TokenStream::from(input.clone());
let macro_string = parse_macro_input!(input as MacroString);
let s = macro_string.eval().unwrap();
let lit = proc_macro2::Literal::string(&s);
quote! {
{
const { let _ = #raw; }; // surface env!()/include!() to rustc's dep-info
#lit
}
}
.into()
}
```
Is the dep-info loss of `env!`/`include!`/`include_str!` expected / known issue?
Because macro-string is an embedded detail in macros it can be difficult to know if it is safe to use sccache for a build or not with a rust library, because internally or somewhere in the dependency tree it may be in use in a way that poisons the cache.
Would it be reasonable for `MacroString` to somehow encourage re-exporting of the input as a way to reduce the occurrence of this bug? It's not obvious to me how this would be achieved so I expect my question is naive at best.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.