How do I use a macro across module files?

谁说我不能喝 提交于 2021-01-29 08:37:40

问题


I have two modules in separate files within the same crate, where the crate has macro_rules enabled. I want to use the macros defined in one module in another module.

// macros.rs
#[macro_export] // or not? is ineffectual for this, afaik
macro_rules! my_macro(...)

// something.rs
use macros;
// use macros::my_macro; <-- unresolved import (for obvious reasons)
my_macro!() // <-- how?

I currently hit the compiler error "macro undefined: 'my_macro'"... which makes sense; the macro system runs before the module system. How do I work around that?


回答1:


Macros within the same crate

#[macro_use]
mod foo {
    macro_rules! bar {
        () => ()
    }
}

bar!();    // works

If you want to use the macro in the same crate, the module your macro is defined in needs the attribute #[macro_use].

Macros can only be used after they have been defined. This means that this does not work:

bar!();  // ERROR: cannot find macro `bar!` in this scope

#[macro_use]
mod foo {
    macro_rules! bar {
        () => ()
    }
}

Macros across crates

To use your macro_rules! macro from other crates, the macro itself needs the attribute #[macro_export]. The importing crate can then import the macro via use crate_name::macro_name;.

Crate util

#[macro_export]
macro_rules! foo {
    () => ()
}

Crate user

use util::foo;

foo!();

Note that macros always live at the top-level of a crate; so even if foo would be inside a mod bar {}, the user crate would still have to write use util::foo; and not use util::bar::foo;.

Before Rust 2018, you had to import macro from other crates by adding the attribute #[macro_use] to the extern crate util; statement. That would import all macros from util. Alternatively, #[macro_use(cat, dog)] could be used to only import the macros cat and dog. This syntax should not be necessary anymore.

More information is available in The Rust Programming Language chapter on macros.




回答2:


This answer is outdated as of Rust 1.1.0-stable.


You need to add #![macro_escape] at the top of macros.rs and include it using mod macros; as mentioned in the Macros Guide.

$ cat macros.rs
#![macro_escape]

#[macro_export]
macro_rules! my_macro {
    () => { println!("hi"); }
}

$ cat something.rs
#![feature(macro_rules)]
mod macros;

fn main() {
    my_macro!();
}

$ rustc something.rs
$ ./something
hi

For future reference,

$ rustc -v
rustc 0.13.0-dev (2790505c1 2014-11-03 14:17:26 +0000)



回答3:


Adding #![macro_use] to the top of your file containing macros will cause all macros to be pulled into main.rs.

For example, let's assume this file is called node.rs:

#![macro_use]

macro_rules! test {
    () => { println!("Nuts"); }
}

macro_rules! best {
    () => { println!("Run"); }
}

pub fn fun_times() {
    println!("Is it really?");
}

Your main.rs would look sometime like the following:

mod node;  //We're using node.rs
mod toad;  //Also using toad.rs

fn main() {
    test!();
    best!();
    toad::a_thing();
}

Finally let's say you have a file called toad.rs that also requires these macros:

use node; //Notice this is 'use' not 'mod'

pub fn a_thing() {
  test!();

  node::fun_times();
}

Notice that once files are pulled into main.rs with mod, the rest of your files have access to them through the use keyword.




回答4:


I have came across the same problem in Rust 1.44.1, and this solution works for later versions (known working for Rust 1.7).

Say you have a new project as:

src/
    main.rs
    memory.rs
    chunk.rs

In main.rs, you need to annotate that you are importing macros from the source, otherwise, it will not do for you.

#[macro_use]
mod memory;
mod chunk;

fn main() {
    println!("Hello, world!");
}

So in memory.rs you can define the macros, and you don't need annotations:

macro_rules! grow_capacity {
    ( $x:expr ) => {
        {
            if $x < 8 { 8 } else { $x * 2 }
        }
    };
}

Finally you can use it in chunk.rs, and you don't need to include the macro here, because it's done in main.rs:

grow_capacity!(8);

The upvoted answer caused confusion for me, with this doc by example, it would be helpful too.



来源:https://stackoverflow.com/questions/63233545/how-do-i-use-rust-macros-in-the-same-crate

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!