Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Rust编译过程讲解与环境准备

Rust编译过程讲解与环境准备

原创
作者头像
程序饲养员
修改于 2024-01-23 13:55:27
修改于 2024-01-23 13:55:27
73300
代码可运行
举报
文章被收录于专栏:风骚语言Rust风骚语言Rust
运行总次数:0
代码可运行

1.了解编译过程

目前主流编译平台有,GNU、MSVC、LLVM。因为rustc调用了llvm,因此我们以LLVM为例,我们从C语言的编译过程聊,再对比Rust,看它们的编译过程有何差异。

clang下载链接: https://releases.llvm.org/download.html

代码语言:shell
AI代码解释
复制
# 保存编译过程中的临时文件

$ clang -save-temps hello.c 

# 打印编译阶段

$ clang -ccc-print-phases hello.c

            +- 0: input, "hello.c", c -----------> hello.c >

         +- 1: preprocessor, {0}, cpp-output ----> hello.i

      +- 2: compiler, {1}, ir -------------------> hello.bc

   +- 3: backend, {2}, assembler ----------------> hello.s

+- 4: assembler, {3}, object --------------------> hello.o

5: linker, {4}, image ---------------------------> a.exe

第一步:预处理

输入是hello.c,输出是hello.i

代码语言:c
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>

int main() {

    printf("Hello World!\n");

    return 0;

}
代码语言:shell
AI代码解释
复制
# 等价的gcc指令:gcc -E hello.c -o hello.i

$clang -E -c hello.c -o hello.i

# 查看.i文件内容

$cat hello.i

  \_\_attribute\_\_((\_\_format\_\_ (scanf, 2, 0))) \_\_attribute\_\_ ((\_\_nonnull\_\_ (2)))

...

# 1650 "D:/usr/msys2/clang64/include/stdio.h" 2 3

# 2 "hello.c" 2

int main() {

    printf("Hello World!\n");

    return 0;

}

将.i 文件导出为LLVM IR后以备下一步使用

代码语言:shell
AI代码解释
复制
clang -emit-llvm hello.i -c -o hello.bc # 导出二进制的LLVM IR

clang -emit-llvm hello.c -S -o hello.ll # 导出文本类型的LLVM IR

第二部:编译

将预处理完的文件进行一些列的词法分析、语法分析、语义分析和优化后生成的汇编指令代码。

这一步我们就可以使用LLVM的llc命令对上一步的IR文件编译了。

代码语言:shell
AI代码解释
复制
# 等价的gcc指令:gcc -S hello.i -o hello.s

$llc hello.ll -o hello.s
代码语言:shell
AI代码解释
复制
$ cat hello.s

        .text

        .def    @feat.00;

        .scl    3;

        .type   0;

        .endef

        .globl  @feat.00

.set @feat.00, 0

        .file   "hello.c"

        .def    main;

        .scl    2;

        .type   32;

        .endef

        .globl  main                            # -- Begin function main

        .p2align        4, 0x90

main:                                   # @main

.seh\_proc main

# %bb.0:

        pushq   %rbp

        .seh\_pushreg %rbp

        subq    $48, %rsp

        .seh\_stackalloc 48

        leaq    48(%rsp), %rbp

        .seh\_setframe %rbp, 48

        .seh\_endprologue

        callq   \_\_main

        movl    $0, -4(%rbp)

        leaq    .L.str(%rip), %rcx

        callq   printf

        xorl    %eax, %eax

        addq    $48, %rsp

        popq    %rbp

        retq

        .seh\_endproc

                                        # -- End function

        .section        .rdata,"dr"

.L.str:                                 # @.str

        .asciz  "Hello\302\240World!\n"

第三步:汇编

把汇编代码转变成机器可以执行的指令,过程相对编译阶段简单,没有复杂的语法,也不需要优化,只需要对照汇编指令和机器指令对照表一一翻译即可。

代码语言:shell
AI代码解释
复制
#等价的gcc指令:gcc -c add.s -o add.o

clang -fmodules -c hello.s -o hello.o

第四步:链接

目标文件和依赖的库 打包成一个可执行文件

代码语言:shell
AI代码解释
复制
clang hello.o -o hello

链接分为静态链接和动态链接。。

总结

到现在我们就可以回答一个问题:编译器究竟做了什么呢?

首先就是将**源码**转换为目标平台可以直接识别的**指令文件**。分为两类:**可执行文件**和**库**。

在编译最后产生的image,不同操作系统有不同的格式(这里的格式指的是文件的布局结构),在Windows通常是PE,Linux上则是ELF。

ELF格式

现在我们得到了可执行文件,我们在思考可执行文件究竟是什么?

