最近经常遇到有些朋友问题我如何学习编译器等各类底层的知识。
这些问题的背后是很多程序员对自我提升的强烈需求。
今天,笔者会通过分享“2020年最后一天的学习完整记录”的方式解答这个问题。
注意:本文是分享自我提升技巧,所以遇到不懂的技术名词,可以直接跳过。
“初识是一个被灌输知识的过程。
当我们看博客或者书籍时,都会遇到一些新知识。这就是初识。
今天,笔者从 百度App Objective-C/Swift 组件化混编之路(二)- 工程化 时,就被灌输了一个”新知识“:module 会供链接器使用 。
下面截取部分原文:
“1.2 Module 化 1.2.1 基本概念
“思考 是一个主动消化知识的过程。
思考 的方式有很多:
当我看到上面的”新知识“时,就会想:
“探索 是一个手动进行研究的过程。
探索 过程非常依赖我们的思考能力和记忆能力。
下面是笔者对 module
的一些思考:
每一次思考都需要我们把记忆能力充分调用:
通过上面的初步思考,我决定通过创建 Demo 的方式对 module 会供链接器使用 进行验证。
image-15402758
Demo 工程会有一个名为 Host
的 APP,同时该 App 会依赖名为 FrameW
的动态库和其它系统库。
项目的整体架构如下图:
通过 xcodebuild
命令,可以对 Host
进行构建。
如下,红框部分是 Xcode 执行 链接 Host
时,所调用的命令:
image-20521724
通过仔细分析上面的完整 命令 信息,我们没有发现与 module
明显相关的参数,所以,我们可以大胆猜测: module 与链接器没有关系。
考虑到编译器可能通过其它方式进行了信息传递,所以,我们通过给上述命令添加参数 -v
的方式进行调试。
image-20917926
很遗憾,新增参数 -v
后,仍然没有得到有效的信息。但是,我们得到了一个新的知识 clang
会调用 ld
命令执行链接任务。
接着,我们再次尝试对 ld
命令添加参数 -v -t
的方式进行调试。
这次的信息量十足:
.o
路径被完整的打印出来了FrameW
路径被打印出来了image-21201007
现在局面很清晰了,ld
与 FrameW
的交互是通过上面日志中的 FrameW.framework/FrameW
文件完成的。如果我们能够证明 FrameW.framework/FrameW
文件与 module
没有关系,就可以证明 ”module 与链接器没有关系“。
下面,我们将依次分析 module
文件与 FrameW.framework/FrameW
文件,并将两者对比。
“如果对某些细节比较好奇,可以在公众号底部留言,我们后续再分享
module
内幕相关的知识。
首先,我们进行编译任务时,会发现有一个名为 -fmodules-cache-path
的参数,该参数的值是一个路径ModuleCache
:
-fmodules-cache-path=/var/folders/4j/jqzrrjzn0nvgm4pyxrqddxnmm530jm/C/org.llvm.clang.xxxx/ModuleCache
cd
命令切到该文件夹find
命令配合 grep
找到 FrameW-xxx.pcm
file
命令,得知该文件是 Mach-O
文件otool -l
grep
sort
,我们发现该文件最大的一个 section
体积是 0x000000000000d318
0x000000000000d318
配合 otool -l
和 grep -B 3
,我们知道它属于 __CLANG __clangast
部分segedit
命令将该部分导出到单独文件file
,我们了解到该文件属于 data
xxd
和 head
命令,我们可以得到 magic number
是 CPCH
image-24230541
CPCH
和 llvm
源码,我们可以判断这是 AST/PCH file magic numberimage-30138062
另外,结合 llvm
源码的 llvm::Error GlobalModuleIndexBuilder::loadModuleFile
内部逻辑,我们可以确认这个就是 动态库module 进行编译后的产物
image-30220599
通常上面的思考,我们可以得到以下结论:module
通常会被编译为单独的 mach-o
文件,该文件主要负责在 section:__CLANG __clangast
存储编译后的 ast
文件。
而 ld
链接的动态库 FrameW.framework/FrameW
是 Mach-O 64-bit dynamically linked shared library arm64
文件
通过上面两种文件的特征,我们可以证明 module 与链接器没有关系。
“考虑到很多情况,我们没法找到各种命令行工具进行分析,所以,下面介绍一份搜索引擎版本的探索流程
ld
注意:
“总结 是对整个学习成果的强化过程。
通过 ”初识“-”思考“-”探索” 三部曲,我们会学到很多知识。
不幸的是,人类的大脑很容易遗忘知识。所以,我们需要一些技巧将记忆强化。
总结 的方法有很多种,其中最高效的方案就是 费曼技巧。
费曼技巧 是一种「以教为学」的学习方式,通过直白浅显的语言把复杂深奥的问题和知识传授给 小孩子 的方式进行学习。
但是,费曼技巧 需要一个倾听者才会有很好的学习效果。所以,我个人更加推荐将 学习笔记公开。
当我们选择将笔记发到公众号或者个人博客时,就会强迫自己将整篇文章的知识理顺,避免错误、遗漏。同时,也会有更多的同行帮我们 指出问题。
请记住,只有当我们把相关的知识点完整串联和记忆后,我们才能真正 超越自己,才能真正的 自我提升。
本文通过一次完整的学习经历分享了 “如何自我学习/提升”的问题。
整体的思路如下:
除了本文分享的知识外, 百度App Objective-C/Swift 组件化混编之路(二)- 工程化 还有很多的知识或者疑惑点值得研究,下面简单的列举几个,欢迎读者进行补充。
.tbd
是文本类型,为什么原作者会认为 dynamic_library
的扩展名是 .tbd
“import C
,导致 swiftmodule 中也明确标记了 import C
,当组件 A import B
时,也同时 import C
,如果组件 A 找不到组件 C 的 module,那组件 A 将编译失败。