This page will walk you through how to create a plugin for FFX. If you are looking for a more advanced look into the internals of FFX plugins, visit Plugin Internals page.
The plugin system employs a combination of GN build rules and Rust attributes to decouple plugin code from FFX internals.
First, create a directory to store your plugin. Next, create a BUILD.gn in that directory.
You will need to create a GN build target for your plugin. You"ll need to use to use the “ffx_plugin” build rule template defined here.
Your BUILD.gn file should look something like this:
import("//src/developer/ffx/build/ffx_plugin.gni") ffx_plugin("ffx_example") { version = "0.1.0" edition = "2018" with_unit_tests = true deps = [] sources = [ "src/args.rs", "src/lib.rs", ] }
Next, create a “src” directory to store your code in the same directory as your BUILD.gn file (ffx_plugin wraps the rustc_library build template - so if you are familiar with that template, you should be familiar with this template).
Inside the “src” directory, there needs to be two files. The first file will define the CLI params for your plugin. Create a file “src/args.rs”:
use {argh::FromArgs, ffx_core::ffx_command}; #[ffx_command()] #[derive(FromArgs, Debug, PartialEq)] #[argh(subcommand, name = "example", description = "an example")] pub struct ExampleCommand {}
This uses the argh crate and more documentation can be found here. This struct has been decorated by the “ffx_command” attribute which signifies that your plugin should run when someone types the following command:
$fx ffx example
Next, you will define the plugin execution code. Create a file “src/lib.rs”:
use { anyhow::Error, ffx_core::ffx_plugin, ffx_example_args::ExampleCommand, }; #[ffx_plugin()] pub async fn example(_cmd: ExampleCommand) -> Result<(), Error> { println!("Hello from the example plugin :)"); Ok(()) }
Plugin methods need to accept the argh command created in the ‘src/args.rs’ file as a parameter even if they do not use them.
If you want to unit tests your plugin, just follow the standard method for testing rust code on a host. The ffx_plugin GN template will generate a library name “<target_name>_lib_test” for unit tests if the “with_unit_tests” parameter is set to “true”.
Lastly, you“ll need to add the plugin as a dependency to FFX to include it in the build. You”ll need to edit this file to add your ffx_plugin target.
And that"s it! You should now see the output:
$fx ffx example Hello from the example plugin :)
Note: If this is the start of a larger project, introduce the new plugin by marking it experimental. This will allow for work-in-progress commits and allow others to try out your plugin by opting-in. See more at the Experimental Plugins page.
You may notice that we imported the ExampleCommand in the “src/lib.rs” via a library that was automatically generated by the ffx_plugin template, “ffx_example_args”. The ExampleCommand struct gets compiled into its own library due to the internal dependency graph of FFX which you can read more about in the Plugin Internals page. This is why there must be two different files for the two parts of the plugin. The name of this library will always be the name of your plugin library concatenated with “_args”. If you want to run the unit tests for this library, the test libraries name will be “<target_name>_args_lib_test”. For this example it would be “ffx_example_args_lib_test”.
Plugins can also use FIDL proxies to communicate with a target device through Overnet. For more information, see the Proxy Plugin page.