2401llvm,clang插件

Clang插件

在编译时,Clang插件可运行额外的用户定义操作.

介绍

Clang插件在代码上运行FrontendActions.见FrontendAction教程,了解如何使用RecursiveASTVisitor编写FrontendAction.
这里,演示如何编写简单的clang插件.

编写PluginASTAction插件

与编写普通FrontendActions的主要区别在,可处理插件命令行选项.PluginASTAction基类声明一个必须在插件中实现的ParseArgs方法.

bool ParseArgs(const CompilerInstance &CI,
    const std::vector<std::string>& args) {
   
  for (unsigned i = 0, e = args.size(); i != e; ++i) {
   
    if (args[i] == "-some-arg") {
   
      //处理命令行参数.
    }
  }
  return true;
}

注册插件

运行时,编译器从动态库加载插件.要在库中注册插件,请使用FrontendPluginRegistry::Add<>:

static FrontendPluginRegistry::Add<MyPlugin> X("my-plugin-name", "my plugin description");

定义编译指示

插件还可通过声明PragmaHandler并使用PragmaHandlerRegistry::Add<>注册它,来定义编译指示:

//定义`#pragma example_pragma`的编译指示处理器
class ExamplePragmaHandler : public PragmaHandler {
   
public:
  ExamplePragmaHandler() : PragmaHandler("example_pragma") {
    }
  void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &PragmaTok) {
   
    //处理编译指示
  }
};
static PragmaHandlerRegistry::Add<ExamplePragmaHandler> Y("example_pragma","example pragma description");

定义属性

插件可通过声明ParsedAttrInfo并使用ParsedAttrInfoRegister::Add<>注册它来定义属性:

class ExampleAttrInfo : public ParsedAttrInfo {
   
public:
  ExampleAttrInfo() {
   
    Spellings.push_back({
   ParsedAttr::AS_GNU,"example"});
  }
  AttrHandling handleDeclAttribute(Sema &S, Decl *D, const ParsedAttr &Attr) const override {
   
    //处理属性
    return AttributeApplied;
  }
};
static ParsedAttrInfoRegistry::Add<ExampleAttrInfo> Z("example_attr","example attribute description");

插件属性必须定义的ParsedAttrInfo的成员包括:

1,拼写(Spellings),必须用属性的每个,都由属性语法该语法的属性名拼写方式组成的拼写这里填充.
如果语法允许域,则拼写必须为"scope::attr"(如果有域)或"::attr"(如果没有).

2,handleDeclAttribute,这是应用属性到声明的函数.它负责检查属性参数是否有效,且一般给Decl添加Attr应用属性.

它返回AttributeApplied(指示已成功应用属性)或(失败)AttributeNotApplied.

根据属性,可能要定义的ParsedAttrInfo成员包括:
1,NumArgsOptArgs,设置属性的必需参数和可选参数个数.
2,diagAppertainsToDecl,检查属性是否用在正确的声明类型上,如果没有,则发出诊断.
3,diagLangOpts,检查当前语言模式是否允许该属性,如果禁止,则发出诊断.
4,existsInTarget,检查给定目标是否允许该属性.

Attribute.cpp示例,可查看属性插件的工作示例.

放在一起

用打印顶级函数名来示例插件.此例已签入clang仓库;请查看最新版本PrintFunctionNames.cpp.

运行插件

用编译器驱动

Clang驱动接受-fplugin选项来加载插件.Clang插件可通过fplugin-arg-<pluginname>-<argument>选项,从编译器驱动命令行接收参数.

这样,插件名自身不能包含破折号,但传递给插件的参数可以.

$ export BD=/path/to/build/directory
$ make -C $BD CallSuperAttr
$ clang++ -fplugin=$BD/lib/CallSuperAttr.so \
          -fplugin-arg-call_super_plugin-help \
          test.cpp

如果插件名包含破折号,请重命名插件或使用下面列举的cc1命令行选项.

使用cc1命令行

