Alternative approach as of 1.32.0
(2018 edition)
Note that while the instructions from @lukas-kalbertodt are still up to date and work well, the idea of having to remember special namespacing rules for macros can be annoying for some people.
On the 2018 edition and onwards, since the version 1.32.0
of Rust, there is another approach which works as well, and which has the benefit, imho, of making it easier to teach (e.g., it renders #[macro_use]
obsolete). The key idea is the following:
A re-exported macro behaves as any other item (function, type, constant, etc.): it is namespaced within the module where the re-export occurs.
Example
macro_rules! macro_name { ... }
pub(crate) use macro_name; // Now classic paths Just Work™
And that's it. Quite simple, huh?
Feel free to keep reading, but only if you are not scared of information overload ;) I'll try to detail why, how and when exactly does this work.
More detailed explanation
In order to re-export (pub(...) use ...
) a macro, we need to refer to it! That's where the rules from the original answer are useful: a macro can always be named within the very module where the macro definition occurs, but only after that definition.
macro_rules! my_macro { ... }
my_macro!(...); // OK
// Not OK
my_macro!(...); /* Error, no `my_macro` in scope! */
macro_rules! my_macro { ... }
Based on that, we can re-export a macro after the definition; the re-exported name, then, in and of itself, is location agnostic, as all the other global items in Rust
In the same fashion that we can do:
struct Foo {}
fn main() {
let _: Foo;
}
We can also do:
fn main() {
let _: A;
}
struct Foo {}
use Foo as A;
The same applies to other items, such as functions, but also to macros!
fn main() {
a!();
}
macro_rules! foo { ... } // foo is only nameable *from now on*
use foo as a; // but `a` is now visible all around the module scope!
And it turns out that we can write use foo as foo;
, or the common use foo;
shorthand, and it still works.
The only question remaining is: pub(crate)
or pub
?
For #[macro_export]
-ed macros, you can use whatever privacy you want; usually pub
.
For the other macro_rules!
macros, you cannot go above pub(crate)
.
Detailed examples
For a non-#[macro_export]
ed macro
mod foo {
use super::example::my_macro;
my_macro!(...); // OK
}
mod example {
macro_rules! my_macro { ... }
pub(crate) use my_macro;
}
example::my_macro!(...); // OK
For a #[macro_export]
-ed macro
Applying #[macro_export]
on a macro definition makes it visible after the very module where it is defined (so as to be consistent with the behavior of non-#[macro_export]
ed macros), but it also puts the macro at the root of the crate (where the macro is defined), in an absolute path fashion.
This means that a pub use macro_name;
right after the macro definition, or a pub use crate::macro_name;
in any module of that crate will work.
- Note: in order for the re-export not to collide with the "exported at the root of the crate" mechanic, it cannot be done at the root of the crate itself.
pub mod example {
#[macro_export] // macro nameable at `crate::my_macro`
macro_rules! my_macro { ... }
pub use my_macro; // macro nameable at `crate::example::my_macro`
}
pub mod foo {
pub use crate::my_macro; // macro nameable at `crate::foo::my_macro`
}
When using the pub / pub(crate) use macro_name;
, be aware that given how namespaces work in Rust, you may also be re-exporting constants / functions or types / modules. This also causes problems with globally available macros such as #[test]
, #[allow(...)]
, #[warn(...)]
, etc.
In order to solve these issues, remember you can rename an item when re-exporting it:
macro_rules! __test__ { ... }
pub(crate) use __test__ as test; // OK
macro_rules! __warn__ { ... }
pub(crate) use __warn__ as warn; // OK
Also, some false positive lints may fire: