ROSE 编译器框架/插件
外观
从 0.9.9.83 版本开始,ROSE 有一个新的功能来支持外部插件。它借鉴了 Clang 插件 的设计和实现。
将 Clang 中的相关源文件和头文件分离的过程可以在以下位置找到:
该接口与 Clang 的接口非常相似,但进行了一些简化和改进。
借助此功能,您可以将基于 ROSE 的工具开发为动态加载的插件。然后,您可以使用 ROSE 默认翻译器的命令行选项,即 rose-compiler(或其他 ROSE 翻译器),来
- 加载包含插件的共享库,
- 指定要执行的操作,
- 以及将命令行选项传递给每个操作。
使用插件的主要优势在于,您可以使用单个安装的 ROSE 默认翻译器来执行一个或多个任意外部插件,以它们在命令行中出现的顺序执行。
这将通过重用代价高昂的解析和反解析,以及通过命令行选项自由地将转换插件链接起来,从而显着减少组合基于 ROSE 的转换的开销。
插件的部署也更加简单。无需重新编译/重新安装 ROSE。
例如,我们必须在两个命令行中调用两个重量级工具
# 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;
现在,我们可以调用默认的 ROSE rose-compiler 并链接两个插件(act1 和 act2)
# 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
rose-compiler --help,插件部分的摘录
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
示例
- rose-compiler -rose:plugin_lib /path/libPrintNamesPlugin.so -rose:plugin_action print-names -rose:plugin_arg_print-names pretty-printing
- 加载包含单个插件的共享库,执行名为 print-names 的插件,并将名为“pretty-printing”的选项传递给插件。
- 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
- 加载多个共享库,按它们在命令行中出现的顺序执行两个操作,并将多个选项传递给每个插件。
为 ROSE 插件提供了两个接口函数
- ParseArgs():可选地处理传递给此插件的命令行选项
- process():处理 AST
class PluginAction { public: virtual void process(SgProject*) {}; virtual bool ParseArgs(const std::vector<std::string> &arg) {return true; }; };
您可以从以下位置找到完整的示例:
此插件只会打印输入源文件的所有定义函数的名称。
// 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");
示例 Makefile
- 注意:复制粘贴可能无法正常工作,因为制表符会被错误地粘贴为空格。您需要在 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
命令行和选项
- rose-compiler -rose:plugin_lib PrintNamesPlugin.so -rose:plugin_action print-names -rose:plugin_arg_print-names op1 -c input_testPlugins.C
示例输入文件:input_testPlugins.C
int foo() {} int bar(); int a, b,c;
示例输出
1 arguments op1 "foo"