编译选项相关:

想要添加的选项,以我添加的-fdpu为例子

能通过clang --help得到的选项,整体需要一个解析文件(好像在LLVM项目中都是通过后缀名为xxx.td和xxx.def的文件来进行存储的,然后通过xxx.h声明,xxx.cpp真正进行解析)

比如添加-fdpu,是在clang/include/Driver/Options.td添加相应的选项(其实就是凭感觉加,感觉和哪个比较像就对应加一个,具体的内容没研究明白),我是加成了这样:

def fdpu : Flag<["-"], "fdpu">, Flags<[DriverOption, CC1Option]>,

HelpText<"Enable DPU extensions">;

这个里边的选项都是直接面向用户的,因此加的时候可以不是那么严谨,里边的Flags是标记作为DriverOption和要传递给CC1(CC1真正完成编译工作,里边才是我们需要添加的动作)

但是也不要乱加,这个里边其实是有定义Group的,比如ActionGroup中定义的都是动作,其他像M_Group等的,都是各种语言相应的Group。而且这个Group的定义是有相应的动作,比如像源源变换等操作,最好就再建立一个Action相关的选项,留给CC1使用

我的实现是在clang/include/Driver/CC1Options.td中添加了一个要实现源源变化的Action:

def rewrite_dpu : Flag<["-"], "rewrite-dpu">,

HelpText<"Rewrite dpu source to C">;

上边也说了,这个是一个要驱动进行源源变换的Action,所以被放在了Action_Group组内。

之前也提到了,我们添加的选项希望都是由用户指定的,在Options和CC1Options中添加了选项还不算完,还需要在clang/include/Driver/Types.def中添加两种选项,具体用法还不是特别清楚,只知道最后一个”u”告诉编译器,这是一个用户指定的选项(user specified)

TYPE("dpu-cpp-output",           PP_DPU,       INVALID,         "dpui",  "u")

TYPE("dpu",                      DPU,          PP_DPU,          "c",     "u")

这里不是使用的都是TYPE么,所以后边就会出现TY_XXX的东西

在clang/lib/Driver/Types.cpp中对Types.def文件进行了解析,这个函数完成的是文件名后缀字符串的解析types::ID types::lookupTypeForExtension(llvm::StringRef Ext)

我们在其中添加dpu的解析:

.Case("dpu", TY_DPU)

.Case("dpui", TY_PP_DPU)

也就是我们这里假设会出现一种专用于DPU平台的xxx.dpui的代码(留作以后使用,目前其实没啥用)

这里做了改动以后,需要在clang可以接受的类型中添加对应的处理,其实就是在

bool types::isAcceptedByClang(ID Id)函数中添加

case TY_DPU: case TY_PP_DPU:

有了类型处理以后,真正进入处理过程。

在clang/lib/Driver/Tools.cpp的

void Clang::ConstructJob(Compilation &C, const JobAction &JA,

const InputInfo &Output, const InputInfoList &Inputs,

const ArgList &Args, const char *LinkingOutput) const 中

这个函数内包含着编译的各个phase的编译工作,比如

isa<AnalyzeJobAction>(JA)

isa<PrecompileJobAction>(JA)

添加对DPU的支持,是在

(isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) && "Invalid action for clang tool.")分支内添加

else if (JA.getType() == types::TY_DPU) {

CmdArgs.push_back("-fdpu");

CmdArgs.push_back("-rewrite-dpu");

}

其实就是在真正的编译过程中加入-fdpu和-rewrite-dpu两个选项

这只是在编译过程中加了选项,还要根据选项添加编译任务。在clang/lib/Driver/Driver.cpp中添加各个阶段真正的任务

比如我是在phases::Compile:阶段添加了

if (Args.hasArg(options::OPT_fdpu)) {

return new CompileJobAction(Input, types::TY_DPU);

}

同时为了能在最后一个阶段有一定的作用,在

phases::ID Driver::getFinalPhase(const DerivedArgList &DAL, Arg **FinalPhaseArg) const

也添加了相应的处理代码

// -{fsyntax-only,-analyze,emit-ast} only run up to the compiler.  这个分支下添加

(PhaseArg = DAL.getLastArg(options::OPT_fdpu) ) ||

编译的阶段和编译的任务都添加好了,之后就是具体的Action实现了。总体来说就是在Frontend中添加响应的Action。

先定义好InputKind,在clang/include/clang/Frontend/FrontendOptions.h的enum InputKind中加入

IK_DPU,

IK_PreprocessedDPU

因为要做个源源变换的工具,在ActionKind中添加响应的项

RewriteDPU,     ///< Run DPU

上边说过了,定义了IK_DPU和IK_PreprocessedDPU这两个符号,但是,该怎么解析才能确定是这两个符号。因此在clang/lib/Frontend/FrontendOptions.cpp中的

