Search code examples
rustmacros

How to call functions hygenically from macros in Rust?


I have a macro in some module that calls a function:

mod a {
  mod b {
    fn foo(_: u32) {}

    macro_rules! bar {
      ( $x:expr ) => (foo($x))
    }
  }
}

This does not work from outside module a::b unless I import foo. Explicitly naming the module works in this case:

macro_rules! bar {
  ( $x:expr ) => (crate::a::b::foo($x))
}

However, this wouldn't work from outside the crate for an exported macro. I tried the following but it didn't work either:

#[macro_export]
macro_rules! bar {
  ( $x:expr ) => (::mycratename::a::b::foo($x))
}

Where mycratename is the name of the library in Cargo.toml.

[lib]
name = "mycratename"
crate-type = ["lib", "cdylib", "staticlib"]

At least it doesn't work when I try to use the macro from within the crate, I didn't try using it from outside. Is there a way to make it work from both within and outside the crate?


Solution

  • This is exactly what the reserved $crate meta variable is for.

    It expands to crate within the defining crate and to ::crate_name outside of it.


    Note: It still expands to the regular ::crate_name even if you rename the crate on import, but it'll still correctly resolve the crate, though manually replacing the macro invocation with the expanded version will fail in this case.