V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
hehedaozuiteng
V2EX  ›  问与答

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

  •  
  •   hehedaozuiteng · 2021-05-22 17:43:35 +08:00 · 2490 次点击
    这是一个创建于 1289 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

    7 条回复    2021-05-23 23:35:41 +08:00
    efen
        1
    efen  
       2021-05-22 18:17:09 +08:00 via iPhone   ❤️ 2
    学 cpp 去看 llvm,就和学开车去看发动机制造原理一样
    学好 cpp 需要的是不断的练习
    纯粹想玩的话就去玩模版元编程🤷‍♂️
    kilasuelika
        2
    kilasuelika  
       2021-05-23 02:07:53 +08:00 via Android
    代码主要是给机器看的,不是给人看的。
    真要想非常非常深入,那应该去学编译原理一类的。
    penguinWWY
        3
    penguinWWY  
       2021-05-23 03:18:15 +08:00
    LLVM 作为编译框架跟 C++没啥关系(除了它本身是 C++写的之外。。。
    可能你同事想说的是 clang ?看 clang 的 AST 或许可以解答一些你对 C++的困惑,但这个也不见得能提高你的 C++水平
    James369
        4
    James369  
       2021-05-23 09:18:31 +08:00
    我看现在 Go 的趋势很火,冲击了服务器后端,冲击了 JAVA,真有点怕会冲击到 C++。
    jones2000
        5
    jones2000  
       2021-05-23 14:32:53 +08:00
    多做项目, 多写代码就可以。
    agagega
        6
    agagega  
       2021-05-23 20:24:03 +08:00
    看 LLVM 有点舍近求远,不过还是有点点用的。LLVM 是一个非常标志性的百万行级别 C++项目,可以学到很多工程化和模块化的经验。
    secondwtq
        7
    secondwtq  
       2021-05-23 23:35:41 +08:00   ❤️ 2
    作为做 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 的“现代性”:写程序一把梭,刷版本号就得了)
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   916 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 20:34 · PVG 04:34 · LAX 12:34 · JFK 15:34
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.