使用Rust开发编译系统(C以及Rust编译的过程)
C以及Rust编译的过程
- 主流的编译器
- GCC
- LLVM
- C语言编译过程
- LLVM编译过程
- 将C源码转为LLVM IR
- 将IR转化为BitCode
- 将BitCode转为目标平台汇编码
- 执行BitCode
- Rust编译过程
- 下一步做什么
主流的编译器
GCC
GCC编译器是由GNU开发的编译器,原名为GUN编译器,原本只能处理C语言随着发展,后续支持了C++,Java,Go等语言,所以改名为GNU编译器套件,GCC主要分为以下接口
- 前端接口: 将源码经过词法分析,语法分析生成与语言无关的低级中间语言表示层,然后经过优化后转化为RTL中间表示层
- 中间接口: 中间接口主要在RTL中间表示上进行各种优化,如循环优化,公共子表达式删除,指令重排等等
- 后端接口:GCC对每条RTL通过模板匹配方法调用对应的汇编模板生成汇编代码,生成的代码因处理器的不同而不同
LLVM
LLVM由C++编写,用于优化任意语言编写的程序,LLVM的命名最早源于Low Level Virtual Machine的缩写,LLVM代码有3种表示形式,IR,bitcode,汇编码,llvm提供了不同的优化Pass,对每个Pass的源码编译,得到一个Object文件,之后这些文件链接得到一个库,Pass之间由LLVM Pass管理器来统一管理
LLVM有很多其项目其中包括 LLVM Core libraries
,Clang
,LLD
,LLDB
,libc++ & libc++ ABI
等等
C语言编译过程
一般的编译过程流程图大概是这样的
但是不同的编译器有着不同的编译方式,下面我们使用LLVM对C语言编译的过程进行实践
LLVM编译过程
我们开始准备LLVM的一些环境
- llvm
- llvm-as(Windows 安装llvm时没有这个文件,打开网站后输入llvm-as.exe搜索下载)
- llc (同llvm-as)
首先我们创建一个test.c文件然后输入以下内容
int mult() {int a = 5; int b = 3; int c = a * b;return c;
}
将C源码转为LLVM IR
输入一下命令
clang -emit-llvm -S test.c -o test.ll
其中我们使用了clang
作为前端进行编译,-emit-llvm
用于LLVM IR写到.ll文件,-S
表示仅运行预处理和编译步骤,-o
参数用于将生成的内容输出到test.ll
文件中
执行完毕后会在test.c同级目录下生成一个test.ll
文件,将C语言代码分解为Token流(每个Token可表示标识符,字面量,运算符等等),Token流会传递给语法分析器,语法分析器使用CFG
(上下文无关文法)组织成AST
(抽象语法树),紧接着进行语义分析,然后生成IR
将IR转化为BitCode
我们使用一个较为简单的IR文件,内容如下
// test.ll
define i32 @mult(i32 %a, i32 %b) #0 { %1 = mul nsw i32 %a, %b ret i32 %1
}
使用命令如下
llvm-as test.ll -o test.bc
我们使用llvm-as
(LLVM汇编器)将LLVM IR
转为BitCode
,-o
参数用于将生成的BitCode输出到test.bc文件中
将BitCode转为目标平台汇编码
我们使用LLVM的静态编译器LLC把BitCode转为汇编码,命令如下
llc test.bc -o test.s
或者我们可以使用Clang从BitCode文件生成汇编码,命令如下
clang -S test.bc -o test.s -fomit-frame-pointer
我们使用了fomit-frame-pointer
参数消除帧指针,因为Clang默认不消除帧指针,但是llc却默认消除帧指针
llc命令把LLVM的BitCode编译为指定架构的汇编语言,如果命令中没有指定任何架构默认生成的本机汇编码
执行BitCode
我们把test.c的内容换为以下内容
#include<stdio.h> int main(){int num = 5; printf("number is %d\n", num); return 0;
}
然后我们按照之前的步骤将test.c转为BitCode
$ clang -emit-llvm -S test.c -o test.ll
$ llvm-as test.ll -o test.bc
注: 在Windows执行第2步是会出现以下错误
llvm-as: test.ll:31:62: error: expected ‘global’ or ‘constant’
@"??_C@_0O@BAPFBKAP@number?5is?5?CFd?6?CFd?6?CFd?6?AA@" = linkonce_odr dso_local unnamed_addr constant [14 x i8] c"number is %d\0A\00", comdat, align 1
错误原因等待解决
最后我们使用LLI
命令来运行BitCode
$ lli test.bc
LLI
使用LLVM bitcode格式 作为输入并且使用即时编译器(JIT)执行,如果当前的架构不 存在JIT编译器,会用解释器执行
Rust编译过程
Rust使用的是rustc
进行编译,编译的过程如下
详细过程如下
- 解析输入:将
.rs
文件作为输入并进行解析生成AST
(抽象语法树) - 名称解析,宏扩展和属性配置:解析完毕后处理
AST
,处理#[cfg]
节点解析路径,扩展宏 - 转为HIR:名称解析完毕后将AST转换为
HIR
(高级中间表示),HIR比AST处理的更多,但是他不负责解析Rust的语法,例如((1+2)+3)
和1+2+3
在AST中会保留括号,虽然两者的含义相同但是会被解析成不同的树,但是在HIR中括号节点将会被删除,这两个表达式会以相同的方式表达 - 类型检查以及后续分析:处理HIR的重要步骤就是类型检查,例如使用
x.f
时如果我们不知道x
的类型就无法判断访问的哪个f
字段,类型检查会创建TypeckTables
其中包括表达式的类型,方法的解析方式 - 转为MIR以及后置处理:完成类型检查后,将HIR转为MIR(中级中间表示)进行借用检查以及优化
- 转为LLVM IR和优化:LLVM进行优化,从而生成许多
.o
文件 - 链接: 最后将那些
.o
文件链接在一起
我们开始实践这一过程
首先我们创建一个Cargo项目
~$ cargo new complier_test
main.rs
文件中的内容如下
fn main(){println!("Hello");
}
将源代码转为HIR
我们可以使用cargo的 -Zunpretty参数来生成hir,rustc命令没有找到。。
~/complier_test$ cargo rustc -- -Zunpretty=hir-tree -o main.hir
然后在src目录下会生成main.hir文件
将源代码转为MIR
转为mir的过程我们可以使用rustc来完成
~/complier_test/src$ rustc --emit mir -o main.mir main.rs
我们使用emit来生成emit
用来生成mir,除此之外还可以使用emit来生成LLVM IR
~/complier_test/src$ rustc --emit llvm-ir -o main.ll main.rs
转换为BitCode
然后我们可以使用llvm-as
将IR转为BitCode
~/complier_test/src$ llvm-as main.ll -o main.bc
或者我们可以使用rustc的emit参数生成
~/complier_test/src$ rustc --emit llvm-bc -o main.bc
最后我们可以使用LLI
来运行BitCode
~/complier_test/src$ lli main.bc
下一步做什么
在下一篇文章我们使用Rust实现一个分词器,我们还需要掌握一些关于分词的理论知识
使用Rust开发编译系统(C以及Rust编译的过程)相关推荐
- c语言程序链接过程,C语言简明教程(二):C程序编译链接过程和实例对照详解...
不像高级编程语言,在C语言开发中,了解其编译链接过程显得相对重要,因为C语言是较为底层的语言,很多时候我们调试C程序或者解决其它问题都可能会涉及到C编译链接的相关知识,例如编译动态库或者静态库.下面我 ...
- [译]使用 Rust 开发一个简单的 Web 应用,第 4 部分 —— CLI 选项解析
原文地址:A Simple Web App in Rust, Part 4 -- CLI Option Parsing 原文作者:Joel's Journal 译文出自:掘金翻译计划 本文永久链接:g ...
- 百度安全 TrustZone SDK 正式成为 OP-TEE 官方推荐 Rust 开发环境
百度安全与 OP-TEE 社区共同合作,推进 Teacalve TrustZone SDK 正式成为 OP-TEE 官方推荐的 Rust 开发环境.OP-TEE 是当今广泛使用的开源 ARM Trus ...
- rust开发环境_Rust 环境搭建
Rust 环境搭建 Rust 支持很多的集成开发环境(IDE)或开发专用的文本编辑器. 本教程将使用 Visual Studio Code 作为我们的开发环境(Eclipse 有专用于 Rust 开发 ...
- 用 Rust 开发 Linux,可行吗?
作者 | 马超 出品 | CSDN(ID:CSDNnews) 继Python之后,Rust最近也火爆得出了圈,目前Rust在Serverless等很多云原生领域已经稳定占据了C位,那么让Rust更进一 ...
- rust开发环境_Rust开发环境搭建
1.Rust概述 按照百度百科的说法,Rust是一门系统编程语言 ,专注于安全 ,尤其是并发安全,支持函数式和命令式以及泛型等编程范式的多范式语言.Rust在语法上和C++类似 ,但是设计者想要在保证 ...
- mac10.11+vim rust开发环境搭建
mac10.11+vim rust开发环境搭建 1.安装rust 打开终端 输入如下命令 curl -sf -L https://static.rust-lang.org/rustup.sh | sh ...
- Rust开发调试环境搭建Windows
Rust Windows环境搭建 2019年02月18日 13:48:31 6日Simmp 阅读数 1672 该文章主要讲述在windows10+vscode下如何构建一个完整的rust编译调试环境, ...
- ios 腐蚀rust手游_用 Rust 开发 iOS 应用(粗糙版)
把环境搞定 在搞事情之前, 我们先把 Rust 环境配好, 这个很简单, 直接用官网的这条命令. curl https://sh.rustup.rs -sSf | sh 复制代码 随便装一个版本, 稳 ...
最新文章
- 努力过头了,其实并不好
- LeetCode 295. 数据流的中位数(大小堆)
- cocos 制作动态生成内容的列表_零代码工具,让你在线轻松制作交互内容!
- (转)C++优先队列中元素及结构体的排序
- wince6.0远程控制工具_用微信远程控制你的电脑,这个工具又加了一些小功能(硬件+软件)...
- 面试题|集合ArrayList list = new ArrayList(20) 中的list扩充几次?
- 金蝶计算机会计实验报告总结,会计实训总结(精选5篇)
- 如何注册电子邮箱账号,教你创建email邮箱账号
- Django+bootstrap启动登录模板页面(Django第三篇)
- seo关键词优化技巧是什么
- 如何区分自己mac电脑的CUP型号
- ggalluvial:冲击图展示组间变化、时间序列和复杂多属性alluvial diagram
- destoon7.0第三方短信插件下载 destoon7.0整合云信通短信平台教程
- 【kali-漏洞利用】(3.4)Metasploit渗透攻击应用:MySQL渗透过程
- 计算机毕业设计php+vue基于微信小程序的叽喳音乐播放小程序
- 简单保护动物网页制作stu-works.com学生保护动物网页设计作品HTML 濒危动物静态网页成品下载
- 一粒云文控模块使用心得
- 打造爆文的8个软文营销写作技巧,提升你的文案写作能力
- Outlook Express邮件丢失的原因
- Android行业薪资现状,月薪2万属于低收入!
热门文章
- idea license server 最新可用 IntelliJ IDEA 2018.1 x64 激活 idea license server
- 【Linux】 常用命令
- 深度暗色调色效果Lr预设
- knex入门学习使用方法
- 计算机考研复试面试问题总结和回答
- FFmpeg从入门到入魔(2):保存流到本地MP4
- 华为路由器显示连接到服务器失败怎么办,华为路由WS5200可以搜到wifi但无法连接怎么办...
- mysql查询数据量
- g.SetGDIHigh()错误
- 史上最佳十大游戏排名 魔兽世界位列第十