Cannot use macros imported in a library in an exec

2019-09-18 18:38发布

问题:

I'm having a lot of trouble getting macros from another crate to work in Rust. My lib.rs file looks like this:

#[macro_use]
extern crate session_types;

mod main;

And here's a simplified part of my main.rs, demonstrating proper use of the offer! macro:

use session_types::*;

type Server = Offer<Choose<Var<Z>, Var<Z>>, Choose<Var<Z>, Var<Z>>>;

struct Foo;

impl Foo {
    fn server(&self, c: Chan<(), Rec<Server>>) {
        let mut c = c.enter();
        loop {
            c = offer!{ c,
                LEFT_BRANCH => c.sel1().zero(),
                RIGHT_BRANCH => c.sel2().zero()
            };
        }
    }
}

I know the compiler is able to expand offer! because I've debugged code in blocks inside that macro, and I get warnings about unused variables in that macro which look like this:

<session_types macros>:1:1: 5:16 note: in expansion of offer!
src/main.rs:107:21: 133:14 note: expansion site
<session_types macros>:3:53: 3:57: warning: unused variable: 'right', #[warn(unused_variables)] on by default
<session_types macros>:3 Branch:: Left ( $id ) => $code, Branch:: Right ( $id ) => offer! {

which obviously includes part of the macro. However, I get compilation errors saying that, on the lines they're used, the macro offer! is undefined.

src/main.rs:107:21: 133:14 note: in this expansion of offer! (defined in <session_types macros>)
src/main.rs:57:17: 57:22 error: macro undefined: 'offer!'
src/main.rs:57             c = offer!{ c,
                               ^~~~~
src/main.rs:107:21: 107:26 error: macro undefined: 'offer!'
src/main.rs:107             night = offer!{ night,

Note: this occurs on the nightly branch of the compiler.

回答1:

This example reproduces your problem:

Cargo.toml

[package]
name = "mac"
version = "0.1.0"
authors = ["An Devloper <an.devloper@example.com>"]

[dependencies]
lazy_static = "0.1.14"

src/lib.rs

#[macro_use]
extern crate lazy_static;

lazy_static! {
    pub static ref LIBRARY_VERSION: u8 = 1;
}

pub fn adder(a: u8, b: u8) -> u8 { a + b }

src/main.rs

extern crate mac;

lazy_static! {
    static ref EXECUTABLE_VERSION: u8 = 1;
}

fn main() {
    println!("Adder version {} (lib version {})", *EXECUTABLE_VERSION, *mac::LIBRARY_VERSION);
    println!("Result: {}", mac::adder(1, 2));
}

The problem is that macro inclusions are not transitive across crates. Including them in your library file doesn't make them available in any downstream crate that uses your library. That would blow any kind of selective usage completely out of the water; think how many items you would have in a project with 20 dependencies (that each themselves can have dependencies)!

You need to explicitly include the macros in your executable file as well, as it's a different crate:

#[macro_use]
extern crate lazy_static;
// ... rest of above src/main.rs


标签: macros rust