How do I use a macro across module files?
Solution 1
Macros within the same crate
New method (since Rust 1.32, 2019-01-17)
foo::bar!(); // works
mod foo {
macro_rules! bar {
() => ()
}
pub(crate) use bar; // <-- the trick
}
foo::bar!(); // works
With the pub use
, the macro can be used and imported like any other item. And unlike the older method, this does not rely on source code order, so you can use the macro before (source code order) it has been defined.
Old method
bar!(); // Does not work! Relies on source code order!
#[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]
. Note that macros can only be used after they have been defined!
Macros across crates
Crate util
#[macro_export]
macro_rules! foo {
() => ()
}
Crate user
use util::foo;
foo!();
Note that with this method, 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;
. By using pub use
, you can export a macro from a module of your crate (in addition to it being exported at the root).
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
. This syntax should not be necessary anymore.
Solution 2
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.
- EDIT: it turns out their answer has been updated to include my suggestion, with no credit mention whatsoever 😕
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.
-
It can then be referred to with a fully qualified path.
-
It can also be locally
use
d / brought into scope so as to refer to it in an unqualified fashion.
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 commonuse 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; usuallypub
. -
For the other
macro_rules!
macros, you cannot go abovepub(crate)
.
Detailed examples
-
For a non-
#[macro_export]
ed macromod 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 macroApplying
#[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 apub 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:
-
from the trigger-happy
clippy
tool, when this trick is done in any fashion; -
from
rustc
itself, when this is done on amacro_rules!
definition that happens inside a function's body: https://github.com/rust-lang/rust/issues/78894
Solution 3
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)
Solution 4
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.
Solution 5
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.
Note: This solution does work, but do note as @ineiti highlighted in the comments, the order u declare the mod
s in the main.rs/lib.rs
matters, all mod
s declared after the macros mod declaration try to invoke the macro will fail.
user
Updated on July 18, 2022Comments
-
user almost 2 years
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?-
u_mulder over 9 yearsShouldn;'t you use
module::my_macro!()?
-
user over 9 yearsnope (not afaik) - the module prefix is reportedly ignored (according to the compiler message).
-
-
user over 9 yearsI'd totally missed that attribute. Thanks!
-
Vladimir Matveev over 9 yearsBTW,
#[macro_export]
attribute is unnecessary here. It is only needed if the macro should be exported to external crate users. If the macro is only used inside the crate,#[macro_export]
is not needed. -
conradkleinespel about 9 yearsThanks a lot for the answer. I just want to add, that if your
something.rs
file uses other modules, for example withmod foobar;
, and thisfoobar
module uses the macros frommacro.rs
, then you have to putmod macro;
beforemod foobar;
for the program to compile. Minor thing, but this is not an obvious IMO. -
user almost 9 years(n.b. this answer is now outdated; I've accepted the up-to-date answer given by Lukas)
-
neverfox over 6 years"Macros can only be used after they have been defined." - This is key because you can run into that error even when you've done all the other things mentioned correctly. For example, if you have modules
macros
andfoo
(which uses a macro frommacros
), and you list them in alphabetical order in your lib.rs or main.rs, foo will be loaded before macros and the code won't compile. -
Luke Dupin over 6 yearsI added more clarification. As of rustc 1.22.1, this does work.
-
semore_1267 over 5 years^ pro tip - this totally got me
-
Markus over 5 yearsAre you sure? Where is this #![macro_use] (not #[macro_use]) documented? I can't find it. It doesn't work here.
-
Luke Dupin over 5 yearsThis worked when I posted it, Rust's include system is such a awful mess, its entirely possible this doesn't work anymore.
-
user over 5 years@Markus Note that the
#![macro_use]
statement is INSIDE the macro-module, not outside. The#![...]
syntax corresponds to having attributes apply to their containing scopes, e.g.#![feature(...)]
(obviously this wouldn't make sense if written as#[feature(...)]
; it would semantically require that the compiler enable certain features on specific items in a crate, rather than the whole root crate). So, as @LukeDupin said, the module system is a mess, though maybe for a different reason than at first glance. -
user over 5 yearsI do wish that this answer mentioned how the construction isn't exactly idiomatic (that aside, I like the answer). In spite of its (non)-idiomaticity, it's interesting because placing it next to the idiomatic form makes it painfully obvious that macros interact with the module system in a different way than the usual constructions. Or it at least gives off a strong smell (as just demonstrated by @Markus having a gripe with it).
-
Sebastian over 4 yearsThis works because in main.rs the line
mod node;
comes beforemod toad;
. Be careful when usingrustfmt
, as it may re-order these lines lexicographically. For me the fix was to put an empty newline between those lines. -
Lucius Hu over 4 years"Macros can only be used after they have been defined." Thanks!
-
Ten about 4 yearsAlso note that for using macros internally, the
#[macro_use]
attribute should be on every module and parent module, etc.. until it reaches the point where you need to use it. -
cambunctious almost 4 yearsI prefer putting the annotation over the
mod
declaration since it prevents rustfmt from changing the order. -
knh190 over 3 years@Shepmaster the upvoted answer has definition of macros and the import statement at the same place, so it caused confusion (for me). I was using
#[macro_use]
in definition. Compiler doesn't say it is misplaced. -
Sorin Bolos over 3 yearsThis answer did not work for me. The module that declared the macro had
#[macro_use]
and it was declared first in lib.rs - still didn't work. @Ten's answer helped and I added#[macro_use]
to the top of lib.rs - then it worked. But I'm still not sure what the best practice is since i read here that "You don't import macros from other modules; you export the macro from the defining module" -
Prgrm.celeritas over 3 yearsThank you for this answer! I was confused by the accepted answer as well and could not figure it out till I read your explanation.
-
detly over 3 years@Shepmaster There is no mention of how macros work in the section you link to. Did you mean to link to some other part of the book?
-
Shepmaster over 3 years@detly no, because what my comment is pointing out is broader than macros. This answerer seemed confused that
mod { ... }
andmod some_file
are the same thing and both create a module. The accepted answer already shows the usage of#[macro_use]
, so this answer doesn't really provide anything new. -
Hutch Moore over 3 yearsI always forget how Rust's macros work with modules. It's an awful system, and hopefully there'll be a better one someday.
-
ineiti over 3 yearsAlso be sure to have the correct order of
mod
inmain.rs
. If you havemod chunk; mod memory;
, then the macro call inmemory.rs
will fail. -
Aitch over 3 years@Ten 's hint helped me.
#[macro_use]
needs to be added to allmod
statements on the complete path, in order to be usable by parent modules. That's very crazy. Thank you so much! -
cherryblossom about 3 yearsI think this is the only way to use use a local macro from a module that isn’t directly above the module which defines the macro (for example if you had a macro in
a::b
this is the only way to use it in modulec
without#[macro_export]
). This is becausec
can’t declaremod a::b
and#[macro_use]
doesn’t work withuse
statements such asuse super::a::b
. -
Zeyi Fan about 3 yearsOh wow, this answer needs more upvotes. Many thanks!
-
user4815162342 almost 3 yearsA re-exported macro behaves as any other item - Based on this, I'd expect to be able to define a macro in a (public) sub-module of a crate, and refer to it from another crate using full path, i.e. as
some_name::some_module::some_macro!
. But if I definemacro_rules! some_macro { ... }
and thenpub use some_macro;
the compiler tells me thatsome_macro
is private. I can usepub(crate)
as shown in the answer, but then it's private to the crate, and only callable using full path from that crate. Is there a way to call it by full path from another crate? -
Daniel H-M almost 3 years@user4815162342 a re-export cannot provide more visibility than the inherent one of an item. And a non-
#[macro_export]
-ed macro inherent visibility is indeedpub(crate)
at most. You'll thus need to#[macro_export]
your macro, although that will make it appear at the root of the crate too. There is no simple workaround for that "also at the root of the crate" issue, but for doc hacks to hide it, or for using an extra external helper crate just for that (such as inkonst_macro_rules
in crates.io/crates/konst/0.2.4/dependencies) -
user4815162342 almost 3 yearsOk, so I can use
#[macro_export] macro_rules some_macro { ... }
followed bypub use some_macro
, and I'll getsome_macro
both in crate root and the module where I want it. While I'd prefer to have it only in the submodule (because the macro is grouped with types and other stuff from that submodule in a logical whole), this works too. I don't really understand why a macro has to be exported to crate root and why that export cannot be disabled (while still allowing public export in other locations). Do you know the rationale for that design? -
Daniel H-M almost 3 yearsHistorical remains, I'd say: originally macros were not "namespaceable" whatsoever, which kind of worked for a crate-local macro, but a special mechanism had to be designed for cross-crate macros. Given their lack of namespace, cross-crate macros, that is,
#[macro_export]
-ed ones, were thus arbitrarily given the "at the root of the crate" namespace / module location. This wouldn't be a problem if the macro could be#[doc(hidden)]
and then#[doc(inline)] pub use
d, but then a rustdoc bug makesdoc(hidden)
transitive across re-exports 😫 -
Randall Coding almost 3 yearsIt's very counter intuitive. So we define macros in a sub module, but then call it from the root crate? Not great for code organization either.
-
Randall Coding almost 3 yearsFinally. This was the answer I was a looking for. If I define a macro in a module I want it namespaced to that module. This has to be the most confusing and poorly documented feature of rust, macros in general.