I'm writing an app that lets you make osx Dock applets from Rust. I have defined a macro in a library that abstracts a bunch of objective-c boilerplate setup. The macro works, but when I use it, all the various objective-c types it uses get "pulled in" to the call site, which means that site needs to import many of the same modules or else it fails to compile.
Which requires a bunch of objective c imports in that file, so that the macro, defined here, compiles.
(Note I couldn't include a preview link because, as a new user, I have a 2 link quota) macro definition
It makes sense to me why this would occur, since its just expanding the macro at the call site. Is there a way to prevent it? It seems like I might be able to use $crate in the macro definition in some way, but so far my efforts have failed. I have studied the Book and serde (which uses a lot of macros) but haven't seen an example of how to resolve this.
Thanks for replying. Using the fully qualified path, or $crate, does seem to help with some types.
It doesn't seem to help with traits though, for instance objc_foundation::object::INSObject
is a Trait, but in the sample app I get
src/main.rs:49:5: 62:23 note: in this expansion of add_fly_item! (defined in <barfly macros>)
<barfly macros>:7:42: 7:54 help: items from traits can only be used if the trait is in scope; the following trait is implemented but not in scope, perhaps add a `use` for it:
<barfly macros>:7:42: 7:54 help: candidate #1: use `objc_foundation::object::INSObject`
even with either one of these in the library macro: ::objc_foundation::object::INSObject
or $crate::INSObject
The lib compiles successfully even though the sample app fails.
Also, is there a fully qualified syntax for macros? The library is using some objc macros that I also don't want to creep into the sample app. I tried ::msg_send! in the library, and that works there, but when I remove the associated crate from the sample app, it fails to build with error: macro undefined: 'msg_send!'
BTW I found your "Little book of rust macros" and I am reading it now, perhaps I will be enlightened.
Either use uniform function call syntax (UFCS), or use the trait in the expansion:
path::to::Trait::method(&explicit_self)
<path::to:Type as path::to::Trait>::method(&explicit_self)
use path::to::Trait;
explicit_self.method()
As for macros, there is no qualification syntax for those. They have one name, and that name cannot be qualified. You can keep a macro private by not flagging it with #[macro_export].
Thanks. With your advice I was able to eliminate most of the dependencies. The key steps are:
use $crate (and therefore pub use for external types) in the library to prevent type leakage. Using :: syntax in the macro appears to work at first, but then you can't remove the extern crate references from the call site.
use UFCS (especially the angle-bracket variant) type deal with Traits in the macro.
Its too bad that macros can't be qualified. I have a lingering dependency on objc in the main program that I can't eliminate because my macros use sel! and msg_send! from that crate. It looks like I'm going to need to replicate (i.e. copy-paste) those macros into my code to make it work. Perhaps the upcoming revision to to the macro system will improve this...
BTW, your book on Rust macros is very informative.