Rust doesn’t yet support eager macro expansion (except for a few special built in cases rustc devs granted themselves), which makes it hard to implement some macros robustly. If you put #[myproc]
on something the macro gets the unexpanded item as input, which prevents users from being able to use macros that expand into tokens myproc
is looking for.
I was thinking about how to use build.rs
to workaround this when I stumbled on this cbindgen
issue:
cbindgen
expands macros by essentially callingcargo rustc --pretty=expanded
.
Which makes sense, cbindgen
needs to generate bindings for everything, even things that may only exist after macro expansion. This is exactly like my use case.
I don’t know how robust their approach is — I assume it’s equivalent to cargo expand
which actually warns not to rely on its output being accurate:
Be aware that macro expansion to text is a lossy process. This is a debugging aid only. There should be no expectation that the expanded code can be compiled successfully, nor that if it compiles then it behaves the same as the original code.
But… a lossless version must be possible in order for rustc
to work? So I started digging into what cbindgen
actually does… which is apparently manually reimplement a significant amount of cargo in order to divine what arguments to give cargo to give rustc.
… there must be easier ways? Like I thought the whole idea of compiler-as-a-library being thought about from the beginning was that rustc and cargo would just have some nice API I can call to say “do whatever you’ve got to do to expand this” and get accurate output? I realize they may be unstable APIs The top Google result for “rustc as library” and “rust embed compiler” is a blog from 2014 which I’m guessing is out of date?