Interaction between independent proc macros via file I/O

This topic has nothing to do with any projects and is purely out of curiosity, but is it reliable to use independent proc macros via file I/O in a single crate?

Suppose I have two macro crates containing a proc macro, respectively, and I want to use those dependently within a single crate. For example, imagine that the first macro, say macro_a, performs complex operations and returns i32 while the second one, say macro_b, expects a token of i32 and performs another operation. In this scenario, since macros are expanded lazily in the current macro system, we can not write something like

macro_b!(macro_a!());

to get the deaired result.

In order to achive this type of thing, one may make a new orchestrator macro which understands what both macros do. However, it may be sometimes a pain to unify different logics into a single piece.

Then, I wondered if it is a practical approach to write the result of macro_a to a file and make macro_b read the content later to reuse it.

I asked a similar question to some open AIs, but they told that this approach is not reliable because macro expansion order may change, and the expansion procedures may be parallelized as well in the future.
However, it seems that proc macros are expanded sequentially from top to bottom in the current system.

I would appreciate any responses!

Don’t do this. Proc macros should not have any side effects.

  • The compiler will be unaware of them and may fail to rebuild things that need to be rebuilt.
  • Future versions of the compiler might sandbox proc macros to increase guaranteed determinism or reduce the risk of malicious code attacking build environments; in this case your code would fail completely.
  • rust-analyzer, today, will run the proc-macro immediately as the user edits code within a macro call. Thus, not only is each macro call expanded as many times as the user presses keys, but they may often be run with incorrect inputs.

“It works today” is not good engineering.

3 Likes

No. For an example where a similar construction breaks, see regression: error[E0277]: the trait bound `Entity: AdapterExt` is not satisfied · Issue #142424 · rust-lang/rust · GitHub

In this case, cargo test --no-run calls rustc twice, concurrently, with the same OUT_DIR.

1 Like

To chain the output of macros, you can do something like:

macro_a!(macro_b);

where macro_a accepts an identifier/path that's a macro's name as input. Then, macro_a would expand to:

macro_b!(123);
1 Like