要运行插件,必须通过-load命令行选项,加载包含插件注册表的动态库.这加载所有已注册的插件,可通过指定-plugin选项来选择要运行的插件.

可用-plugin-arg-<plugin-name>传递插件其他参数.

注意,这些选项必须到达clangcc1进程.有两个方法:
1,用-cc1选项直接调用解析过程;缺点是没有配置默认头文件搜索路径,因此要在命令行上指定完整系统路径配置.
2,如常使用clang,但在cc1进程的所有参数前面加上-Xclang.

如,要对clang中的源文件上运行print-function-names插件,请先构建该插件,然后用源码树中的插件调用clang:

$ export BD=/path/to/build/directory
$ (cd $BD && make PrintFunctionNames )
$ clang++ -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS \
          -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D_GNU_SOURCE \
          -I$BD/tools/clang/include -Itools/clang/include -I$BD/include -Iinclude \
          tools/clang/tools/clang-check/ClangCheck.cpp -fsyntax-only \
          -Xclang -load -Xclang $BD/lib/PrintFunctionNames.so -Xclang \
          -plugin -Xclang print-fns

另见print-function-name插件示例的README这里

使用clang命令行

clang命令行上,使用-fplugin=plugin,在cc1命令行上,按-load参数传递插件.如果插件类实现了getActionType方法,则会自动运行插件.

如,要在主AST操作后自动运行插件(即与用-add-plugin相同):

//在主`AST`操作后自动运行插件
PluginASTAction::ActionType getActionType() override {
   
  return AddAfterMainAction;
}

-clear-ast-before-backend的交互

为了减少编译器的内存使用峰值,建议在一般是生成代码主操作前,运行插件.这是因为在codegen操作后运行插件,都会自动关闭-clear-ast-before-backend.

-clear-ast-before-backend通过在生成IR后和运行IR优化前,清理ClangAST来减少峰值内存.按getActionType,使用CmdlineBeforeMainActionAddBeforeMainAction来运行插件,同样受益于-clear-ast-before-backend.

插件必须确保不修改AST,否则应在主操作之后运行它们.

相关推荐

  1. 2401编辑器,好

    2024-01-26 12:04:01       71 阅读
  2. 2401llvm,clang

    2024-01-26 12:04:01       57 阅读
  3. 2403d,无串传播uda

    2024-01-26 12:04:01       42 阅读
  4. vscode 安装

    2024-01-26 12:04:01       62 阅读
  5. Wireshark开发

    2024-01-26 12:04:01       51 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-01-26 12:04:01       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-01-26 12:04:01       106 阅读
  3. 在Django里面运行非项目文件

    2024-01-26 12:04:01       87 阅读
  4. Python语言-面向对象

    2024-01-26 12:04:01       96 阅读

热门阅读

  1. conda常用命令总结

    2024-01-26 12:04:01       60 阅读
  2. ·策略模式

    2024-01-26 12:04:01       53 阅读
  3. conda使用,pip使用

    2024-01-26 12:04:01       58 阅读
  4. 解决linux下wps缺失字体的问题

    2024-01-26 12:04:01       62 阅读
  5. 低代码开发助力业务效能高速提升

    2024-01-26 12:04:01       61 阅读
  6. C++(2) 结构体和动态数组的实现

    2024-01-26 12:04:01       46 阅读
  7. ubuntu运行指定的py环境

    2024-01-26 12:04:01       53 阅读
  8. 04 约数

    04 约数

    2024-01-26 12:04:01      48 阅读
  9. kotlin sum 与 sumOf

    2024-01-26 12:04:01       60 阅读
  10. Android.bp 语

    2024-01-26 12:04:01       59 阅读
  11. kotlin中的初始化问题纪录

    2024-01-26 12:04:01       52 阅读
  12. 大厂程序员成长路径

    2024-01-26 12:04:01       58 阅读
  13. 深度挖掘:前端架构设计与现代化实践

    2024-01-26 12:04:01       58 阅读