答案就是可执行文件内包含了初始状态的进程数据。

通常可执行文件、目标文件、静态链接库(Linux的.a,Windows的.obj)和动态链接库(Linux的.so,Windows的DLL)都是ELF格式的文件

ELF文件中主要包含程序指令程序数据

ELF的结构:

* File Header 主要包含了文件是否为可执行文件、目标硬件、目标操作系统、段表等。段表描述了各个段在文件中的偏移等信息。

* .text section 代码段

* .data section 数据段

* .bss section 未初始化的全局变量和局部静态变量,在文件中不占空间。

* ...

od -x ./hello # 以16进制查看文件 xxd -b ./hello # 以2进制查看文件 hexdump -C ./hello # 以16进制查看文件 file ./add # 查看文件的头信息 ldd ./add # 查看可执行文件依赖的动态库 objdump -h ./add # 打印ELF文件的各个段 size ./add # 查看ELF各个段的长度 readelf -h ./add # 查看ELF文件的信息 clang -ccc-print-phases hello.c # 查看编译过程

Rust中的编译过程

通过前面的介绍,我们知道LLVM有一个好处,就是将前端和后端通过IR中间语言隔离开了。

这样一来,Rust只需要实现一个前端就可以了。Rust实现的编译器就是rustc.exe,它就包含了rust前端编译器,LLVM和调用连接器。连接器后续极有可能也会使用llvm提供的连接器,目前还是使用mvsc或者GNU的连接器,这也是为什么安装Rust时,需要单独安装vs环境或者gcc环境的原因。

把这个过程说清楚之后,下一节我们来实践安装Rust。

2.安装Rust

如果你只是想体验一下Rust或者快速验证想法可以访问https://play.rust-lang.org

正式的学习和开发还是需要在你的本地安装Rust,这就用到了Rustup。

Rustup是Rust社区提供的工具链管理工具,使用Rustup来安装和管理工具链,并且可以随时切换工具链的版本。访问地址: https://rustup.rs/

在windows11安装Rust

这里以windows11为例,其它版本也是类似。在windows平台有两个版本可供选择:

x86\_64-pc-windows-gnu

x86\_64-pc-windows-msvc

GNU 和 MSVC 都是编译器工具链,它们提供一套工具和库,这些工具和库被用来构建、链接和调试应用程序。Rust使用了它们提供的**连接器**,其实还有第三种选择就是LLVM,我认为Rust最终会在各个平台使用LLVM的**连接器**来取代目前的GNU和MSVC的地位,因为rust编译器在汇编阶段使用的就是LLVM,为了统一起来极有可能会采用LLVM的连接器,但目前这项工作还没有完成。为了获得更好的兼容性和运行效率,我们在windows平台上选择MSVC。

https://www.rust-lang.org/zh-CN/learn/get-started

下面的命令窗口提示,你的电脑缺少vc++环境(连接器和windows api库),也就是需要安装MSVC。

这里我们选择第一项,他会下载vs的安装包。。。等待它下载完成。

下载完成会弹出安装弹框,点击“继续”,接下来会下载安装程序并安装vs。

msvc与windows sdk必须勾选,然后点击“安装”

出现下面界面就说明已经安装成功了,就可以关掉了。

关掉vs,回到cmd继续安装rust,选择第一项默认安装即可。

到这一步下载工具链并设置好PATH环境变量。

当看到上面这个提示就说明已经安装完成了,最后测试rust是否安装成功

代码语言:shell
AI代码解释
复制
# 查看rustup版本

rustup -V

# 查看工具链

rustup show

# 查看cargo版本

cargo -V

# 查看编译器版本

rustc -V

在Linux安装Rust

Hello world

任何一门编程语言的入门都少不了Hello world,我们快速写一个helloworld程序,准备玩起来:

创建一个文件hello.rs

代码语言:rust
AI代码解释
复制
// hello.rs

fn main() {

    println!("Hello, world!");

}

编译并执行:

代码语言:shell
AI代码解释
复制
$ rustc hello.rs

$ .\hello.exe # on Windows

接下来我们需要选择一个趁手的编辑器,目前有vim、vscode和去年jetbrains推出的RustRover,可以根据你的喜好选择。我强烈建议你试用一下RustRover,虽然它还在测试阶段。

https://www.jetbrains.com/rust/

经过上面的步骤,我们已经能愉快开发rust项目。

但是开发项目通常会有一套规范或者说最佳实践,来管理项目依赖和约定目录结构,不至于像早期c/c++每个项目都有一套自己规范。现代语言通常都有的工具,在js中有npm,java中有maven,rust同样提供了类似的工具来管理项目就是cargo。有了cargo我们就可以创建rust package,构建以及发布package到官方仓库。

