跳转到内容

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"
华夏公益教科书