预处理与链接

时间:2016-04-21 23:36:31

标签: compiler-construction linker preprocessor-directive

无处不在我寻找链接器实际上做了什么(除了重定位,有些人似乎置于“加载”之下)人们给出了两个(比方说)C模块的例子,它们互相调用函数。

据我了解,这应该通过预处理(#include等)来处理。我可以理解,如果我想在不同的时间组装两个模块,我需要稍后链接它们。但是当我使用说gcc时,它会直接输出可执行文件,所以在这个上下文中我并没有真正看到链接点,除非预处理(我将猜测它将是递归的)最终命中对象代码。

注意:我在这里指的是静态链接。我可以看到动态链接的重点。

1 个答案:

答案 0 :(得分:1)

gcc正在使用大量工具来创建可执行文件,编译器就是其中之一,链接器,预处理器等也是如此,以查看它实际上正在做什么将-v选项传递给它。如果你想看到中间文件使用-save-temps,即一旦你创建了下面的文件,试试这个......

gcc-5 -save-temps -v -std=c11 -Wall -pedantic-errors main.c foo.c 

如果查看目录,您会看到几个额外的文件......

a.out // Executable when no name is specified
foo.c // original foo.c
foo.h // original foo.h
foo.i // Preprocessed ouput of foo.c and foo.h
foo.o // foo Object file
foo.s // foo assembler
main.c // original main.c
main.i // main preprocessed
main.o // main object file
main.s // main assembler

如果您查看main.i,您会发现它包含此内容

# 1 "foo.h" 1


int foo(int i);

但它不知道函数foo实际上做了什么。这都在foo.i。这也意味着在创建目标文件时main.o知道它需要foo函数。将main.o中的符号foo与foo.o中的foo连接是链接器正在进行的操作。

这是一个例子,创建以下三个文件

foo.h中

#ifndef FOO_H
#define FOO_H
int foo(int i); 
#endif

foo.c的

#include "foo.h"
int foo(int i) {
  return i - 1729;
}

的main.c

#include "foo.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
int main(void) {
  printf("%d\n", foo(1));
  return 0;
}

创建他们的Object文件,即不是可执行文件,如下所示,注意我已经为此添加了详细的标志..

gcc-5 -v -std=c11 -Wall -pedantic-errors main.c foo.c -c

如果您使用了-o标志,您将看到gcc调用的实际链接器命令将对象链接到可执行文件中,即

gcc-5 -v -std=c11 -Wall -pedantic-errors main.c foo.c -o fooer

此时,您将在目录中找到两个目标文件。您可以使用ld创建可执行文件,如下所示(注意这是特定于mac的,使用gcc -v的输出为您的机器找到正确的命令)。

ld -dynamic -arch x86_64 -macosx_version_min 10.11.3 -lSystem main.o foo.o -o fooer