InputKind FrontendOptions::getInputKindForExtension(StringRef Extension)中添加

.Case("dpui", IK_PreprocessedDPU)

.Case("dpu",  IK_DPU)

意思就是遇到这样的字符串,就解析成这两个值

在clang/lib/Frontend/FrontendActions.cpp中的void PrintPreambleAction::ExecuteAction() 中添加IK_DPU和 IK_PreprocessedDPU的支持

case IK_DPU:

break;

case IK_PreprocessedDPU:

前期准备工作基本上差不多了,Action也准备好了,就差真正的调用了。

在clang/lib/Frontend/CompilerInstance.cpp中,存在了大量对CompileInstance的设置和修改,为了能对DPU中的输入文件进行兼容,在

static InputKind getSourceInputKindFromOptions(const LangOptions &LangOpts)中添加了相应的处理

if (LangOpts.DPU)

return IK_DPU;

CompileInstance修改好,终于到了真正的调用过程CompileInvocation

在clang/lib/Frontend/CompilerInvocation.cpp中

static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,

DiagnosticsEngine &Diags,

bool &IsHeaderFile)函数中

是针对前端进行的处理,前边提到了我们把前端的处理作为ActionGroup中一个子项rewrite_dpu,那么这里的处理代码就应该加在

if (const Arg *A = Args.getLastArg(OPT_Action_Group)) {

switch (A->getOption().getID())

下边,具体如下:

case OPT_rewrite_dpu:

Opts.ProgramAction = frontend::RewriteDPU; break;

前边说过,这个是要进行源源变换的,源源变换的输出是c或者dpui

因此在该函数下半部分针对字符串进行解析的时候,添加对应的处理,也就是在

DashX = llvm::StringSwitch<InputKind>(A->getValue())

添加

.Case("dpu", IK_DPU)

.Case("dpu-cpp-output", IK_PreprocessedDPU)

这里同样可以对语言进行设置,我这里是针对

void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,

const llvm::Triple &T,

PreprocessorOptions &PPOpts,

LangStandard::Kind LangStd)函数

if (LangStd == LangStandard::lang_unspecified)分之下进行了支持

case IK_DPU:

case IK_PreprocessedDPU:

LangStd = LangStandard::lang_gnu11; //C++ 11的支持

break;

等等,这里只有一个类型的声明,具体的调用我们还没有看到,我们希望看到的是具体的new classA类似的调用过程。因此,在具体的clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp中的

static std::unique_ptr<FrontendAction> CreateFrontendBaseAction(CompilerInstance &CI)函数内存着真正的调用过程,添加处理如下:

case RewriteDPU:             return llvm::make_unique<RewriteDPUAction>();

RewriteDPUAction这个类是我们真正实现的类。

这个类需要继承至public ASTFrontendAction

实现特别简单

std::unique_ptr<ASTConsumer> RewriteDPUAction::CreateASTConsumer(CompilerInstance &CI,

StringRef InFile) {

 if (std::unique_ptr<raw_ostream> OS = CI.createDefaultOutputFile(false, InFile)) {

    return CreateDPUConsumer(CI, InFile ,std::move(OS));

  }

return nullptr;

}

bool RewriteDPUAction::BeginInvocation(CompilerInstance &CI) {

return true;

}

剩下所有的东西都交给DPUConsumer这个消费者来处理

我在DPUConsumer中添加了对public SemaConsumer, public PassManager的继承,以此对Pass管理器和语法消费者的支持,从而准备支持制导。

在这个层次,就可以随心所欲的添加自己想要的Pass了

目前还在开发中,代码不方便open,之后应该会作为一个开源项目在GitHub上见到,有什么问题可以给我发消息。最近也比较忙,没时间修改格式,待假期有空修改。

http://www.cnblogs.com/jourluohua

