跳轉到內容

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"
華夏公益教科書