下面简单演示如何使用cargo新建一个项目:

代码语言:shell
AI代码解释
复制
$ cargo new hello\_world

$ cd hello\_world

$ tree .

.

├── Cargo.toml

└── src

    └── main.rs



1 directory, 2 files

cargo的基本知识在下一节中介绍。

参考和拓展

* 《程序员的自我修养》2.1小节

* rust语言自举,为什么还需要GNU 和 MSVC?

* 为什么go仅仅160M的安装包就可以编译程序?而rust却还需要几个G的msvc才能编译?

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【AI系统】LLVM 架构设计和原理
在上一篇文章中,我们详细探讨了 GCC 的编译过程和原理。然而,由于 GCC 存在代码耦合度高、难以进行独立操作以及庞大的代码量等缺点。正是由于对这些问题的意识,人们开始期待新一代编译器的出现。在本文,我们将深入研究 LLVM 的架构设计和原理,以探索其与 GCC 不同之处。
用户11307734
2024/11/27
3240
从Rustup出发看看Rust语言的编译生态
当你心血来潮想学习Rust这门语言时,一定会用到Rustup来安装Rust。同时你可以会疑问toolchain是啥,target又是啥,为啥学其它编程语言没有这些概念,下面我们就一一解答你的疑问。
程序饲养员
2023/12/27
5030
从Rustup出发看看Rust语言的编译生态
转载:【AI系统】GCC 主要特征
GCC(GNU Compiler Collection,GNU 编译器集合)最初是作为 GNU 操作系统的编译器编写的,旨在为 GNU/Linux 系统开发一个高效的 C 编译器。其历史可以追溯到 1987 年,当时由理查德·斯托曼(Richard Stallman)创建,作为 GNU 课程的一部分。
聊月夜以予星辰
2024/12/11
920
转载:【AI系统】GCC 主要特征
iOS开发你不知道的事-编译&链接
对于平常的应用程序开发,我们很少需要关注编译和链接过程。我们平常Xcode开发就是集成的的开发环境(IDE),这样的IDE一般都将编译和链接的过程一步完成,通常将这种编译和链接合并在一起的过程称为构建,即使使用命令行来编译一个源代码文件,简单的一句gcc hello.c命令就包含了非常复杂的过程!
iOSSir
2019/05/13
5950
mac 使用Clang(Next-gen compiler infrastructure)配置VS Code C/C++环境
如果想使用 gcc 指令来编译执行 C++ 程序,需要在使用 gcc 指令时,手动为其添加
早起的鸟儿有虫吃
2025/01/12
5521
mac 使用Clang(Next-gen compiler infrastructure)配置VS Code C/C++环境
【AI系统】GCC 主要特征
GCC(GNU Compiler Collection,GNU 编译器集合)最初是作为 GNU 操作系统的编译器编写的,旨在为 GNU/Linux 系统开发一个高效的 C 编译器。其历史可以追溯到 1987 年,当时由理查德·斯托曼(Richard Stallman)创建,作为 GNU 课程的一部分。
用户11307734
2024/11/27
1170
gcc常用命令_C语言编译过程几个步骤
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
全栈程序员站长
2022/11/07
5580
gcc常用命令_C语言编译过程几个步骤
编译、链接到载入、运行的大致过程 ----1. 编译
对于需要编译的编程语言(c, c++, java, c# ...高级语言),源码写完后,是无法直接运行的;需要有 编译,链接的过程才能生成最终可以执行的二进制文件;
qsjs
2020/06/08
5210
【Rust日报】2023-11-21 如何将 Rust 的编译效率提高 75%
Rust经常被提到的一个痛点是编译时间较慢。为了享受借用检查器、安全性和零成本抽象等好处,我们需要花费更多时间进行编译。为了测试不同的更改,我们需要建立一个基准。我电脑的配置如下:
MikeLoveRust
2023/11/23
2K0
【Rust日报】2023-11-21 如何将 Rust 的编译效率提高 75%
Hello World背后的故事:如何在Linux上编译C语言程序
C语言的经典程序“Hello World”并不难写,很多朋友都可以闭着眼将它写出来。那么编译一个“Hello World”到底经历了怎样的过程呢?
PP鲁
2020/09/15
2K0
Hello World背后的故事:如何在Linux上编译C语言程序
【C语言系列】C语言编译流程分析
前几天看了《程序员的自我修养——链接、装载与库》中的第二章“编译和链接”,主要根据其中的内容简单总结一下C程序编译的过程吧。 我现在一般都是用gcc,所以自然以GCC编译hellworld为例,简单总结如下。 hello.c源代码如下: #include <stdio.h> int main() { printf(“Hello, world.\n”); return 0; } 通常我们使用gcc来生成可执行程序,命令为:gcc hello.c,默认生成可执行文件a.out 其实编译(包括链接)的命令:g
程序员互动联盟
2018/03/16
11K0
【C语言系列】C语言编译流程分析
用gcc编译c语言程序以及其编译过程
对于初学c语言编程的我们来说,学会如何使用gcc编译器工具,对理解c语言的执行过程,加深对c语言的理解很重要!!!
黑泽君
2018/10/11
1.7K0
【Linux】深度解析与实战应用:GCC/G++编译器入门指南
  在Linux系统中,GCC(GNU Compiler Collection)是极其重要且广泛使用的编译器,它支持多种编程语言,包括C、C++、Objective-C、Java、Fortran等。GCC以其高效、灵活和跨平台的特点赢得了开发者的青睐。本文将详细介绍GCC中的C编译器gcc和C++编译器g++的基本使用方法和编译过程。
大耳朵土土垚
2024/09/25
3590
【Linux】深度解析与实战应用:GCC/G++编译器入门指南
Rust学习笔记之Rust环境配置和入门指南
在前端技术,如雨后春笋般破土而出的今天。其技术偏向性,不仅仅是搞一个新的技术框架,更多的是往高性能和底层技术发展。比方说,利用Rust特性所编写的SWC前端构建工具,目前核心功能相当于 Babel;还有就在2022年10月26日,Vercel 公司正式宣布推出新的打包工具 Turbopack,他们用基于 Rust 的 SWC 替换基于 JavaScript 的转译器 Babel,速度提升了 17 倍。他们还替换了 Terser,压缩的速度提高了 6 倍,从而减少了加载时间和带宽的使用;还有在一些原本只能在客户端运行的程序,现在也被移植到浏览器中运行,例如AutoCAD/Photoshop等,而这些都依赖近期比较热门的WebAssembly技术。
前端柒八九
2022/12/19
1.1K0
Rust学习笔记之Rust环境配置和入门指南
【Rust学习】01_入门
让我们开始您的 Rust 之旅吧!有很多东西要学,但每一段旅程都是从第一步开始的,在本章中,我们将一起来学习以下知识点:
思索
2024/06/24
1640
【Rust学习】01_入门
解密C语言编译背后的过程
我们大部分程序员可能都是从C语言学起的,写过几万行、几十万行、甚至上百万行的代码,但是大家是否都清楚C语言编译的完整过程呢,如果不清楚的话,我今天就带着大家一起来做个解密吧。
Coding十日谈
2020/08/13
8910
解密C语言编译背后的过程
Rust跨平台编译
大家好,我是「柒八九」。一个「专注于前端开发技术/Rust及AI应用知识分享」的Coder
前端柒八九
2024/04/11
1.2K0
Rust跨平台编译
我用 Rust 改写了自己的C++项目:这两个语言都很折磨人!
作者 | Strager 译者 | 马可薇 策划 | 褚杏娟 C++ 漫长的构建时间可谓臭名昭著,编程圈的“我的代码在编译”只是个段子,但 C++ 让这个段子长盛不衰。 谷歌 Chromium 规模的项目在新硬件上的构建时间长达一小时,而在老硬件上的构建时间更是达到了六个小时。虽然也有海量的调整方案能加速构建速度,还有不少削减构建内容但极易出错的捷径供人选择,再加上数千美元的云计算能力,Chromium 的构建时间仍是接近十分钟。这点我完全无法接受,人们每天都是怎么干活的啊? 有人说 Rus
深度学习与Python
2023/03/29
1.6K0
我用 Rust 改写了自己的C++项目:这两个语言都很折磨人!
Linux 程序编译过程的来龙去脉
大家肯定都知道计算机程序设计语言通常分为机器语言、汇编语言和高级语言三类。高级语言需要通过翻译成机器语言才能执行,而翻译的方式分为两种,一种是编译型,另一种是解释型,因此我们基本上将高级语言分为两大类,一种是编译型语言,例如C,C++,Java,另一种是解释型语言,例如Python、Ruby、MATLAB 、JavaScript。
刘盼
2018/09/25
3.1K0
Linux 程序编译过程的来龙去脉
【C语言】C语言 4 个编译过程详解
C语言的编译过程涉及几个关键步骤、概念和细节,每个步骤都有助于将人类可读的源代码转换为可执行的机器码。以下是详细的解释和示例:
LuckiBit
2024/12/07
1.4K0
【C语言】C语言 4 个编译过程详解
相关推荐
【AI系统】LLVM 架构设计和原理
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验