有关GCC编译器和链接器的问题

问题描述 投票:0回答:3

假设您的程序由两个源文件(main.c 和auxiliary.c)和两个头文件(declarations.h 和auxiliary.h)组成。

然后按如下方式运行编译器:

$gcc main.c auxiliary.c -o myprogram

问题 1:编译器会为我的程序创建一个目标文件(即,仅缺少库)还是会创建两个目标文件,每个源文件一个(然后将所有内容链接在一起)?

问题2:是否需要单独调用链接器?因为如果您使用上面的命令,编译器会为您处理这个问题,对吧?

问题 3:为什么有些库会自动链接(例如,stdio)以及为什么有些库需要额外的工作(例如,math.h 需要在编译时添加 -lm)。 -lm 代表什么?

问题 4:假设您有一个源文件,并且您的程序不需要任何外部库。这是否意味着您从编译器获得的目标代码已经可以执行? (即像 $gcc -c main.c 一样编译它)。

c gcc
3个回答
4
投票
  1. gcc 通常会为每个源文件创建一个对象。 但有一个

    -combine
    选项可以告诉你你想要什么。

  2. 当您有几十个源文件时重新编译所有内容并不是一个好主意(当您有更多源文件时,您将它们拆分为库)。

  3. 历史。 曾经有一段时间——在共享库之前——数学库相对较大,将其放入每个可执行文件中,即使是那些不需要它的人也被认为是浪费(使用数学库涉及 printf 等函数的替代版本,因此即使不使用也会产生费用)

  4. 我正在等待看到一个甚至不使用标准库的任何部分的程序(逻辑上调用 main 是作为

    exit(main(argc, argv))
    完成的,所以至少
    exit
    被调用),然后是启动和完成代码。


3
投票
  1. gcc
    为每个源文件创建一个目标文件,然后链接它们以构建可执行文件。

  2. 您的示例证明

    gcc
    能够链接所有需要的步骤

  3. 自动链接的库是标准C 库。其他的需要具体说明。这允许在不需要时构建更小的可执行文件

    atan2()

    -lm
    指示编译器应该找到 id 为
    m
    的数学库。在 Unix 上,其文件名是
    libm.so
    libm.a
    ,具体取决于链接是动态(在运行时执行并生成较小的可执行文件)还是静态(在链接时执行并生成独立的可执行文件)。

  4. 没有。无论如何,它必须链接到标准 C 库。此外,目标代码的文件格式与可执行文件不同。


1
投票

问题 1:使用“-save-temps”执行 gcc 语句,您将看到编译器创建了两个目标文件。

问题2:对链接器的调用是隐式的。 “gcc”命令并不是真正的编译器,而是根据需要调用预处理器、编译器、汇编器和链接器来驱动编译过程。 在小型程序中,让“gcc”处理所有事情可能是个好主意,但对于具有许多源文件的大型程序,这意味着重新编译所有源文件,即使它们没有更改。

问题3:这是一个惯例问题。 (m 库是数学库。)

问题4:不,事实并非如此。总是有一些必须链接的附加代码来满足进程启动/拆卸的要求。在 Linux 上,这些是 crt1.o、crti.o、crtbegin.o 和 crtn.o 文件。

© www.soinside.com 2019 - 2024. All rights reserved.