ROSE Compiler Framework/Plugin
Overview
editStarting from Version 0.9.9.83, ROSE has a new feature to support external plugins. It borrows the design and implementation of Clang Plugins.
The process to isolate the relevant source files and headers in Clang is available at:
The interface is very similar to what Clang has, with some simplification and improvements.
With this feature, you can develop your ROSE-based tools as dynamically loadable plugins. Then you can use command line options of ROSE's default translator, rose-compiler (or another ROSE translator), to
- load shared libraries containing the plugins,
- specify actions to be executed,
- as well as pass command line options to each action.
Benefits
editThe main benefit of using plugins is that you can use a single installed ROSE default translator to execute one or more arbitrary external plugins, in the order they appear on the command line.
This will significantly reduce the overhead of composing ROSE-based transformations, by reusing the costly parsing and unparsing, and freely chaining up the transformation plugins through command line options.
The deployment of plugins are much simpler also. No need to recompile/reinstall ROSE.
For example, we had to call two heavy-weight tools in two command lines:
# two separated command lines to run two ROSE-based tools, each of which has costly parsing and unparsing. tool_1 input.c; tool_2 input.c;
Now, we can call the default ROSE rose-compiler and chain up two plugins (act1 and act2) instead:
# sharing one identitiTranslator's parsing/unparsing support, # load multiple shared libraries, executing two actions in the order they show up in the command line, also pass multiple options to each of the plugins rose-compiler -rose:plugin_lib lib.so -rose:plugin_lib lib2.so -rose:plugin_action act -rose:plugin_action act2 \ -rose:plugin_arg_act1 op1 -rose:plugin_arg_act1 op2 -rose:plugin_arg_act2 op3 -rose:plugin_arg_act2 op4
Command Line Interface
editrose-compiler --help , excerpt of the plugin section
Plugin Mode: -rose:plugin_lib <shared_lib_filename> Specify the file path to a shared library built from plugin source files This option can repeat multiple times to load multiple libraries -rose:plugin_action <act_name> Specify the plugin action to be executed This option can repeat multiple times to execute multiple actions in the order shown up in command line -rose:plugin_arg_<act_name> <option> Specify one option to be passed to a plugin named act_name This option can repeat multiple times to provide multiple options to a plugin
Examples
- rose-compiler -rose:plugin_lib /path/libPrintNamesPlugin.so -rose:plugin_action print-names -rose:plugin_arg_print-names pretty-printing
- load a shared library containing a single plugin, execute the plugin named print-names, also pass an option named "pretty-printing" to the plugin.
- rose-compiler -rose:plugin_lib lib.so -rose:plugin_lib lib2.so -rose:plugin_action act1 -rose:plugin_action act2 -rose:plugin_arg_act1 op1 -rose:plugin_arg_act1 op2 -rose:plugin_arg_act2 op3 -rose:plugin_arg_act2 op4
- load multiple shared libraries, executing two actions in the order they show up in the command line, also pass multiple options to each of the plugins
Plugin Super Class
editTwo interface functions are provided for a ROSE plugin:
- ParseArgs(): optionally handle command line options passed to this plugin
- process(): process the AST
class PluginAction { public: virtual void process(SgProject*) {}; virtual bool ParseArgs(const std::vector<std::string> &arg) {return true; }; };
An Example Plugin
editYou can find the full example from
This plugin will just print all defining functions' names of an input source file.
// An example ROSE plugin: PrintNamesPlugin.cpp //Mandatory include headers #include "rose.h" #include "plugin.h" // optional headers #include "RoseAst.h" // using AST Iterator #include <iostream> using namespace std; using namespace Rose; //Step 1. Derive a plugin action from Rose::PluginAction class PrintNamesAction : public Rose::PluginAction { public: PrintNamesAction() {} ~PrintNamesAction() {} // This is optional. Need only if your plugin wants to handle options // Provide command line option processing: arg will be the options passed to this plugin bool ParseArgs(const std::vector<std::string> &arg) { cout<<arg.size()<< " arguments "<<endl; for (size_t i=0; i< arg.size(); i++) { cout<<arg[i]<<endl; } return true; } // This is mandatory: providing work in your plugin // Do actual work after ParseArgs(); void process (SgProject* n) { SgNode* node= n; RoseAst ast(node); for(RoseAst::iterator i=ast.begin();i!=ast.end();++i) { SgFunctionDeclaration* fdecl= isSgFunctionDeclaration(*i); if (fdecl && (fdecl->get_definingDeclaration()==fdecl)) cout<<fdecl->get_name()<<endl; } } // end process() }; //Step 2: Declare a plugin entry with a unique name // Register it under a unique action name plus some description static Rose::PluginRegistry::Add<PrintNamesAction> uniquePluginName1("print-names", "print function names");
Compile the plugin
editA sample makefile
- Note: copy&paste may not work since tabs will be wrongfully pasted as whitespaces. You need to restore tabs before commands in the Makefile.
# specify where the installed copy of ROSE is located. # Essentially the --prefix path used with configure ROSE_INSTALL=/path/to/rose/install ## Your Plugin source files Plugin=PrintNamesPlugin Plugin_SOURCE=$(Plugin).cpp ## Input testcode for your plugin TESTCODE=test1.cpp # Standard C++ compiler stuff (see rose-config --help) comma := , CXX = $(shell $(ROSE_INSTALL)/bin/rose-config cxx) CPPFLAGS = $(shell $(ROSE_INSTALL)/bin/rose-config cppflags) -I. CXXFLAGS = $(shell $(ROSE_INSTALL)/bin/rose-config cxxflags) LIBDIRS = $(shell $(ROSE_INSTALL)/bin/rose-config libdirs) LDFLAGS = $(shell $(ROSE_INSTALL)/bin/rose-config ldflags) -L. \ $(addprefix -Wl$(comma)-rpath -Wl$(comma), $(subst :, , $(LIBDIRS))) #------------------------------------------------------------- # Makefile Targets #------------------------------------------------------------- all: $(Plugin).so # compile the plugin and generate a shared library # -g is recommended to be used by default to enable debugging your code $(Plugin).so: $(Plugin_SOURCE) $(CXX) -g $(Plugin_SOURCE) -fpic -shared $(CPPFLAGS) $(LDFLAGS) -o $@ # test the plugin check: $(Plugin).so $(ROSE_INSTALL)/bin/rose-compiler -c -rose:plugin_lib $(Plugin).so -rose:plugin_action print-names -rose:plugin_arg_print-names op1 -I. -I$(ROSE_INSTALL)/include $(TESTCODE) clean: rm -rf $(Plugin).so *.o rose_* *.dot
Running the plugin
editCommand line and options:
- rose-compiler -rose:plugin_lib PrintNamesPlugin.so -rose:plugin_action print-names -rose:plugin_arg_print-names op1 -c input_testPlugins.C
Sample input file: input_testPlugins.C
int foo() {} int bar(); int a, b,c;
Sample output:
1 arguments op1 "foo"