diff --git a/README.md b/README.md index 939614830..87787769a 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,10 @@ hey~,我是科科人神,目前就职于国内一家互联网公司,你们 - [栈内存管理](./runtime/栈内存管理) - [系统监控](./runtime/系统监控) - [netpool](./runtime/netpool) +## 编译器 +- [gc](./编译器/gc) +- [llvm](./编译器/llvm) +- [gccgo](./编译器/gccgo) ## 工程 - [go 编程范式/设计模式](./工程/go编程范式/README.md) - [包管理工具](./工程/包及其构建工具) diff --git a/changelog.config.js b/changelog.config.js index a13044ebd..6af824292 100644 --- a/changelog.config.js +++ b/changelog.config.js @@ -2,7 +2,7 @@ * @Author: shgopher shgopher@gmail.com * @Date: 2023-05-06 12:20:49 * @LastEditors: shgopher shgopher@gmail.com - * @LastEditTime: 2023-05-06 13:13:05 + * @LastEditTime: 2023-11-17 12:41:29 * @FilePath: /GOFamily/changelog.config.js * @Description: * @@ -15,7 +15,7 @@ module.exports = { maxMessageLength: 64, minMessageLength: 3, questions: ['type', 'scope', 'subject', 'body', 'breaking', 'issues', 'lerna'], - scopes: ['basic','root','all','runtime','concurrency','project','.vuepress','.github'], + scopes: ['basic','root','all','runtime','compiler','concurrency','project','.vuepress','.github'], types: { chore: { description: 'Build process or auxiliary tool changes', diff --git "a/\345\267\245\347\250\213/\351\224\231\350\257\257\345\244\204\347\220\206/README.md" "b/\345\267\245\347\250\213/\351\224\231\350\257\257\345\244\204\347\220\206/README.md" index 304be8acb..0547f45df 100644 --- "a/\345\267\245\347\250\213/\351\224\231\350\257\257\345\244\204\347\220\206/README.md" +++ "b/\345\267\245\347\250\213/\351\224\231\350\257\257\345\244\204\347\220\206/README.md" @@ -2,7 +2,7 @@ * @Author: shgopher shgopher@gmail.com * @Date: 2022-11-17 20:40:42 * @LastEditors: shgopher shgopher@gmail.com - * @LastEditTime: 2023-11-16 21:20:57 + * @LastEditTime: 2023-11-16 22:01:32 * @FilePath: /GOFamily/工程/错误处理/README.md * @Description: * @@ -578,15 +578,15 @@ func Countlines(r io.Reader)(int,error){ // 代码看起来也是很合理的样子,也很简洁,但是,我们其实用的函数不是特别的合适 //其实这里使用 scan 更加合适,代码量更加精简,并且结构异常舒服 -func Countlines(r io.Reader) (int,error){ - +func Countlines(r io.Reader) (int,error){ sc := bufio.NewScanner(r) lines := 0 for sc.Scan() { lines++ } - return lines,sc.Err() + + return lines, sc.Err() } ``` diff --git "a/\347\274\226\350\257\221\345\231\250/README.md" "b/\347\274\226\350\257\221\345\231\250/README.md" new file mode 100644 index 000000000..676f56fd1 --- /dev/null +++ "b/\347\274\226\350\257\221\345\231\250/README.md" @@ -0,0 +1,36 @@ + +# go 编译器 +## 编译器概述 +默认编译器 gc 介绍 +编译原理和过程 +编译器组件工具链 +编译优化技术 +## 编译器特性 +编译速度快 +生成自包含可执行文件 +内存安全保证 +跨平台支持 +模块化支持 +## 编译器实战 +常见编译错误和解决方法 +编译参数和定制 +增量编译 +hook 编译过程 +交叉编译 +## 编译器源码 +gc 编译器源码解析 +编译器前端实现 +编译器后端实现 +## 其他编译器 +gccgo +gollvm +编译器比较 \ No newline at end of file diff --git "a/\347\274\226\350\257\221\345\231\250/gc/README.md" "b/\347\274\226\350\257\221\345\231\250/gc/README.md" new file mode 100644 index 000000000..c0a7b6a33 --- /dev/null +++ "b/\347\274\226\350\257\221\345\231\250/gc/README.md" @@ -0,0 +1,18 @@ +# go 语言官方编译器 gc + +Go 语言默认的编译器全称是 gc,它是 Go 语言官方实现的编译器,主要功能包括: + +- gc - Go 语言编译器前端,负责分析和转换 Go 语言源代码。 +- ssa - 生成静态单赋值 (SSA) 中间表示。 +- scheduler - 根据依赖关系安排指令执行顺序。 +- linker - 链接程序依赖的库。 +- runtime - Go 运行时,提供垃圾回收,并发等功能。 +- assembler - 将汇编指令转换为机器码。 + +gc 编译器由 Go 语言的创造者 Robert Griesemer、Rob Pike 及 Ken Thompson 开发,首次在2007年与 Go 一起开源发布。 + +gc 实现了对 Go 语言的完整支持,可以编译包括复杂特性如 goroutine、channel 和接口在内的所有 Go 语言程序。它输出自包含的可执行文件,不需要外部依赖。 + +gc 编译器写在 Go 语言本身并采用了 Go 的并发特性,编译速度非常快。它与 Go 的发布周期同步,确保语言 feature 得到及时支持。 + +所以 Go 语言默认编译器的全称就是 gc,它是官方提供的 Go 语言编译器。 \ No newline at end of file diff --git "a/\347\274\226\350\257\221\345\231\250/gccgo/README.md" "b/\347\274\226\350\257\221\345\231\250/gccgo/README.md" new file mode 100644 index 000000000..61e112aed --- /dev/null +++ "b/\347\274\226\350\257\221\345\231\250/gccgo/README.md" @@ -0,0 +1,15 @@ +# gccgo +gccgo 是 Gо 语言到 C 语言的编译器,它将 Gо 语言源代码编译成 C 语言源代码。 + +gccgo 本身只是一个编译器前端,负责解析 Gо 语言代码并生成 C 语言代码。要生成最终的可执行文件,还需要一个编译器后端。 + +gccgo 常见的后端有: + +gcc - GNU 编译器,可以将 gccgo 生成的 C 语言代码进一步编译成机器代码,生成最终的可执行文件。 +clang - LLVM 编译器,同样可以将 C 语言编译成机器代码。 +tcc - Tiny C Compiler,一个小型快速的 C 语言编译器。 +所以简单来说,gccgo 编译器的常见后端是 gcc 和 clang。完整的编译流程是: + +gccgo 前端 → C 语言代码 → gcc/clang 后端 → 机器代码 (可执行文件) + +开发者可以根据需要选择不同的编译器后端,来编译 gccgo 生成的 C 语言代码。 \ No newline at end of file diff --git "a/\347\274\226\350\257\221\345\231\250/llvm/README.md" "b/\347\274\226\350\257\221\345\231\250/llvm/README.md" new file mode 100644 index 000000000..214934abf --- /dev/null +++ "b/\347\274\226\350\257\221\345\231\250/llvm/README.md" @@ -0,0 +1,60 @@ + +# llvm +LLVM 可以通过以下两种主要方式为 Go 语言代码提供编译支持: + +## gollvm +gollvm 项目实现了将 Go 代码编译为 LLVM IR 的 frontend。它可以直接生成 LLVM IR,然后通过 LLVM 进行后端代码生成。 + +主要步骤是: + +- gollvm 解析 Go 代码,生成对应的 LLVM IR +- 执行 LLVM 优化流水线进行优化 +- LLVM 后端生成目标平台的机器码 +- 嵌入 LLVM pass +## 可以通过修改 Go Compiler 工具链,在编译过程中调用 LLVM Pass 执行优化。 + +主要步骤是: + +- Go Compiler 前端生成 initial IR +- 将 IR 传递给 LLVM Pass 执行优化 +- LLVM Pass 输出优化后的 IR +- Go Compiler 后端根据 IR 生成机器码 + +这种方式需要 invasive 修改 Go 编译器,较为复杂。 + +总结: + +gollvm 通过完全 External 的方式引入 LLVM,而嵌入 LLVM Pass 需要修改 Go Compiler。 + +gollvm 方式集成更简单,但是需要保证 IR 的转换正确性;嵌入 Pass 可以利用 Go Compiler 的 Context 信息进行更准确的优化。 + +根据需求和成本进行抉择。 +## llvm -golang +llvm-golang 是另一个用于 Go 语言编译的 LLVM 集成项目。 + +它与 gollvm 的主要区别有: + +实现方式不同 +- gollvm 是独立的 Go frontend,将 Go 代码编译成 LLVM IR +- llvm-golang 直接使用 LLVM 对 Go 代码进行编译 +编译入口不同 +- gollvm 通过调用 gollvm 命令,传入 Go 源文件 +- llvm-golang 编译时调用 clang 命令,并使用-femulate-llvm-golang 参数 +编译过程不同 +- gollvm 编译生成完整的 LLVM IR 然后优化 +- llvm-golang 是逐函数生成 LLVM IR 并编译 +项目状态不同 +- gollvm 活跃维护,可正常使用 +- llvm-golang 最后更新在5年前,未维护 +总之,llvm-golang 是直接使用 LLVM 编译 Go 的早期尝试,但维护情况不佳。gollvm 作为独立 frontend 集成 LLVM,是更可靠的解决方案。 + +但 llvm-golang 的直接编译方式也具有借鉴意义,合理结合两种方式可以获得更好的 LLVM 集成效果。