@Davidliudonghao you cannot define #[proc_macro…]
functions outside the root file of the proc-macro = true
crate (usually lib.rs
).
You have two options:
-
the most common and cleanest one, is to define the functions at the top-level file (
lib.rs
) by delegating to a call to the function with the meat of the logic://! `src/lib.rs` use ::proc_macro::TokenStream; #[proc_macro_attribute] pub fn foo (attrs: TokenStream, input: TokenStream) -> TokenStream { my_module::foo(attrs.into(), input.into()) .unwrap_or_else(|err| err.to_compile_error()) .into() } … mod my_module;
//! `src/my_module.rs` or `src/my_module/mod.rs` #![allow(unused_imports)] use ::proc_macro2::TokenStream /* as TokenStream2 */; use ::quote::{format_ident, quote, quote_spanned, ToTokens}; use ::syn::{*, parse::{self, Parse, ParseStream, Parser}, punctuated::Punctuated, Result, // explicitly shadow Result }; pub fn foo (attrs: TokenStream, input: TokenStream) -> Result<TokenStream> { let _: parse::Nothing = parse2(attrs)?; // notice how we get to use `?` in the function's body 👌 let fun: ItemFn = parse2(input)?; … Ok(quote!( … )) }
-
The other option is to use
include!("my_module.rs")
instead ofmod my_module;
, although this has the drawback of flattening all your crate namespacing, possibly leading to clashes. This allows you to write#[proc_macro…]
functions inside theinclude!
d files.
Regarding the first option, if you have many such proc-macros, you can define a helper macro_rules!
to wrap the stuff for you:
macro_rules! reexport_proc_macro_attribute {
(
pub use $module:ident :: {
$(
$( #[doc = $doc:expr] )*
$fname:ident
),+ $(,)?
};
) => (
$(
$( #[doc = $doc] )*
#[proc_macro_attribute] pub
fn $fname (
attrs: ::proc_macro::TokenStream,
input: ::proc_macro::TokenStream,
) -> ::proc_macro::TokenStream
{
$module::$fname(attrs.into(), input.into())
.unwrap_or_else(|err| err.to_compile_error())
.into()
}
)*
);
(
$( #[doc = $doc:expr] )*
pub use $module_name:ident :: $fname:ident;
) => (
reexport_proc_macro_attribute! {
pub use $module_name::{ $( #[doc = $doc] )* $fname };
}
);
}
- (and so on for
proc_macro_derive
andproc_macro
)
That way you can write:
mod my_module;
reexport_proc_macro_attribute! {
pub use my_module::{
/// This is a very nice proc-macro that does …
foo,
};
}