为什么要从.o创建.a文件进行静态链接?

时间:2009-12-05 18:05:47

标签: c linux gcc static-linking

考虑以下代码:

one.c:

#include <stdio.h>

int one() {
   printf("one!\n");
   return 1;
}

two.c:

#include <stdio.h>

int two() {
   printf("two!\n");
   return 2;
}

prog.c中

#include <stdio.h>

int one();
int two();

int main(int argc, char *argv[]) 
{
   one();
   two();

   return 0;
}

我想将这些程序链接在一起。所以我这样做:

gcc -c -o one.o one.c
gcc -c -o two.o two.c
gcc -o a.out prog.c one.o two.o

这很好用。

或者我可以创建一个静态库:

ar rcs libone.a one.o
ar rcs libtwo.a two.o
gcc prog.c libone.a libtwo.a
gcc -L. prog.c -lone -ltwo

所以我的问题是:为什么我会使用第二个版本 - 我创建了一个“.a”文件 - 而不是链接我的“.o”文件?它们似乎都是静态链接,所以在一个与另一个之间是否存在优势或架构差异?

6 个答案:

答案 0 :(得分:41)

通常,库是可以在多个程序中使用的目标文件的集合。

在你的例子中没有任何优势,但你可能已经完成了:

ar rcs liboneandtwo.a one.o two.o

然后链接您的程序变得更简单:

gcc -L. prog.c -loneandtwo

这真的是一个包装问题。您是否有一组自然形成一组相关功能的目标文件,可以在多个程序中重复使用?如果是这样,那么他们可以合理地存档到静态库中,否则可能没有任何优势。

最终链接步骤有一个重要区别。您链接的任何目标文件都将包含在最终程序中。仅当库中的目标文件有助于解析其他目标文件中的任何未定义符号时,才会包含它们。如果他们不这样做,他们将不会被链接到最终的可执行文件。

答案 1 :(得分:12)

不同之处在于可执行文件的大小,尽管可能不适用于您的示例。

链接到库时,只包含可执行文件使用的位。当链接目标文件时,你就完成了所有事情。

例如,如果您的可执行文件只需要在数学库中包含每个数学函数时只使用一个数学函数,那么它将比它需要的大得多并包含大量未使用的代码。

将此与Windows的动态链接模型进行对比很有意思。在那里,操作系统必须完全加载您的可执行文件使用的所有Dll(动态链接库),这可能导致RAM中的膨胀。这种模型的优点是您的可执行文件本身较小,并且链接的Dll可能已经在其他可执行文件使用的内存中,因此不需要再次加载它们。

在静态链接中,为每个可执行文件单独加载库函数。

答案 2 :(得分:2)

从技术上讲,结果完全一样。通常,您为实用程序函数创建库,因此您只需链接库,而不是为链接器提供数十个目标文件。

顺便说一句,创建一个只包含一个.o文件的.a文件绝对没有意义。

答案 3 :(得分:2)

您可以将一组文件放在存档(.a)文件中以供以后重用。标准库就是一个很好的例子。

有时将大型项目组织到图书馆中是有意义的。

答案 4 :(得分:1)

主要优点是当你必须链接时,你可以只指定一个库而不是所有单独的目标文件。管理文件,处理一个库而不是一堆目标文件也有一个小优势。有一段时间,这也大大节省了磁盘空间,但目前的硬盘价格使这一点变得不那么重要了。

答案 5 :(得分:0)

每当我被问到这个问题时(由我的团队中的新人),“为什么(有时甚至是'什么是')a。?”,我使用下面的答案,使用.zip作为类比。< / p>

“dotAy就像所有dotOhs的zip文件,在构建你的exe / lib时你想要链接它们。在磁盘空间上节省,加上一个不需要输入所有dotOhs的名字。”

到目前为止,这似乎让他们明白了。 ;)