Clang特性分析

本文详细的介绍了Clang的功能和目标,并对我们的意思给出了更广泛的解释。

快速编译与低内存使用

我们在clang上工作的一个主要焦点是使其快速,轻便和可扩展。clang的基于库的体系结构使得它可以直接计时并分析堆栈每层的成本,并且驱动程序具有许多性能分析选项。许多详细的基准测试可以在网上找到。
编译时间性能很重要,但是当使用clang作为API时,通常内存使用更是如此:代码占用的内存越少,一次可以容纳到内存中的代码就越多(例如,对于整个程序分析工具很有用)

除了在批处理模式下与GCC进行头对头攻击时,clang还具有基于库的架构,使其相对容易适应并使用它构建新工具。这意味着通常可以应用开箱即用的思维和新颖的技术来以各种方式改进编译。

富有表现力的诊断

除了快速和实用之外,我们的目标是让Clang非常友好。就命令行编译器而言,这基本上归结为使编译器生成的诊断(错误和警告消息)尽可能有用。我们有几种方法可以做到这一点,但最重要的是精确查明程序中的错误,突出显示相关信息,以便一目了然,并使措辞尽可能清晰。
这是一个简单的例子,说明了典型的GCC和Clang诊断之间的区别:

$ gcc-4.9 -fsyntax-only t.c
t.c: In function 'int f(int, int)':
t.c:7:39: error: invalid operands to binary + (have 'int' and 'struct A')
return y + func(y ? ((SomeA.X + 40) + SomeA) / 42 + SomeA.X : SomeA.X);
^
$ clang -fsyntax-only t.c
t.c:7:39: error: invalid operands to binary expression ('int' and 'struct A')
return y + func(y ? ((SomeA.X + 40) + SomeA) / 42 + SomeA.X : SomeA.X);
~~~~~~~~~~~~~~ ^ ~~~~~

在这里你可以看到你甚至不需要看到原始的源代码来理解基于Clang错误的错误:因为Clang打印一个插入符号,你确切地知道它正在抱怨哪个加号。范围信息突出显示了加号的左侧和右侧,这使得编辑器正在谈论的内容立即变得明显,这对于涉及优先级问题和许多其他情况的情况非常有用。
Clang诊断非常精致,具有许多功能。有关更多信息和示例,请参阅“表达式诊断”页面。

GCC兼容性

GCC目前是当前的事实标准开源编译器,它通常会编译大量的代码。GCC支持大量的扩展和功能(其中许多是未记录的),并且许多代码和头文件依赖于这些功能来构建。
虽然能够忽略这些扩展并专注于实现语言标准是很好的,但语用学迫使我们支持最常用的GCC扩展。许多用户只是希望他们的代码能够编译,他们并不关心是否迂腐C99。
如上所述,所有扩展都被明确识别,并标记为扩展诊断,可以映射到警告,错误或忽略。

基于库的架构

clang的一个主要设计概念是它使用基于库的架构。在这种设计中,前端的各个部分可以干净地分成单独的库,然后可以将它们混合以满足不同的需求和用途。此外,基于库的方法鼓励良好的界面,使新开发人员更容易参与(因为他们只需要了解大局的一小部分)。

“世界需要更好的编译工具,这些工具是作为库构建的。这个设计点允许以新的和新颖的方式重用工具。但是,将工具构建为库是不够的:它们必须具有干净的API,如同解耦尽可能彼此相容,并且易于修改/扩展。这需要干净的分层,合理的设计,并保持库独立于任何特定的客户端。“

目前,clang分为以下库和工具:

  • libsupport - 来自LLVM的基本支持库。
  • libsystem - 来自LLVM的系统抽象库。
  • libbasic -
    诊断,SourceLocations,SourceBuffer抽象,输入源文件的文件系统缓存。
  • libast - 提供用于表示C
    AST,C类型系统,内置函数以及用于分析和操作AST(访问者,漂亮的打印机等)的各种帮助程序的类。
  • liblex -
    词法分析和预处理,标识符哈希表,pragma处理,令牌和宏扩展。
  • libparse -
    解析。该库调用客户端提供的粗粒度“Actions”(例如libsema构建AST),但对AST或其他特定于客户端的数据结构一无所知。
  • libsema -
    语义分析。这提供了一组解析器操作来为程序构建标准化的AST。
  • libcodegen - 将AST降低到LLVM IR以进行优化和代码生成。
  • librewrite -
    编辑文本缓冲区(对于代码重写转换很重要,比如重构)。
  • libanalysis - 静态分析支持。
  • clang - 驱动程序,各级图书馆的客户。

作为这个基于库的设计的强大功能的一个例子….如果你想构建一个预处理器,你可以使用Basic和Lexer库。如果您想要一个索引器,您可以使用前两个并添加Parser库和一些用于索引的操作。如果需要重构,静态分析或源到源编译器工具,则可以添加AST构建和语义分析器库。
有关各种clang库的低级实现细节的更多信息,请参阅 clang Internals
Manual

支持多样化的客户

