26

I'm sure this is trivial to do, but I can't seem to make it work.

I've looked at http://doc.rust-lang.org/book/advanced-macros.html#scoping-and-macro-import/export, and I appreciate, that in general, the way to use macros is to define them using:

#[macro_export]
macro_rules! background(($token:expr) => (($token >> (32 + 8)) & $crate::graphics::mask::Color));

...and then import them into another context that uses them using:

#[macro_use]
extern crate terminal;
...

However, I what I want to do is use the macros from within the crate where they are defined.

If my file structure is:

- lib.rs
- macros.rs
- foo
- foo/mod.rs
- foo/junk.rs

How do I use the macros in macros.rs from junk.rs?

I've tried various combinations of #[macro_use] mod macros, etc. with no luck. The documentation suggests that if a macro is defined in some scope, then it is available in all child modules... does that mean I have to define my macros in lib.rs?

Doug
  • 32,844
  • 38
  • 166
  • 222

2 Answers2

73

The accepted answer is correct, but for anyone else who finds this question in the future, I'd like to add that the order in which modules are loaded is important.

For example, in this sequence:

pub mod terminal;
pub mod terminals;
pub mod graphics;

#[macro_use]
mod macros;

If terminal uses a macro from macros, it will not work; the #[macro_use] must occur above any other module that uses the macro:

#[macro_use]
mod macros;

pub mod terminal;
pub mod terminals;
pub mod graphics;
Doug
  • 32,844
  • 38
  • 166
  • 222
30

You need to mark your macro with #[macro_export] and then mark the module with #[macro_use]:

#[macro_use]
mod macros {
    #[macro_export]
    macro_rules! my_macro(() => (42));
}

pub mod foo {
    pub mod junk {
        pub fn usage() -> u8 {
            my_macro!()
        }
    }
}

fn main() {
    println!("{:?}", foo::junk::usage());
}

Technically, you only need to use #[macro_export] if you want the macro to be available to users of your crate.

(Playground link)

E_net4
  • 27,810
  • 13
  • 101
  • 139
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • 2
    That works inline, but when I try it using files, it doesn't seem to; have a look at this trivial example https://github.com/shadowmint/rust-starter; it errors with "src/module1/blah.rs:2:15: 2:18 error: macro undefined: 'fmt!'", but https://raw.githubusercontent.com/shadowmint/rust-starter/master/src/lib.rs does exactly what you've said. – Doug Mar 16 '15 at 03:06
  • There's no `mod module1;` in the code you link, maybe the error is coming from something else? – huon Mar 16 '15 at 03:12
  • (See also: http://doc.rust-lang.org/nightly/book/advanced-macros.html#scoping-and-macro-import/export.) – huon Mar 16 '15 at 03:13
  • @huon-dbaupp ah, right you are, it needed to be in main.rs – Doug Mar 16 '15 at 03:16
  • 1
    Might it be worth noting that `mod macros {}` must appear before other `mod` declarations depending on the macros? – E_net4 May 03 '18 at 18:40