计算机中执行一个文件,经历着「加载、解析、执行、终止」的流程。然而,当需要执行多个相关联的文件时,整个过程又会是怎样的呢?
什么是链接?
链接(linking)将多个代码文件组合在一起,形成一个可执行程序或库的过程。想象一下你有一些拼图碎片,每个碎片都是独立的一部分,这些碎片是不同的形状、颜色和图案,你把这些碎片连接起来的过程,就是「链接」。
计算机的「链接」通过解决代码文件之间的引用关系,将不同模块连接起来,使得程序能够正确执行。
就像拼图中,我们需要找到碎片之间的匹配关系,并将它们正确地连接在一起,只有当所有碎片都连接在一起时,拼图才能呈现出完整的图像。
什么时候执行?
链接最终会生成一个可执行目标文件,这个文件被加载到内存然后执行。
可以执行于「编译时」,也就是在源代码被翻译成机器代码时;
也可以执行于「加载时」,也就是在程序被加载器加载到内存并执行时;
也可以执行于「运行时」,也就是由应用程序来执行。
链接使得分离编译成为可能,我们不用将一个大型的应用程序组织为一个巨大的源文件,而是可以将它分解成更小,更好管理的模块,可以独立地修改和编译这些模块,当我们改变某个模块时,只需要重新编译它,并重新链接应用,而不必重新编译其他文件。
在我们目前的系统中,链接是由叫做链接器(linker)程序自动执行的。
如何编译一个程序?
大多数编译系统提供编译器驱动程序(compiler driver),在 C 语言中,main.c 文件引用了 sum.c 文件里的 sum 方法,所以链接器会把两个文件合成一个「可执行目标文件」
根据上面的图,我们来概括一下将示例程序翻译成可执行目标文件的行为:
C 语言程序的编译过程大致分为四个步骤:预处理、编译、汇编和链接。
在预处理阶段,C 预处理器(cpp)将 C 源程序翻译成一个 ASCII 码的中间文件;
在编译阶段,C 编译器(cc1)将中间文件翻译成一个 ASCII 汇编语言文件;
在汇编阶段,汇编器(as)将汇编语言文件翻译成一个可重定位目标文件;
在链接阶段,链接器程序 ld 将目标文件和一些必要的系统目标文件组合起来,创建一个可执行目标文件。
最后,shell 调用操作系统中一个叫做加载器(loader)的函数,它将可执行文件中的代码和数据复制到内存,然后将控制转移到这个程序的开头,开始执行。
和前端有什么关系?
上面我们聊的是计算机系统的「链接」,和前端有关系么?表面看上去没啥关系,但联想一下前端的开发模式和构建工具「Rollup、Vite、WebPack」,它们之间还是有些相似之处的,比如「模块化、依赖管理、构建优化」等几个方面。
模块化:链接和前端开发都强调模块化的思想,链接是把代码文件组成可执行程序或库,前端开发将代码拆分为独立的组件、模块和库,都是为了更好的组织代码;
依赖管理:链接和包管理器都需要处理模块之间的依赖关系,链接器解决代码之间的引用关系,确保模块可以正确连接到一起,前端通过包管理器「npm、yarn」管理和加载项目所需要的第三方库和模块。
构建优化:链接和构建工具都涉及构建和优化代码的过程,链接器可以进行代码优化,比如:删除未使用的代码、合并重复的代码。构建工具「Rollup、Vite、WebPack」将代码打包、压缩、优化,来提高页面加载性能。
这些相似之处反映了软件开发的通用原则和最佳实践。
题图生成:Pixabay
内容优化:ChatGPT
内容来源:《深入理解计算机系统》
原创文章,作者:小道研究,如若转载,请注明出处:https://www.sudun.com/ask/34472.html