I'm working on a relatively simple library that provides a derive macro. As required by the use of proc_macro
, it's split into two crates, which I'll call bibliophile
and bibliophile-macros
for demonstration. The derive macro in bibliophile-macros
, which I'll call ReadingList
, needs to reference traits, structs, and also crate imports of bibliophile
.
The way I have things currently set up is that in the main bibliophile
crate, I re-export the necessary crates in a re_export
module, and then have something like the following derivation macro implementation :
use syn::{parse_macro_input,DeriveInput};
use quote::quote;
#[proc_macro_derive(ReadingListA, attributes(readinglist))]
pub fn derive_entity(tokens: TokenStream) -> TokenStream {
let input = parse_macro_input!(tokens as DeriveInput);
let ident = &input.ident;
quote!{
impl ::bibliophile::TraitA for #ident {
fn a_func(_param: ::bibliophile::re_export::some_crate::SomeType) { }
}
}.into()
}
The problem with this approach is that if I chain the dependencies by implementing an avidreader
library crate that depends on bibliophile
, and then a bookclub
binary crate that depends on avidreader
, using the re-exported bibliophile-macro
derive macro in bookclub
will fail unless the end bookclub
crate also has bibliophile
in its list of imported crates.
This seems like an undesirable property that each library requires its users to also list some of its dependencies (and my modicum of experience with the Rust ecosystem leads me to believe that it's unlikely to actually be the case!), and yet it seems like an unavoidable property of procedural macros given their unhygenic nature.
A quick survey of existing implementations of other libraries has not turned up anything useful yet. Is there a concept or trick that I'm missing?
Thank you!