Clang编译选项和Pass构建的更多相关文章

  1. hdu2377Bus Pass(构建更复杂的图+spfa)

    主题链接: 啊哈哈,点我点我 思路: 题目是给了非常多个车站.然后要你找到一个社区距离这些车站的最大值最小..所以对每一个车站做一次spfa.那么就得到了到每一个社区的最大值,最后对每一个社区扫描一次 ...

  2. Mac 下的 C++ 开发环境

    1. Xcode 创建 C++ 项目 Xcode (版本 4.6.3)默认支持创建 C++ 项目,步骤很简单:打开 Xcode,新建一个项目:在 OS X 中的 Application 中选择 Com ...

  3. Linux基于webRTC的二次开发(一)

    最近在做Linux平台下webRTC的二次开发,一路摸索,中间踩了不少坑,这一篇博客先来简单介绍下Linux上如何使用GCC编译webRTC. 为什么使用GCC编译? 这其实是无奈之举,Linux下w ...

  4. DeviceOne 让你一见钟情的App快速开发平台

    接触 DeviceOne 要从15年11月开始说起了,因项目和产品时间需求接触了快速开发平台,DeviceOne是非常棒的一个平台,双向数据绑定,可以自定义指令,过滤器等等.总之非常好用完全超出了我们 ...

  5. Python单元测试框架unittest使用方法讲解

    这篇文章主要介绍了Python单元测试框架unittest使用方法讲解,本文讲解了unittest概述.命令行接口.测试案例自动搜索.创建测试代码.构建测试套件方法等内容,需要的朋友可以参考下   概 ...

  6. cmake中文帮助文档

    CMake的 在这个页面 了解CMake的生成命令 在摇篮使用cmake变量 报告问题 使用过Android Studio 2.2及更高版本,可以使用NDK和CMake的 编译C和C ++代码到本机库 ...

  7. [译]Vulkan教程(02)概况

    [译]Vulkan教程(02)概况 这是我翻译(https://vulkan-tutorial.com)上的Vulkan教程的第2篇. This chapter will start off with ...

  8. Python单元测试框架:unittest(一)

    Python单元测试框架unittest使用方法讲解 主要介绍了Python单元测试框架unittest使用方法讲解,本文讲解了unittest概述.命令行接口.测试案例自动搜索.创建测试代码.构建测 ...

  9. AFL++ Fuzz一个libexif例子

    CVE-2009-3895 首先在NVD找到漏洞描述如下: 大致意思是说:libexif 0.6.18 中的 libexif/exif-entry.c 中的 exif_entry_fix 函数中基于堆 ...

随机推荐

  1. php执行方式对比:mod_php&php-fpm

    mod_php 1.是apache的附属包,apache死掉后php也会死掉 2.稳定性差,php出错服务器进程也会受影响 php-fpm       1.和nginx是两个独立的个体. 2.php- ...

  2. Win10怎样显示此电脑

    1.在桌面空白处右击鼠标,在出现的选项框中选择“个性化”按钮: 2.在打开的页面中选择左侧的“主题”选项,在右侧选择“桌面图标设置”: 3.在弹出的小窗口中勾选“计算机”,点击“确定”,回到桌面即有此 ...

  3. IPV6基础

    Pv6与IPv4的区别 Pv6报文与IPv4报文差别就两个地方: 一个是数据链路层(以太网协议)中协议类型,IPv4是0x0800,IPv6是0x86DD 另一个是IPv6 Header是40字节,I ...

  4. Java之HSF搭建demo

    1.去阿里云官网下载Demo edas-app-demo.zip 2.下载Ali-Tomcat和Pandora,注意红色下面字体 a)下载 Ali-Tomcat,保存后解压至相应的目录(如:d:\wo ...

  5. [笔记] 如何在Windows上同时打开多个钉钉?

    钉钉防多开原理 常规程序防止多开,会使用Mutex. 钉钉是常规程序,所以也是使用Mutex. 查找钉钉使用的Mutex 工具:ProcessExplorer.exe 启动钉钉,然后使用Process ...

  6. Data - 【转】数据统计、数据挖掘、大数据、OLAP的区别

    原文链接 数据分析 数据分析是一个大的概念,理论上任何对数据进行计算.处理从而得出一些有意义的结论的过程,都叫数据分析. 从数据本身的复杂程度.以及对数据进行处理的复杂度和深度来看,可以把数据分析分为 ...

  7. JWT With NetCore WebApi

    1 什么是JWT? JWT是一种用于双方之间传递安全信息的简洁的.URL安全的表述性声明规范.JWT作为一个开放的标准(RFC 7519),定义了一种简洁的,自包含的方法用于通信双方之间以Json对象 ...

  8. mariadb数据库集群

    1.主从架构: 每个从节点需要一个dump线程连接主节点 异步:效率高,安全性低,有延迟 同步:效率低,安全性高,无延迟 主:可读可写,(dump thread) 从:可读不可写 (sql threa ...

  9. 【JulyEdu-Python基础】第 4 课:面向对象基础

    类(class):用来描述具有相同的属性和方法的对象的集合,它定义了该集合中每个对象所共有的属性和方法.对象是类的实例. 对象:通过类定义的数据结构实例.对象包括两个数据成员(类变量和实例变量)和方法 ...

  10. C++学习笔记-多态

    多态作为面向对象的重要概念,在如何一门面向对象编程语言中都有着举足轻重的作用,学习多态,有助于更好地理多态的行为 多态性(Polymorphism)是指一个名字,多种语义:或界面相同,多种实现. 重载 ...