(Xcode) 編譯器小白筆記 - LLVM前端Clang

栏目: IOS · 发布时间: 6年前

内容简介:Apple(包括中后期的NeXT) 一直使用GCC作为官方的编译器。GCC作为开源世界的编译器标准一直做得不错,但Apple对编译工具会提出更高的要求。Clang这个软体专案在2005年由苹果电脑发起,是LLVM编译器工具集的前端(front-end),目的是输出程式码对应的抽象语法树(Abstract Syntax Tree, AST),并将程式码编译成LLVM Bitcode。接着在后端(back-end)使用LLVM编译成平台相关的机器语言 。main.m

Apple(包括中后期的NeXT) 一直使用GCC作为官方的编译器。GCC作为开源世界的编译器标准一直做得不错,但Apple对编译 工具 会提出更高的要求。

Clang这个软体专案在2005年由苹果电脑发起,是LLVM编译器工具集的前端(front-end),目的是输出程式码对应的抽象语法树(Abstract Syntax Tree, AST),并将程式码编译成LLVM Bitcode。接着在后端(back-end)使用LLVM编译成平台相关的机器语言 。

(Xcode) 編譯器小白筆記 - LLVM前端Clang

先看结果

main.m

#import <Foundation/Foundation.h>
#define DEFINEEight 8

int main(){
    @autoreleasepool {
        int eight = DEFINEEight;
        int six = 6;
        NSString* site = [[NSString alloc] initWithUTF8String:"starming"];
        int rank = eight + six;
        NSLog(@"%@ rank %d", site, rank);
    }
    return 0;
}

复制代码

直接编译成执行档

clang -fmodules main.m

产出 .out (executable)

(Xcode) 編譯器小白筆記 - LLVM前端Clang

Clang (Frontend前端)

是一个C、C++、Objective-C和Objective-C++程式语言的编译器前端

Clang源码结构

(Xcode) 編譯器小白筆記 - LLVM前端Clang

Clang步骤

clang -ccc-print-phases main.m

(Xcode) 編譯器小白筆記 - LLVM前端Clang
(Xcode) 編譯器小白筆記 - LLVM前端Clang

1.Input (Driver)

指定语言 , 架构, 输入file

clang -x objective-c main.m

2.Preprocessor(预处理)

import 头文件, include头文件等 ,macro宏展开,处理'#'开头指令

单做预处理, 并取得预处理结果

clang -E main.m

预处理最终结果:

# 1 "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/System/Library/Frameworks/Foundation.framework/Headers/FoundationLegacySwiftCompatibility.h" 1 3
# 185 "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/System/Library/Frameworks/Foundation.framework/Headers/Foundation.h" 2 3
# 2 "main.m" 2


int main(){
    @autoreleasepool {
        int eight = 8;
        int six = 6;
        NSString* site = [[NSString alloc] initWithUTF8String:"starming"];
        int rank = eight + six;
        NSLog(@"%@ rank %d", site, rank);
    }
    return 0;
}

复制代码

依据上面的结果能明显看到 header被换成了明确的全局位置,常量 DEFINEEight 也被替换进代码里,讲到import 就不得不提 modules

2.1 Modules 模块 (-fmodules)

参考LLVM modules文档

文章里提及: Modules provide an alternative, simpler way to use software libraries that provides better compile-time scalability and eliminates many of the problems inherent to using the C preprocessor to access the API of a library.

Clang 以简单的 import std.io 概念取代 原本冗余的函数库(libraries)引进 #include <stdio.h> ,类似 java 的package,目前Clang

  1. #include的机制是 编译器会去递回检查每个Header,header inculde的 header 文章里提了几个弱点: Compile-time scalability :耗时编译 Fragility :多引入顺序或导致宏冲突 Conventional workarounds :C语言长久的息惯,导致代码较丑 Tool confusion

  2. 然而编译器在碰到import时,会直接载入module对应的二进制文件并取得他的api,一个module不依赖外部header,只编译一次,api也只解析一次, 当然module也有些缺点包括 namesspace(可能重名), 改库代码, 无法适应各种机器的Arch。

3 Lexical Analysis (词法分析 Lex, Tokenization) -> .i (Tokens)

此步骤是Compiler里的基本程序,将字符一个一个的读进Lexer里,并根据构词规则识别 Token(单词),此处还不会校验语法

