Your first macro
Let's start from the basics: you'll write a macro that does nothing. It just re-emits the code that's been annotated
with
the macro, unchanged.
This will give you a chance to get familiar with the overall setup before moving on to more complex endeavors.
proc-macro = true
You can't define a procedural macro in a "normal" library crate.
They need to be in a separate crate, with a Cargo.toml
that includes this key:
[lib]
proc-macro = true
That key tells cargo
that this crate contains procedural macros and it should be compiled accordingly.
#[proc_macro_attribute]
There are various kinds of procedural macros:
- Function-like macros. Their invocation looks like a function call (e.g.
println!
). - Derive macros. They're specified inside a
derive
attribute (e.g.#[derive(Debug)]
). - Attribute procedural macros. They're applied to items as attributes (e.g.
#[tokio::test]
).
For a test macro, we need an attribute procedural macro.
As you've learned in the intro, it's a function that's annotated with #[proc_macro_attribute]
:
#![allow(unused)] fn main() { use proc_macro::TokenStream; #[proc_macro_attribute] pub fn my_attribute_macro(args: TokenStream, item: TokenStream) -> TokenStream { // [...] } }
The proc_macro
crate is distributed as part of the Rust toolchain, just like the standard library, std
.
Exercise
The exercise for this section is located in 08_macros/01_no_op_macro