$crate refers to crate name defining the decl macro. The equivalent of $crate in proc macro is simply the absolute crate name path.
If you write the absolute path, the obvious error the caller may run into is the crate is not in the caller's scope. When the macro is reexported in another crate, no matter for the decl or proc macro, you won't solve the problem until the crate is usable in scope.
Got it. But another question, a procedural macro cannot be used in the crate(or the crate first export it) where it itself is, since the absolute path is not recognized. It must use the keyword crate instead of using the crate name. Is that designed to be?
Calling this function is ok in crates outside. But if in my_crate, where ths macro itself is, will doesn't work. Because the compiler doesn't resolve path ::my_crate. The compiler will says cannot find crate ``my_crate`` in the list of imported crates
Compiling hello v0.1.0 (D:\FancyFlame\hello)
error[E0433]: failed to resolve: could not find `hello` in the list of imported crates
6 | ::hello::func_a()
| ^^^^^ could not find `hello` in the list of imported crates
11 | call_a!(); // Error!
| --------- in this macro invocation
= note: this error originates in the macro `call_a` (in Nightly builds, run with -Z macro-backtrace for more info)
For more information about this error, try `rustc --explain E0433`.
error: could not compile `hello` due to previous error
I don't think #[derive(Serialize)] is used in serde crate defining the Serialize trait. So the macro just needs to write the absolute path. If I'm wrong, feel free to correct me.
A simple way is to write impl #impl_gen Trait for #ident #type_gen, the downside is everytime the caller must import Trait to scope. I've seen some custom derive macros use this.
Another way is: you could expose two separate macros, one for users and reexport it, the other for yourself and don't reexport it.
The third way is to leave some tokens that only serves you. When parsing, the additonal tokens used in your defining crate leads to the crate:: expansion, otherwise, absolute path tokens are expanded.
The recommened way: write impl #impl_gen ::my_crate::Trait for #ident #type_gen, and in the root of crate defining Trait, i.e. my_crate/src/lib.rs, write extern crate self as my_crate;. Now your macro works for all cases.
I didn't mean to use a procedural macro in the crate where it is, which marked proc-macro = true. They are two crates, one containing derive macros that deriving from trait defining in that crate which is not marked proc-macro = true. And that crate exporting those derive macros and other items. Should I not apply derive macros to items defined in that not-proc-macro crate?
You should. This is a very common pattern, see i.e. serde and serde-derive. But instead of $crate, which is meaningless in your procedural macro, use the name of the crate that exposes your traits directly. Say you have my-crate (containing the traits you want to derive) and my-crate-derive (containing the derive macros), use my_crate::MyTrait in your procedural macros.
If you are worried about people aliasingmy-crate, you can add an attribute where people can override the location of my-crate, see serde's #[serde(crate = "...")] attribute. But I wouldn't worry too much about this, unless someone raises an issue in your repository requesting this feature.
In that case, you would just write out the full path literally. If you have a crate foo and foo-macros, and foo-macros generates code that refers to traits in foo, then the generated code should refer to those traits (and all other items) using their fully-qualified path, foo::module::Trait, foo::helper_function(), etc.
But the question is back to that mentioned before: if the macro writes impl my_crate::Trait for ... while I'm implementing Trait for a struct defined in my-crate, the compiler doesn't know what my_crate refers to. If I modify the macro to impl crate::Trait for ..., then the outer crate cannot use it.
I think it'll be better if rustc recognize the crate name like my_crate as crate keyword. I can't think of anything wrong it will cause.
And I think I can add use crate as my_crate;, so my_crate::Trait will be recognized in my_crate.
Ah, I see. Yes, a workaround like use crate as my_crate; would work. Or you could use an attribute, like I suggested. For example:
#[derive_foo(crate = "crate")]
I assume this has something to do with extern crate, which you had to call in Rust 2015 explicitly in order to import crates. Since your current crate is not really an external crate, there is no implicit extern crate self as my_crate; in your prelude, I'd say. Therefore you can't refer to your current crate by its crate name per default and have to do something like use crate as my crate; or extern crate self as my_crate; in your crate's root module . extern crate is still the way to import crates, but it is now done implicitly, see this answer: