Clang之libclang

写在前面的话:之前在翻译Clang官方文档(http://www.hellogcc.org/?p=33721)的时候,已经涉及到了libclang,并且对libclang有了一个简单的介绍,特别是关于在什么时候去使用libclang。在这里,侧重谈下自己对libclang的理解和使用的感受。

正文:

现在的Clang,不仅仅是一个编译器前端,同时也可以作为一个库使用。作为一个库使用的时候,可以用它去分析C/C++/ObjectC语言代码,可以 分析源码得到AST,也可以获取已经分析好的AST,也可以遍历AST,还可以获取AST中基本元素的物理源码位置。这就是libclang。

libclang提供了一系列的C语言的接口,但是这些接口并不能完全提供存储在Clang C++ AST中的所有信息,只能提供部分基本信息,但是这些基本信息已经可以满足一般情况下的使用。主要目的是为了稳定,并且可以支持开发工具的基本功能。 (clang/include/clang-c/Index.h中的注释原文如下: This C interface to Clang will never provide all of the information representation stored in Clang’s C++ AST, nor should it: the intent is to maintain an API that is relatively stable from one release to the next, providing only the basic functionality needed to support development tools.)

与此同时,libclang支持和python绑定使用,也就是说你可以是用python去调用libclang。clang在 clang/bindings/python/这个目录下面提供了绑定所需要的文件。目前这个目录下面除了README之外还有三个目 录:clang,examples,tests。其中clang目录下面的文件是绑定所需要的,examples目录下面是绑定后测试用的两个小例子。 test目录下面应该是测试需要的一些文件(该目录下面文件目前还没有认真分析)。只需要把绑定文件放到python的库文件下面(包含clang文件 夹),然后确保系统安装clang到系统目录,之后就可以运行例子了。
libclang带来的优点很明显,可以在很多不同的环境下面轻松的用上libclang,只是作为一个提供了parser功能的库,非常方便快捷 的嵌入自己的工具中,避免了大量的重复工作。同时也不用去分析clang内部的代码,不需要熟悉内部大量的AST相关的代码,就可以使用,这可以节省大量 的时间。当然,想深挖clang的代码的同学,也可以把这里当作一个突破口。

附录(一个同主题的非常好的英文博客,该内容包含了如何去具体实现python调用libclang):

http://eli.thegreenplace.net/2011/07/03/parsing-c-in-python-with-clang/

Android中编译工具链的改动—-LLVM份量的增加

最近,Android中的编译工具链发生了改动,这个改动是Android的runtime(也可以说是VM,这两种说法在Google官方文档中也多次交互出现)改动引发的。之前Android采用的是Dalvik VM,在Android2.2之前,连JIT都没有使用,只是解释执行,所以速度很慢,从Android2.2之后加入了JIT之后,一直用了相当长的时间。直到ART(Android Runtime)的出现,ART的出现也是为了进一步提高运行速度,据早期的测试结果表明,ART上的执行速度可以比Dalvik上的执行速度快一倍。所以总的来说,不管是添加JIT支持,还是现在的ART,都是为了速度更快。

ART是在Android4.4正式出现的,就是它引起了Android中编译工具链的改动。之前Dalvik拿到.dex或者优化过的.odex文件,是使用JIT然后执行的。现在ART是直接使用LLVM去做AOT(Ahead of Time),这样的话,执行速度自然就上来了,带来的牺牲是应用的安装速度会降下来,因为AOT编译是在安装的时候做的,后续的启动和执行,都使用的是AOT之后的结果。所以等于是用一次时间牺牲,换来之后的多次时间节省。
ART目前是和Dalvik同时存在系统中的,用户也可以自己选择。在系统中它们分别以Dalvik runtime (libdvm.so) 和 ART (libart.so)这两个库的形式存在,ART的源码位置也是在和Dalvik的同级位置,直接在Android目录下有个art目录。目前art目录下的设置基本上也是参照Dalvik的形式来的,几个工具也都是类似,只是把与原来的dexopt工具给换成了dex2oat,然后引入了LLVM去做编译的工作。到这个程度,LLVM等于已经参与了Android上的所有应用的编译工作,在art出现之前,LLVM只是处理Android Renderscript中的rs文件。

ART目前所带来的缺点就是占用空间增大和首次安装时间延长,这都是由AOT导致的,目前看来是没有办法避免的。还有一个问题就是目前为了同时支持Dalvik和ART,依然采用dex格式文件作为输入,但是dex格式本身就是给Dalvik所设计的可执行格式,所以如果将来真的丢掉Dalvik的话,这个dex格式就有点不伦不类了,可能到那时候这个dex格式也终将作出改变。

参考资料:

Google关于ART的介绍: https://source.android.com/devices/tech/dalvik/art.html

Dalvik: http://en.wikipedia.org/wiki/Dalvik_(software)

AOT: http://en.wikipedia.org/wiki/AOT_compiler

JIT: http://en.wikipedia.org/wiki/Just-in-time_compilation

CSDN一篇不错的分析ART机制的文章:http://blog.csdn.net/androidsecurity/article/details/17462529

一个关于ART的YOUTUBE视频:http://www.youtube.com/watch?v=USgXkI-NRPo

一篇介绍ART的很通俗易懂的文章:http://www.extremetech.com/computing/170677-android-art-google-finally-moves-to-replace-dalvik-to-boost-performance-and-battery-life

Clang文档翻译—- Using Clang Tools—-Overview

原文地址:http://clang.llvm.org/docs/ClangTools.html

译者:shining

简介

 

Clang工具是为C++开发者所设计的单独的命令行(潜在的图形界面)工具,这些开发者是已经使用Clang并且喜欢使用Clang作为他们的编译器。这些工具提供了面向开发的功能:语法检查,自动格式化,重构等。

只有少数几个最基本和基础的工具被保留在Clang的SVN工程里。剩下的工具都被保存在边上其他的工程里,因为有些用户不想要或者不需要构建他 们。如果你想进入额外的Clang工具代码库,简单的把他们下载到你的Clang的工具目录,然后采用平常所使用的构建过程去和有关联的 LLVM/Clang代码一起构建:

  • With Subversion:
    • cd llvm/tools/clang/tools
    • svn cohttp://llvm.org/svn/llvm-project/clang-tools-extra/trunk extra
  • Or with Git:
    • cd llvm/tools/clang/tools
    • git clonehttp://llvm.org/git/clang-tools-extra.gitextra

这个文档描述了工程内部的Clang工具的高层次组织的简介,同时介绍了这些工具中更重要的几个。然而,需要注意的是,这个文档只是针对Clang和Clang工具的开发者,不是这些工具的最终用户。

Clang工具的组织

Clang工具是为了让C++开发者可以直接使用的命令行或者图形界面程序。它们最初不是为了给Clang的开发者使用的,尽管希望它们可以对恰巧 工作在Clang的C++开发者有很大帮助,我们积极扩展他们的功能。它们被作为三个部分进行开发:基于Clang而构建的一个单独工具的基础设施;被很 多不同的工具所使用的核心共享逻辑,这些工具是以重构和重写库的形式出现的;工具本身。

Clang工具的基础设施是LibTooling平台。可以从它的文档中看到更多关于它的架构如何工作的细节。重构和重写的工具包风格的库的共同之处也是LibTooling组织的一部分。

几乎没有Clang工具是和核心的Clang库,像基本功能和测试用例那样一起开发。然而,大多数的工具就在边上的代码库(不在项目的代码库)上开 发就是为了证明它们其实就是简单的从核心库中分离。我们没打算支持很多不在项目代码库的公共库,我们想很细心的复审和查找好的库的接口,然后把它们从那些 库里放到核心Clang库系列。

无论Clang的工具的代码放在哪个代码库中,所有的Clang工具的开发过程和实践都是Clang本身的。它们都是Clang项目的一部分,无论使用什么样的版本控制体系。

核心Clang工具

Clang工具的核心系列是在主工程之内的,完成程度已经非常高,并且允许使用和进行Clang的特定功能测试。

clang-check

ClangCheck联合了运行一个Clang工具所需的LibTooling框架和对特定的文件进行快速的语法检查的Clang诊断,使用的是命 令行接口。它也可以通过接受不同的标志来显示不同格式的输出,适合用来驱动IDE或者编辑器。此外,它能在修复模式下直接使用Clang提供的修复提示。 可以从文档How To Setup Clang Tooling For LLVM中去查找如何去建立和使用clang-check的命令。

clang-format

Clang-format既是一个库,也是一个单独的工具,它的目标是根据认证的风格指引去自动格式化C++源码文件。为了达到这个目 标,clang-format使用Clang的Lexer去把一个输入文件转换为一个token流,然后改变这些token周围的的所有空格。 clang-format的这个目标是既要可以作为一个用户工具(理论上拥有强大的IDE集成),同时又要作为其它重构工具的一部分,比如:在重命名的时 候去格式化所有改变的行。

cpp11-migrate

cpp11-migrate 迁移C++的代码去在合适的地方使用C++11的特性。目前它可以:

  • 把循环转化为基于范围的for循环;
  • 把空指针常量(比如NULL或者0)转换为C++11的nullptr;
  • 用auto类型说明符替换变量声明中的类型说明;
  • 在适当的成员函数上添加override说明;

额外的Clang工具

不同种类的Clang工具被添加到额外的代码库中,它们将在这里被跟踪记录。这个文档的焦点是对于其他工具开发者来说的工具范围特征,每一个工具都应该提供它自己的聚焦用户的文档。

新工具的思路:

  • C++ cast转换工具。将可以把C风格的casts((type)value) 转换为C++ cast(static_cast,const_cast orreinterpret_cast)。
  • 无成员的begin()和end()转换工具。将可以转换foo.begin()为begin(foo),end()也是同样的,这里的foo是一个标准容器。我们也会探测数组的相似的模式。
  • make_shared /make_unique转换。这个转换器的一部分可以和auto转换器联合起来。它将可以转换:
    std::shared_ptr<Foo> sp(new Foo);
    std::unique_ptr<Foo> up(new Foo);
    
    func(std::shared_ptr<Foo>(new Foo), bar());

    变为:

    auto sp = std::make_shared<Foo>();
    auto up = std::make_unique<Foo>(); // In C++14 mode.
    
    // This also affects correctness.  For the cases where bar() throws,
    // make_shared() is safe and the original code may leak.
    func(std::make_shared<Foo>(), bar());
  • tr1去除工具。它将使用TR1库的源码迁移到使用C++11的库。例如:
    #include <tr1/unordered_map>
    int main()
    {
        std::tr1::unordered_map <int, int> ma;
        std::cout << ma.size () << std::endl;
        return 0;
    }

    应该被重写为:

    #include <unordered_map>
    int main()
    {
        std::unordered_map <int, int> ma;
        std::cout << ma.size () << std::endl;
        return 0;
    }
  • 一个去除auto工具。将把auto转换为一个明确的类型或者添加推断的类型到注释里。这个工具的动机是因为有开发者不想去使用auto,他们害怕会让他们的代码失控。
  • C++14:更少的函数对象冗余操作(N3421)。例如:
    sort(v.begin(), v.end(), greater<ValueType>());

    应该被重写为:

    sort(v.begin(), v.end(), greater<>());

翻译Clang文档:Choosing the Right Interface for Your Application

 

为你的程序选择正确的接口

 

Clang为实现需要一个程序的语法和语义信息的工具提供了基础设施。((译者注:为了便于理解,再意译一句)如果你想实现一个工具,而这个工具需要获取 一个程序的语法和语义信息,那么恭喜你,Clang可以为你提供一些基础实现。)这个文档将给出使用不同的方法去实现基于Clang的工具的一个简短介 绍,包括它们的优点和缺点。

LibClang

LibClang是一个稳定的高层次的Clang的C语言接口。如果不确定LibClang是你想要用的接口,只有当你有一个好的理由不用LibClang的时候,这个时候你才可以去用别的接口。

如果遇到如下情况,那么就是典型的使用LibClang的时候:(译者注:Xcode目前没搞清楚,暂时保留):

  • Xcode
  • Clang Python Bindings

如果遇到下列情况,请使用LibClang:

  • 想使用Clang除了C++之外的编程语言的接口
  • 需要一个稳定的接口可以向后兼容
  • 需要一个十分强大的高层次的抽象,比如:像一个光标一样遍历AST,或者不想去学习Clang的AST的所有的细节问题

如果遇到下列情况,请不要使用LibClang:

  • 想完全控制Clang AST

 

Clang Plugins

 

Clang Plugins允许你在AST之上运行一些额外的动作,而这些动作作为编译的一部分。Plugins是运行的时候被编译器加载的动态库,她们很容易合并到你的构建环境中。

如果遇到如下情况,那么就是典型的使用Clang Plugins的时候:

  • 你的工程有特殊的lint风格的警告或者错误
  • 从一个单独的编译步骤要创建额外的构建神器

如果遇到下列情况,请使用Clang Plugins:

  • 需要你的工具去返回任何依赖关系的变化
  • 想让你的工具去执行或者跳出一次构建
  • 需要完全控制Clang AST

如果遇到下列情况,请不要使用Clang Plugins:

  • 想在你的构建环境的外部运行工具
  • 想完全控制Clang如何建立起来,包括内存虚文件的映射
  • 想去运行你工程中的一部分特殊的文件,而这部分文件和触发重新构建是没有必要联系的

LibTooling

LibTooling是一个C++接口,它的目标在于实现完全独立的工具,而这些工具就像是被集成到运行Clang工具的服务中了一样。
如果遇到如下情况,那么就是典型的使用LibTooling的时候:

  • 一个简易的语法检查器
  • 重构工具

如果遇到下列情况,请使用LibTooling:

  • 想在独立于构建系统的单个文件或者一系列特殊的文件上运行工具
  • 想完全控制Clang AST
  • 想和Clang Plugins共享代码

如果遇到下列情况,请不要使用LibTooling:

  • 想作为可以被依赖关系改变而触发的构建系统的一部分运行
  • 想要一个稳定的接口,不需要因为AST API的改变而改变你的代码
  • 想要一个高层次的抽象像光标和在盒子之外完成的代码
  • 不想使用C++去实现你的工具

Clang tools是一系列基于LibTooling架构基础之上构建的特殊的开发者工具,它们是Clang工程的一部分。它们的目标是自动化和改善C/C++开发者的核心开发活动。

我们已经在构建或者计划构建的作为Clang工程的一部分例子工具有:

  • 语法检查 (clang-check)
  • 自动修复编译错误 (clang-fixit)
  • 自动代码格式化 (clang-format)
  • 新语言标准的新特性的迁移工具(cpp11-migrate,译者注)
  • 核心重构工具

(完)