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"