Clang的设计和制造有许多宏大的计划,我们可以如何使用它。推动力是我们每天使用C和C
++,并且由于缺乏可用的好工具而不得不受苦。我们认为C和C
++工具生态系统在解析和表示这些语言的源代码方面受到很大限制,我们的目标是在clang中纠正这个问题。
这个目标的问题是不同的客户有不同的要求。考虑代码生成,例如:解析代码生成的简单前端必须分析代码的有效性,并以某种中间形式发出代码以传递给优化器或后端。因为有效性分析和代码生成可以在很大程度上动态完成,所以前端实际上并不需要为代码中的所有表达式和语句构建完整的AST。TCC和GCC是编译器的例子,它们不构建真正的AST(在前一种情况下)或构建一个精简的AST(在后一种情况下),因为它们主要关注codegen。
在频谱的另一面,一些客户端(如重构)需要有关原始源代码的非常详细的信息,并希望用完整的AST来描述它。重构希望获得有关宏扩展的信息,每个表达式’(((x)))’与’x’的位置,完整位置信息等等。此外,重构需要查看 整个程序,以确保它正在进行安全的转换。提高效率并实现这一目标需要大量的工程和算法工作,这对简单的静态编译器来说根本不需要。
clang方法的优点在于它并不限制你如何使用它。特别是,可以使用clang预处理器和解析器来构建一个非常快速且轻量级的动态代码生成器(类似于TCC),它根本不构建AST。作为中间步骤,clang支持使用当前的AST生成和语义分析代码,并且代码生成客户端在代码生成之后为每个函数释放AST。最后,clang为构建和保留完整的AST提供支持,甚至支持将它们写入磁盘。
使用简洁的API设计库允许在客户端中确定这些高级策略决策,而不是在任何这些库的实现中强制“一种真实的方式”。做到这一点很难,我们并不总是第一次做对,但是当我们意识到自己犯了错误时,我们会解决任何问题。

与IDE集成

我们相信,集成开发环境(IDE)是将各种开发难题结合在一起的好方法,旨在使clang在这样的环境中正常运行。IDE的主要优点是它们通常具有整个项目的可见性,并且是长期存在的流程,而独立的编译器工具通常在项目中的每个单独文件上调用,因此范围有限。
这种差异有很多含义,但重要的是与效率和缓存有关:在项目中的不同文件之间共享地址空间意味着您可以使用智能缓存和其他技术来显着缩短分析/编译时间。
IDE和批处理编译器之间的另一个区别是它们经常对前端施加非常不同的要求:它们依赖于高性能以提供“快速”的体验,因此真正需要诸如“增量编译”,“模糊”之类的技术最后,IDE通常与代码生成有着非常不同的要求,通常需要只有codegen的前端才能丢弃的信息。Clang专门设计和构建以捕获此信息。

使用LLVM “BSD”许可证

我们积极打算将clang(和LLVM作为一个整体)用于商业项目,不仅作为独立的编译器,而且作为嵌入在专有应用程序中的库。BSD许可证是允许此操作的最简单方法。我们认为许可证鼓励贡献者获取源并使用它,并相信如果他们不想永远维护分支,这些个人和组织将贡献他们的工作(这在合并时耗时且昂贵)涉及)。此外,这些天没有人在编译器上赚钱,但很多人需要他们来实现更大的目标:每个人一起工作是有意义的。

有关LLVM /clang许可证的更多信息,请参阅LLVM许可证说明以获取更多信息。

一个产品级的高质量的编译器

Clang由经验丰富的编译器开发人员设计和构建,他们对现有开源编译器所存在的问题越来越感到沮丧。Clang经过精心设计和构建,为新一代C / C++ / Objective C开发工具奠定了基础,我们打算将其作为生产质量。
作为一个生产质量的编译器意味着很多东西:它意味着高性能,稳定和(相对)无错误,它意味着最终被广泛的人使用和依赖。虽然我们仍处于早期发展阶段,但我们坚信这将成为现实。

一个简单且易于破解的代码库

我们的目标是使任何对C/C++/ObjC语言的编译器和工作知识有基本了解的人能够理解和扩展clang源代码库。很大一部分原因在于我们决定让AST镜像语言尽可能接近:你有友好的if语句,语句,括号表达式,结构,联合等等,都以简单明了的方式表示。
除了简单的设计之外,我们还努力通过对其进行评论来使源基础变得平易近人,包括适当的语言标准引用,以及为简单起见而设计代码。除此之外,clang还提供了一组AST转储程序,打印机和可视化工具,可以轻松放入代码并查看代码的表示方式。

C/C++, Objective C/C++的统一解析器

Clang是“C语言家庭前端”,这意味着我们打算支持C家族中最受欢迎的成员。我们相信,这类语言的正确解析技术是手工构建的递归下降解析器。因为它是普通的C++代码,递归下降使新开发人员很容易理解代码,它很容易支持临时规则和C / C++所需的其他奇怪的黑客攻击,并且可以直接实现出色的诊断和错误复苏。
我们相信,在单个统一解析器中实现C / C ++ /ObjC使得最终结果比维护单独的C和C++解析器更容易维护和发展,解析器必须相互独立地进行修复和维护。

符合C/C++/ObjC及其变体

当您开始实施一种语言时,您会发现语言的工作方式与大多数人理解它的工作方式之间存在巨大差距。这个差距是一个普通的程序员和一个(可怕的?超自然的?)“语言律师”之间的差异,他知道语言的来龙去脉,可以轻松地解决这个问题。

在实践中,符合语言意味着我们的目标是支持完整的语言,包括黑暗和尘土飞扬的角落(如三角形,预处理器奥秘,C99 VLA等)。我们支持超出标准正式允许范围的扩展,我们努力在代码中明确地调用它并发出有关它的警告(默认情况下禁用,但可以选择映射到警告或错误),允许如果你愿意,你可以在“严格”模式下使用clang。

我们还打算支持这些语言的“方言”,如C89,K&R C,C ++’03,Objective-C 2等。