Re-exporting #[macro_export]ed macros by module where they are defined

I'm trying to understand best practices regarding publicly accessible macros. Consider I have a crate a with this module:

pub mod some_module {
    #[macro_export]
    macro_rules! some_macro {
        {} => { println!("Hello!"); }
    }
}

Then that crate will export the macro as a::some_macro.

If I now have a crate b, which does:

use a::some_module::*;

fn main() {
    some_macro!();
}

Then this will fail to compile:

error: cannot find macro `some_macro` in this scope
 --> src/main.rs:4:5
  |
4 |     some_macro!();
  |     ^^^^^^^^^^
  |
  = note: consider importing this macro:
          a::some_macro

I can fix this either by importing the macro from the crate-level module (use a::some_macro instead of use a::some_module::*), or I can modify crate a as follows:

 pub mod some_module {
     #[macro_export]
     macro_rules! some_macro {
         {} => { println!("Hello!"); }
     }
+    pub use crate::some_macro;
 }

Thus, it's possible to export the macro as a::some_module::some_macro in addition to the crate-level export.

My question: Is it reasonable to re-export macros where they are defined? For example, this would allow users of the crate to import all items from a submodule (including macros) when doing use a::some_module::*;.

I have seen that std also has some macros that aren't at the crate-level, e.g. std::ptr::addr_of. In that case, the macro doesn't even exist at the root-level (Playground).

I would like to understand better when and where to export macros, and how to achieve it. What's the usual practice; and does std something magic that ordinary crates cannot or should not do?

P.S.: I have a use-case where I re-export a macro in a prelude module: radiorust::prelude. Is this idiomatic?

Another possibility:

crate a:

pub mod english {
    #[macro_export]
    macro_rules! __english__foo {
        {} => { println!("Hello!"); }
    }
    pub use crate::__english__foo as foo;
}

pub mod chinese {
    #[macro_export]
    macro_rules! __chinese__foo {
        {} => { println!("你好!"); }
    }
    pub use crate::__chinese__foo as foo;
}

crate b:

use a::english::*;
// or:
//use a::chinese::*;

fn main() {
    foo!();
}

I think there was a change in macro exporting a while ago that now allows a simple public re-use line to make it work:

pub mod some_module {
    #[macro_export]
    macro_rules! some_macro {
        {} => { println!("Hello!"); }
    }

    pub use some_macro;
}

[playground]

Oh, I didn't know it worked. I found this post by @Yandros, but thought it was limited to pub(crate), but apparently it works across crate boundaries too.

Ah yeah, my post might have been a bit fuzzy on this topic.

The idea is that it also works with #[macro_export], as in, you'll successfully have a "copy" of the exported macro in your desired location, but due to #[macro_export] you'll also have the macro be accessible at the root of the crate.

Sadly, #[doc(hidden)] on the latter will also hide the correctly-scoped macro (since #[doc(inline)] is currently unable to remove the doc(hidden)s on the original item, which I personally deem to be a bug).

Thence the need for hacks such as:

to palliate that :pensive:

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.