How to import/use macro from different module in the same crate?
Asked Answered
S

1

6
Real life scenario:

I wanted to use crate::app::verbose_trace!("string literal") inside crate::app::args::parse module.

Reproducable scenario:

After an hour of attempts, I came with following simple example. It exposes my misunderstanding of macros.

  #[macro_use]
  mod foo{
      pub fn bar(){
          println!("bar works")
      }
      #[macro_export]
      macro_rules! baz{
          ()=> {println!("baz works")}
      }
  }

  fn main(){
      foo::bar();
      foo::baz!();
      // Following doesn't work either:
      // use foo::baz;
      // baz!();
  }

Compiler complains

  error[E0433]: failed to resolve: could not find `baz` in `foo`
  --> src\main.rs:14:14
  |
  14 |         foo::baz!();
  |              ^^^ could not find `baz` in `foo`

as if it was utterly blind :0

I read:
I would like to see:
  • A compilable version of my example.
  • Explanations why it did failed to compile.
  • Optionally:
    • Some other suggestions how to use marco in submodule/supermodule.
Spacious answered 26/11, 2022 at 22:47 Comment(0)
G
14

#[macro_export] exports the macro under the crate root. Thus, crate::baz!() will work, but foo::baz!() won't (and you don't need #[macro_use], it is for using the macro in another crates).

If you want to export the macro in this path, for crate local macros don't use #[macro_export] as all. Instead, export the macro like:

macro_rules! baz {
    () => {
        println!("baz works")
    };
}
pub(crate) use baz;

For exporting the macro for use in other crates you still need #[macro_export]:

#[macro_export]
macro_rules! baz {
    () => {
        println!("baz works")
    };
}
pub use baz;

This will export the macro both under the crate root and under foo.

Gitt answered 26/11, 2022 at 22:52 Comment(3)
is there a way to avoid exporting from the crate root but export from the current module in a way that other crates can use? I have a secenario where exporting at the crate root will cause conflicts between several modulesCher
@SamJohnson Not with macro_rules, unfortunately (only with macros 2.0). But you can use a trick: export a macro with #[doc(hidden)] mangled name (e.g. module__macro), then reexport it with public name from the module.Gitt
@SamJohnson E.g. #[macro_export] #[doc(hidden)] macro_rules! foo__bar { ... } pub use foo_bar as bar;.Gitt

© 2022 - 2024 — McMap. All rights reserved.