Using build.rs for macro expansion

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 calling cargo 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 :slight_smile: 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?

The internal representation of macro expansion is lossless, but when actually printing out source code, there is simply no way to represent hygiene info, so printing out the results of expansion will always be lossy. There is an option to output hygiene info, but this is done in the form of comments that are treated like any other comment when parsing again.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.