include_proc_macro
A convenient macro for working with multiple procedural macros in one crate, and to import them from any arbitrary paths. Reduces boilerplate and repetition, and improves readability.
Usage
The
include_proc_macro
crate provides utilities that make working with procedural macros simpler and more convenient. It offers a simple, comparatively pretty syntax for defining multiples of function-like macros, attribute macros, and derive macros, in a single crate, along with flexible options for importing their implementations.
Important changes in 2.0.6
Version 2.0.6 introduces several new syntax options to give you more control over how modules are handled:
- The
use
keyword tells the macro that you've already imported or defined the module, so it should just use it without redeclaring it - The explicit
mod
keyword makes it clear that this line declares the module (default behavior, but now can be explicit) - When no keyword is present,
mod
is implicitly used (maintaining backward compatibility)
macros!;
Previous version notes
Version 2.0.0 completely overhauls the api and the way the macros are used:
// old:
include_proc_macro!;
// this would often cause name clashes, competing implementations
// and other issues, and was fairly unusable/unneeded outside of very niche applications.
// it was also only for including external macros from arbitrary paths,
// which still resulted in you having to be verbose or otherwise tricky with other macros
// in the crate's module tree
For better readability, increased control, and making use of different types of proc macros in a single crate easier, the syntax evolved thus:
// new:
macros!;
// now we hide implementation details within modules, and delegate to them
// within the crate root. should be fairly clash-free, and handles
// pretty much all the macros you'd want in a single proc-macro crate
Example
use macros;
// we can define multiple macros in a single go, separated by commas
macros!;
Though it doesn't look like much, this would save you a lot of boilerplate, though the average case would likely not have so many macros defined in a single crate. But hey, you can do it if you want to, and now it won't look like a mess.
Comparison
This is short and sweet bit is what we can have, if we use this crate:
macros!;
Otherwise it could look something like this:
use already_imported;
use imported_derive_mod;
In practice
This crate reduces the boilerplate needed when working with procedural macros, especially if there are many of them in a large codebase.
Instead of writing out each proc macro definition by explicitly delegating to its implementation, in the crate root, repetitively, with all the proper attributes and function signatures, you can instead just use the
macros!
syntax to define them all without thinking about the boilerplate.
Also, the ability to fairly cleanly import implementations from external files can be useful for some use cases, such as when you want to keep your macro implementations separate from the main codebase, for whatever reason, have procedural macro tests and want to organize them better, or something wild like allow for external proc macro injection.
The problem
Rust's procedural macro system requires all procedural macros to be defined at the crate root. This can lead to a gigantic, hard-to-navigate root module, and even if avoiding that some way, e.g by separating impls from the macro declarations like this crate does under-the-hood, it's all still very verbose and repetitive to write. It's a little bit tedious to organize larger proc macro codebases with multiple kinds of macro implementations, if you want to keep them in the same crate.
This crate solves these problems by:
- Providing a concise, declarative syntax for defining all types of procedural macros
- Supporting imports from various module paths and even external files
- Allowing for custom naming of macros separate from their implementation
- Enabling batch definitions for much prettier and more readable root module
This is all done via the macro, at compile time, so there are no runtime overhead or other similar implications to consider. The compilation time is slightly increased (due to this dependency), but this is of course only for your proc macro crate, and not for the actual code that uses the macros. For most use cases, you won't notice any side effects.
Support
Whether you use this project, have learned something from it, or just like it, please consider supporting it by buying me a coffee, so I can dedicate more time on open-source projects like this :)
License
You can check out the full license here
This project is licensed under the terms of the MIT license.