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"