求教彦祖们, c++ 想深入, LLVM 源码有没有学习的必要,怎么学?

2021-05-22 17:43:35 +08:00
 hehedaozuiteng

最近刚刚看完了 《 stL 源码解析》。 想进一步学习一下 c++,之前有个同事推荐我去看 LLVM 的源码。

但是直接上 github 上看源码又有点硬核。

向大佬们请教一下,怎么通过阅读 LLVM 的源码来提高自己 c++的水平。有没有什么系统性的方法或者相关的书推荐的?

2481 次点击
所在节点    问与答
7 条回复
efen
2021-05-22 18:17:09 +08:00
学 cpp 去看 llvm,就和学开车去看发动机制造原理一样
学好 cpp 需要的是不断的练习
纯粹想玩的话就去玩模版元编程🤷‍♂️
kilasuelika
2021-05-23 02:07:53 +08:00
代码主要是给机器看的,不是给人看的。
真要想非常非常深入,那应该去学编译原理一类的。
penguinWWY
2021-05-23 03:18:15 +08:00
LLVM 作为编译框架跟 C++没啥关系(除了它本身是 C++写的之外。。。
可能你同事想说的是 clang ?看 clang 的 AST 或许可以解答一些你对 C++的困惑,但这个也不见得能提高你的 C++水平
James369
2021-05-23 09:18:31 +08:00
我看现在 Go 的趋势很火,冲击了服务器后端,冲击了 JAVA,真有点怕会冲击到 C++。
jones2000
2021-05-23 14:32:53 +08:00
多做项目, 多写代码就可以。
agagega
2021-05-23 20:24:03 +08:00
看 LLVM 有点舍近求远,不过还是有点点用的。LLVM 是一个非常标志性的百万行级别 C++项目,可以学到很多工程化和模块化的经验。
secondwtq
2021-05-23 23:35:41 +08:00
作为做 LLVM 的来说一下吧,学 C++ 看 GCC 更像是“学开车去看发动机制造原理”,GCC 代码是 C 的底子,本身确实“跟 C++ 没啥关系”,LLVM 则是个彻底的现代 C++ 项目

首先,LLVM 早已经不是一个简单的“编译框架”,现在的 LLVM 既可以指狭义的“LLVM Proper”(这词是我自己 coin 的,只是为了区分,社区没这说法),即“基于 LLVM IR,提供优化和代码生成的框架”,也可以指广义的“LLVM Project”,即“以 LLVM Proper 为中心,由 LLVM 社区所管理的一系列项目”,LLVM Project 包含 “LLVM Proper” 编译框架,Clang C/C++/Objective-C/OpenCL/CUDA ... 前端,LLD 链接器,LLDB 调试器,libc++ C++ 标准库,compiler-rt 运行库,llvm-libc C 标准库,Flang Fortran 前端和 MLIR 等一系列项目,一起构成一个 monorepo,但是每个项目的实践都有或大或小的不同

对于一个非编译器相关的开发者而言,我认为 LLVM 最值得学习的是它的基础设施
LLVM 的核心理念之一是“把一切功能封装成一个库”,也就是说 LLVM 本体是“库”。LLVM 会编译出许多 executable,但是这些 executable 绝大多数都是对库的简单 CLI 封装( Clang 除外,因为要与其他编译器兼容,Clang 的 Driver 层做得格外重),也就是说你自己的程序里面也可以调同样的库来实现类似的功能。举个例子,比如 clang 带一个程序叫 clang-rename,实现了“重命名符号”的代码重构操作,但是这个程序只有几百行,功能实际是在 clang/Tooling/Refactoring/Rename 这个库里实现,而这个库又依赖于 Clang 的 Refactoring 库和语义分析库 ... 我自己就利用这个特性做过简单的代码生成小工具: https://github.com/secondwtq/einstein/blob/master/Einstein.cpp
把一切封装为“库”的目的就是最大化复用,也就是说这个理念背后的隐含意思是“基础设施能帮你做的都会尽量帮你做,你只需要写你自己需要的东西就行”
比如说 LLVM 提供了一整套的容器和数据结构,这些基本上都是通用的,很值得一看
LLVM 的若干公用模块大量使用了模板
LLVM 大多数模块都天生非常适合自动化测试,LLVM 也有完整的测试设施,常用的有 gtest 单元测试,LIT 测试和运行时集成测试三级。做编译器经常出现改东边的东西影响到西边的测试的情况,针对这种状况 LLVM 给你准备好了自动更新测试用例的脚本。
作为一个通用的编译器框架,LLVM 支持很多指令集,不同指令集通用的算法(如指令选择、寄存器分配等)被封装成了一个叫做 CodeGen 的库,而针对每一个指令集的支持都是一个单独的模块(前两个月刚有人搞了个 68000 的支持 ...),每一个指令集都需要定义大量的指令,为了解决这个问题,LLVM 搞了一个叫 TableGen 的 DSL 做代码生成,这个东西统一地解决了指令集定义、指令选择、调用约定、微架构细节定义、CLI 选项定义等一系列问题。这么一整套框架做下来,添加新指令集,添加新指令,很大程度上都是重复性工作。

另外,抛开 LLVM 源码来说,学习 C++,不可不学各种新的工具,而 Clang 占据了半壁江山;不可不了解编译器优化,一般非编译器开发者研究优化都是看汇编,也就是看个一头一尾,但是了解 LLVM IR 就能看中间;不可不看 CppCon 等前沿实践,而其中最有趣的之一就是 LLVM 社区大佬 Chandler Carruth 的基于自己开发经验的系列演讲

不足的地方:
LLVM 作为传统的编译器(也就是说还是主要面向 C/C++)整体设计并没有偏离传统太多,后果之一是里面跟多线程有关的东西很少(因为传统编译器不需要这玩意,直接多进程点到为止就行了),还有一堆全局状态,学这方面的你得另请高明
编译时间太 TM 长 ... 普通 PC 少说半小时吧,我用服务器也得 10 分钟,而且还很大,GCC 就很快(但是好处是需要的依赖很少,只是吃 CPU 而已,基本不用折腾,浏览器则是真正的 worst case,代码量和依赖都很多)
说是把所有东西都做成了库,实际上不同的库之间是互相依赖的,加起来光库就有好几十 M,也就是说很难做到单独拿出一个东西能用。这个理念的意义更主要还是在于,只要你依赖了 LLVM,里面的东西可以随便单独拿出来调用——但是前提是你依赖了 LLVM,这个逻辑就好像“你如果入了苹果的坑,很多东西都会看上去很好(之所以‘看上去很好’是因为金玉其外败絮其中),但是你必须听苹果的话”( GitHub 上甚至有人做把 LLVM 项目里面特定模块单独拎出来的项目)
如果你是 LLVM 的用户,你会发现它的 API 也不是很稳定,很多老项目都直接钉死某一个 LLVM 版本,因为维护成本不低(这进一步说明了 LLVM 的“现代性”:写程序一把梭,刷版本号就得了)

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/778561

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX