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
deriveattribute (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