为什么首先编译为目标文件?

tom*_*fer 31 c c++ fortran compilation object-files

在去年,我开始在Fortran开设编程,在一所研究型大学工作.我之前的大部分经验都是使用PHP或旧ASP等网络语言,所以我是编译语句新手.

我有两个不同的代码我正在修改.

其中 有一个明确的声明创建的.o从模块文件中创建可执行文件之前(如gfortran -c filea.f90).

另一个直接创建可执行文件(有时创建.mod文件,但没有.o文件,例如gfortran -o executable filea.f90 fileb.f90 mainfile.f90).

  • 是否有一种理由(除了,也许是Makefiles)一种方法比另一种方法更受欢迎?

kri*_*iss 29

首先编译为目标文件称为单独编译.有许多优点和一些缺点.

好处:

  • 易于将目标文件(.o)转换为库并稍后链接到它们
  • 许多人可以同时处理不同的源文件
  • 更快的编译(当源未更改时,您不会再次编译相同的文件)
  • 目标文件可以从不同的语言源创建,并在以后的某个时间链接在一起.为此,目标文件只需使用相同的格式和兼容的调用约定.
  • 单独编译可以分布系统范围的库(OS库,语言标准库或第三方库)静态或共享.

缺点:

  • 有一些优化(比如优化函数)编译器无法执行,链接器也不关心; 但是,许多编译器现在都包含执行"链接时间优化"的选项,这在很大程度上抵消了这个缺点.但这对于系统库和第三方库来说仍然是一个问题,特别是对于共享库(不可能优化掉每次运行时可能发生变化的组件部分,但是其他技术,如JIT编译可能会缓解这种情况).
  • 在某些语言中,程序员必须提供某种标题,供其他与此对象链接的标题使用.例如,在C中,您必须提供.h与目标文件一起使用的文件.但无论如何这是好习惯.
  • 在基于文本的语言中包括C或C++,如果更改函数原型,则必须在两个位置进行更改.一旦进入头文件,一旦进入实现文件.

  • 实际上,一些链接器可以在汇编级别执行内联或其他优化. (2认同)
  • 有可以跨目标文件优化的编译器.较新的VC版本可以做到这一点.不过,一个很好的答案,"+ 1"来自我. (2认同)
  • @ybungalobill,模板?在fortran?!? (2认同)

Eri*_*rik 14

如果项目包含几百个源文件,则每次更改时都不希望重新编译所有这些文件.通过将每个源文件编译为单独的目标文件并仅重新编译受更改影响的源文件,您可以花费从源代码更改到新可执行文件的最短时间.

make是用于跟踪此类依赖关系的常用工具,并在某些更改时重新创建二进制文件.通常,您可以设置每个源文件所依赖的内容(这些依赖项通常由编译器生成 - 以适合的格式make),并让make处理创建最新二进制文件的详细信息.


Wil*_*ung 5

.o文件是对象文件.它是最终节目的中间代表.

具体来说,通常,.o文件具有已编译的代码,但它没有的是所有不同例程或数据的最终地址.

程序在运行之前需要的东西之一就是内存映像.

例如.

如果你有你的主要程序并且它调用例程A.(这是人造堡垒,我几十年没有碰过,所以在这里和我一起工作.)

PROGRAM MAIN
INTEGER X,Y
X = 10
Y = SQUARE(X)
WRITE(*,*) Y
END
Run Code Online (Sandbox Code Playgroud)

然后你有SQUARE功能.

FUNCTION SQUARE(N)
SQUARE = N * N
END
Run Code Online (Sandbox Code Playgroud)

这些是单独编译的单位.你可以看到,当编译MAIN时,它不知道"SQUARE"在哪里,它的地址是什么.它需要知道,当它调用微处理器JUMP SUBROUTINE(JSR)指令时,该指令有一些地方可去.

.o文件已经有JSR指令,但它没有实际值.这是在链接或加载阶段后期(取决于您的应用程序).

因此,MAINS .o文件包含main的所有代码,以及它想要解析的引用列表(特别是SQUARE).SQUARE基本上是独立的,它没有任何引用,但与此同时,它还没有关于它在内存中存在的地址.

链接器将从.o文件中取出所有内容并将它们合并到一个exe文件中.在过去,编译的代码实际上是一个内存映像.该程序将从某个地址开始,然后简单地加载到RAM批发中,然后执行.因此,在该场景中,您可以看到链接器获取两个.o文件,将它们连接在一起(以获取SQUARE的实际地址),然后它将返回并在MAIN中找到SQUARE引用,并填写地址.

现代链接器并没有那么远,并且将最终处理的大部分推迟到程序实际加载时.但这个概念是相似的.

通过编译到.o文件,您最终得到可重复使用的逻辑单元,然后在执行之前通过链接和加载过程进行组合.

另一个不错的方面是.o文件可以来自不同的语言.只要调用机制是兼容的(即如何将参数传递给函数和过程),那么一旦编译成.o,源语言就变得不那么相关了.你可以用FORTRAN代码链接,组合,C代码.

在PHP等等中,该过程是不同的,因为所有代码都在运行时加载到单个图像中.你可以考虑FORTRANs .o文件,类似于你如何使用PHP包括将文件组合成一个大而有凝聚力的整体的机制.