29

I was trying to create a derive macro for my trait, to simplify some stuff.

I've encountered some problems:

the #[proc_macro_derive] attribute is only usable with crates of the proc-macro crate type

and, after the small fix proc-macro=true:

proc-macro crate types cannot export any items other than functions tagged with #[proc_macro_derive] currently functions tagged with #[proc_macro_derive] must currently reside in the root of the crate`

What is the reason for this behavior?

vallentin
  • 23,478
  • 6
  • 59
  • 81
majkrzak
  • 1,332
  • 3
  • 14
  • 30

1 Answers1

41

Procedural macros are fundamentally different from normal dependencies in your code. A normal library is just linked into your code, but a procedural macro is actually a compiler plugin.

Consider the case of cross-compiling: you are working on a Linux machine, but building a WASM project.

  • A normal crate will be cross-compiled, generate WASM code and linked with the rest of the crates.
  • A proc-macro crate must be compiled natively, in this case to Linux code, linked with the current compiler runtime (stable, beta, nightly) and be loaded by the compiler itself when compiling the crates where it is actually used. It will not be linked to the rest of the crates (different architecture!).

And since the compilation flow is different, the crate type must also be different, that is why the proc_macro=true is needed.

About this restriction:

proc-macro crate types cannot export any items other than functions tagged with #[proc_macro_derive]

Well, since the proc-macro crate is loaded by the compiler, not linked to the rest of your crates, any non-proc-macro code you export from this crate would be useless.

Note that the error message is inexact, as you can also export functions tagget with #[proc_macro].

And about this other restriction:

functions tagged with #[proc_macro_derive] must currently reside in the root of the crate

Adding proc_macro or proc_macro_derive items in nested modules is not currently supported, and does not seem to be particularly useful, IMHO.

rodrigo
  • 94,151
  • 12
  • 143
  • 190
  • 2
    The book mentions: "At the moment, procedural macros need to be in their own crate. *Eventually, this restriction may be lifted*, but for now, it's required." I think, in the future, the compiler might automatically separate the proc-macro code (from the other library code) and compile it in that special way. Hopefully that will be implemented soon. Nice answer! – Lukas Kalbertodt Jun 22 '19 at 09:27
  • That is why i though. Abut splitng macros in multiple fileds it might be usefulll if you dont like over 9000 lines long files in your project. But it seems to be a genereal rust issue that you preffer to put everything in a siungle fille – majkrzak Jun 22 '19 at 10:39
  • 7
    @majkrzak: About the 9000-line file, that is not actually necessary. You can write any number of private modules, submodules (in separated files) and private functions in your proc-macro crate. You are just prevented from making them public. – rodrigo Jun 22 '19 at 10:52
  • 1
    Hello, 2023 here... Any update on this? Do we still need to use a separate crate? – Mikael Lindqvist Apr 15 '23 at 04:52
  • @MikaelLindqvist: I haven't seen any movement towards removing the need of proc-macro crates, I guess that the same restrictions and rationale still apply. What has changed is the cargo [feature resolver algorithm](https://doc.rust-lang.org/cargo/reference/resolver.html#feature-resolver-version-2) to make the proc-macro crate dependencies decoupled from the regular ones, making separate crates more flexible. – rodrigo Apr 15 '23 at 09:40
  • Any reason why the answer only mentions `proc_macro` and `proc_macro_derive` items, and omits the third type proc macro, i.e., `proc_macro_attribute`. Are attribute proc macros special in this regard, or was it just a coincidence not mentioning them? I'd assume the limitation applies to them as well, because they aren't conceptually different? – bluenote10 May 01 '23 at 08:10
  • @bluenote10: No reason, you are right that all procedural macros are conceptually the same. This answer is from 2019, maybe `proc_macro_attribute` was not yet stable (I skimmed through the changelog but unconclusively). Or maybe I wasn't even aware that they existed? – rodrigo May 02 '23 at 12:32