Understanding compiler plugins

The Rust nightly compiler accepts loading extensions, called plugins. They effectively change the way the compiler behaves, so they can modify the language itself. A plugin is a crate, similar to the procedural macro crate we created previously.

The difference between a procedural or standard macro and a plugin is that, while the first two modify the Rust code they are given, a plugin is able to perform extra computations that can greatly improve the performance of your crate.

Since these plugins get loaded inside the compiler, they will have access to a lot of information that standard macros don't have. Moreover, this requires using the rustc compiler and the libsyntax library as external crates, which means that you will be loading a lot of the compiler code when compiling the plugin.

Therefore, do not add your plugin as an external crate to your binaries as it will create a huge executable with a lot of compiler code. To use a plugin without adding it as a library, you will need the nightly compiler and you will have to add #![feature(plugin)] and #![plugin({plugin_name})] attributes to your crate.

When developing a new plugin, you will need to create the crate with some extra information in the Cargo.toml file, as we did with the procedural macro:

[lib]
plugin = true

Then, in the lib.rs file, you will need to import the required libraries and define the plugin registrar. The bare minimum for the plugin to work would be the following:

#![crate_type="dylib"]
#![feature(plugin_registrar, rustc_private)]

extern crate syntax;
extern crate syntax_pos;
extern crate rustc;
extern crate rustc_plugin;

use rustc_plugin::Registry;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
unimplemented!()
}

Even though, in this example, the rustc, syntax, and syntax_pos crates are not being used, it's almost certain you will need them when developing the plugin, since they have the required types for you to change any behaviour. The Registry object lets you register multiple types of new language items, such as macros or syntax extensions. For each of them, you will need to define a function to receive the compiler tokens and modify them to produce the desired output.

The #![crate_type = "dylib"] attribute tells the compiler to create a dynamic library with the crate, instead of the normal static one. This enables the library to be loaded by the compiler. The plugin_registrar nightly feature lets us create the actual plugin registrar function and the rustc_private feature allows us to use the private Rust compiler types so that we can use the compiler internals.

At the time of writing, the only online documentation for these crates is the one hosted by Manish Goregaokar, but that should change soon. On his website, you can find the API documentation for rustc_plugin (https://manishearth.github.io/rust-internals-docs/rustc_plugin/index.html), for rustc (https://manishearth.github.io/rust-internals-docs/rustc/index.html), for syntax (https://manishearth.github.io/rust-internals-docs/syntax/index.html), and for syntax_pox (https://manishearth.github.io/rust-internals-docs/syntax_pos/index.html). I invite you to read the API of those crates and to create small plugins for the compiler. Nevertheless, remember that the syntax will probably change, which makes it more difficult to maintain.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.223.171.51