简体   繁体   中英

How do you refer to functions in a crate from an exported crate macro in rust?

I'm trying to write some debugging helper macros. So I create a crate to hold all of them, and referred to the crate externally using phase(plugin):

#[cfg(test)]
#[phase(plugin)]
extern crate debugging;

That successfully exports the macros into the crate.

However, for some of these tools I wanted to invoke functions from the crate, for example:

#[macro_export]
macro_rules! trace(
  {$($arg:tt)*} => {
    {
      extern crate debug;
      let s = ::macros::logger(); // <---- This!
      let _ = s.write_line(format_args!(::std::fmt::format, $($arg)*).as_slice());
    }
  };
)

Using a global namespace, ie. ::macros::logger works if the macro is placed into macros.rs and imported from the crate root of a crate.

However, what I'm trying to achieve here is the same thing when the macro has to invoke a call from its own crate.

If the macro expanded correctly, I believe:

let s = ::crate_name::logger();

Would be the way to do it, but the crate with the macro cannot refer to itself by name in this way. It generates errors like:

src/macros.rs:52:15: 52:20 error: failed to resolve. Maybe a missing `extern crate debugging`?
src/macros.rs:52       let s = ::debugging::logger();
                               ^~~~~
src/macros.rs:49:1: 56:2 note: in expansion of trace!
src/file.rs:26:11: 26:29 note: expansion site

...and finally just so we're completely clear about what I'm trying to do:

crate debugging:
   lib.rs
     fn logger() 
   macros.rs
     macro_rules! trace(...) // <--- Trying to figure out what to put here...

crate foo:
   lib.rs
     #[phase(plugin)] extern crate debugging;
     fn test_thing() {
       trace!("{}", ...); // <--- So debugging::logger() is invoked here
     } 

So, is there some way to do this from a macro?

For now, the correct thing to do is use an absolute path like that and then do some reexports in the original crate so that path resolves.

Ie in lib.rs put

mod debugging {
    pub use logger;
}

which reexports the top level function logger as debugging::logger . There is work being done that makes this saner, eg $crate which expands to name of the crate from which the macro came (when used externally), or to nothing (when used internally); this isn't necessarily the final design, but it is improving.

For anyone else who finds this, it's worth noting that you cannot use from a crate marked with phase plugin. To import the symbols locally (as per the accepted answer), you need to do this:

#[cfg(test)]
mod debug {
  #[phase(plugin)]
  extern crate debugging;
  extern crate debugging;
  pub use self::debugging::debug;
}

Notice the double extern crate debugging, because typically you wouldn't want to export a syntax extension module as part of the code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM