Exporting Macros
By default, a macro_rules! macro is private to the module in which it is defined and is only visible to code that appears textually after its definition. Rust provides two mechanisms for sharing macros across modules and crates: #[macro_export] (for crate-root and external crate exports) and path-based pub(crate) use / pub use re-exports.
1. Exporting Across Crates with #[macro_export] and $crate
Annotating a macro_rules! definition with #[macro_export] places the macro at the root namespace of your crate (my_crate::my_macro!) and makes it publicly importable by downstream crates via use my_crate::my_macro;.
When an exported macro references helper functions, types, or other macros defined inside your own crate, always prefix those paths with $crate:: so the macro resolves them inside your crate regardless of what modules the caller has imported:
pub mod internal {
pub fn format_tag(tag: &str, msg: &str) -> String {
format!("[{tag}] {msg}")
}
}
#[macro_export]
macro_rules! log_info {
($msg:expr) => {
// `$crate::` always resolves to the root of the crate defining `log_info!`:
println!("{}", $crate::internal::format_tag("INFO", $msg))
};
}
fn main() {
log_info!("Server listening on 127.0.0.1:8080");
}
[INFO] Server listening on 127.0.0.1:8080
2. Module-Scoped Macros with pub(crate) use
Unlike functions and structs, you cannot write pub macro_rules! foo directly. Instead, define the macro_rules! foo inside a module and immediately re-export it with pub(crate) use foo; (or pub use foo;). This makes the macro work like any other module item (my_mod::foo!()) without polluting the crate root or requiring textual #[macro_use] ordering:
mod assertions {
macro_rules! assert_approx_eq {
($a:expr, $b:expr, $eps:expr) => {{
let diff = ($a - $b).abs();
assert!(
diff <= $eps,
"assertion failed: |{} - {}| = {} > {}",
$a,
$b,
diff,
$eps
);
}};
}
// Re-export the macro as a normal module item:
pub(crate) use assert_approx_eq;
}
fn main() {
assertions::assert_approx_eq!(0.1_f64 + 0.2_f64, 0.3_f64, 1e-12);
println!("Approximate equality verified!");
}
Approximate equality verified!
Comparing Macro Visibility Mechanisms
| Mechanism | Where the Macro Lives | Visible to External Crates? | Requires Textual Top-to-Bottom Order? |
|---|---|---|---|
Bare macro_rules! m |
Current module only | No | Yes (only visible after definition) |
pub(crate) use m; after macro_rules! m |
Module namespace (mod_name::m!) |
No (or Yes with pub use + #[macro_export]) |
No (works anywhere via path import) |
#[macro_export] macro_rules! m |
Crate root (crate::m!) |
Yes | No |