做词法分析并把Token分析结果展示出来

clang -fmodules -fsyntax-only -Xclang -dump-tokens main.m

每一个标记都包含了对应的源码内容和其在源码中的位置。注意这里的位置是宏展开之前的位置,这样一来,如果编译过程中遇到什么问题,clang 能够在源码中指出出错的具体位置。

(Xcode) 編譯器小白筆記 - LLVM前端Clang

-fsyntax-only : Run the preprocessor, parser and type checking stages.

4 语法分析(Semantic Analysis) -> AST

语法分析,在Clang中有Parser和Sema两个模块配合完成,验证语法是否正确,并给出正确的提示。

4.1 Parser

遍历每个Token做词句分析,生成一个 节点( Nodes )该有的资讯

4.2 Semantic

在Lex 跟 syntax Analysis之后, 也就是在这个阶段已经确保 词 句 语法已经是正确的形式了,semantic 接着做return values, size boundaries, uninitialized variables 等检查,之后根据当前的资讯,生成语意节点( Nodes ),并将所有节点组合成抽象语法书( AST )

做 语法分析 并展示 AST

clang -fmodules -fsyntax-only -Xclang -ast-dump main.m

(Xcode) 編譯器小白筆記 - LLVM前端Clang

5 抽象语法树 Abstract Syntax Tree

可以说是Clang的核心,大部分的优化, 判断都在AST处理(例如寻找Class, 替换代码...等)

此步骤会将 Clang Attr 转换成 AST 上的 AttributeList ,能在clang插件上透过 Decl::getAttr<T> 获取

Clang Attributes是 Clang 提供的一种 源码注解 ,方便开发者向编译器表达某种要求,参与控制如 Static Analyzer、Name Mangling、Code Generation 等过程, 一般以 __attribute__(xxx) 的形式出现在代码中, Ex: NS_CLASS_AVAILABLE_IOS(9_0)

结构跟其他Compiler的AST相同与其他编译器不同的是 Clang的AST是由C++构成类似Class,Variable的层级表示,其他的则是以汇编语言编写。

这代表着AST也能有对应的api,这让AST操作, 获取信息 都比较容易,甚至还夹带着地址跟代码位置。

AST Context: 存储所有AST相关资讯, 且提供ASTMatcher等遍历方法

Node三大Class Decl - Declarations(声明), Stmt - Statements(陈述句), type(类型) 子类过于详细不在这多写

(Xcode) 編譯器小白筆記 - LLVM前端Clang

6 代码生成 CodeGen -> IR中间代码(.ll)

CodeGen负责将语法树从顶至下遍历,翻译成LLVM IR,是LLVM Backend 的输入,是前后端的桥接语言。

产出IR: clang -S -fobjc-arc -emit-llvm main.m -o main.ll

LLVM IR 有三种表示格式,第一种是 bitcode 这样的存储格式,以 .bc 做后缀,第二种是可读的以 .ll,第三种是用于开发时操作 LLVM IR 的内存格式。

产出Bit clang -emit-llvm -c main.m -o main.bc

查看BitCode llvm-dis < main.bc | less

6.1 IR 优化 Optimization

IR提供了多种优化选项,-01 -02 -03 -0s.... 对应着不同的入参,有比如类似死代码清理,内联化,表达式重组,循环变量移动这样的 Pass。

(Xcode) 編譯器小白筆記 - LLVM前端Clang
(Xcode) 編譯器小白筆記 - LLVM前端Clang

以上所述就是小编给大家介绍的《(Xcode) 編譯器小白筆記 - LLVM前端Clang》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Linux内核设计与实现(原书第3版)

Linux内核设计与实现(原书第3版)

Robert Love / 陈莉君、康华 / 机械工业出版社华章公司 / 2011-4-30 / 69.00元

《Linux内核设计与实现(原书第3版)》详细描述了Linux内核的设计与实现。内核代码的编写者、开发者以及程序开发人员都可以通过阅读本书受益,他们可以更好理解操作系统原理,并将其应用在自己的编码中以提高效率和生产率。 《Linux内核设计与实现(原书第3版)》详细描述了Linux内核的主要子系统和特点,包括Linux内核的设计、实现和接口。从理论到实践涵盖了Linux内核的方方面面,可以满......一起来看看 《Linux内核设计与实现(原书第3版)》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器