Search code examples
rustrust-cargo

Re-exporting proc macro results in "unresolved extern crate" error


I'm trying to re-export the html macro from Maud but am getting an "unresolved extern crate" whenever I try to use the re-exported macro.

How can I re-export this macro from my own crate?

Setup

I'm using a Cargo workspace. I'm re-exporting the macro from crate a and am trying to use it in crate b.

Code

I have omitted lines that I believe are irrelevant. Comment if there's details missing and I'll add them.

Workspace

# Cargo.toml

[workspace]

members = ["a", "b"]
resolver = "2"

[workspace.dependencies]
a = { path = "a" }
maud = "0.26.0"

Crate a

# a/Cargo.toml

[package]
name = "a"

[dependencies]
maud.workspace = true
// a/src/lib.rs

pub use maud::html;

Crate b

# b/Cargo.toml

[package]
name = "b"

[dependencies]
a.workspace = true
// b/src/lib.rs

use a::html;

fn test() {
    let markup = html!{ "hello" };
              // ^^^^^^^^^^^^^^^^
              // unresolved extern crate
              // can't find crate for `maud`
}

Solution

  • The maud::html macro just emits ::maud in its token output, so there isn't really anything you can do about it except asking your users to import maud as well, unless you want to write your own wrapper that accepts a customized crate name.

    This issue was better solved in decl macros using $crate, so if you can modify the maud proc macro code, you may want to add a decl macro like this:

    // maud/src/lib.rs
    macro_rules! html {
        ($($tt:tt)*) => { $crate::maud_macros::html! {
            {$crate}
            $($tt)*
        }
    }
    

    and modify the proc macro code to read the leading {$crate} token tree.

    But otherwise you can't really fix this without asking users to import maud in all crates.