.o文件与.a文件

54 c c++ linux gcc build-process

这两种文件类型有什么区别.我看到我的C++应用程序在构造可执行文件时链接了两种类型.

如何构建.a文件?链接,参考,尤其是示例,非常感谢.

D.S*_*ley 58

.o文件是对象.它们是编译器的输出和输入到链接器/库管理器.

.a文件是档案.它们是对象组或静态库,也可以输入到链接器中.

其他内容

我没有注意到你问题的"例子"部分.通常,您将使用makefile生成静态库.

AR = ar 
CC = gcc

objects := hello.o world.o

libby.a: $(objects)
    $(AR) rcu $@ $(objects)

%.o: %.c
    $(CC) $(CFLAGS) -c $< -o $@
Run Code Online (Sandbox Code Playgroud)

这将编译hello.cworld.c转换为对象,然后将它们存档到库中.根据平台的不同,您可能还需要运行一个名为的实用程序ranlib来生成存档上的目录.

一个有趣的旁注:.a文件在技术上是归档文件而不是库.它们类似于没有压缩的zip文件,尽管它们使用的是更旧的文件格式.由实用程序生成的目录ranlib是使归档成为库的原因.Java归档文件(.jar)的类似之处在于它们是具有Java归档程序创建的一些特殊目录结构的zip文件.

  • @ShammelLee - 我通常避免使用`$ ^`,因为它是GNU Make扩展而不存在于[BSD make](https://www.freebsd.org/cgi/man.cgi?make(1))或者[POSIX make](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/make.html).我并不重要,因为大多数Linux发行版都是基于GNU的,但是从bash到dash的`/ bin/sh`的切换足以让我继续避免GNU特定的扩展. (2认同)

Vat*_*ine 14

.o文件是编译单个编译单元(本质上是源代码文件,具有关联的头文件)的结果,而.a文件是打包为库的一个或多个.o文件.


bst*_*rre 11

D Shawley的答案很好,我只想补充几点,因为其他答案反映了对正在发生的事情的不完全理解.

请记住,存档文件(.a)不限于包含目标文件(.o).它们可能包含任意文件.通常不常用,但请参阅存档中嵌入的动态链接器依赖信息,以获取愚蠢的链接器技巧.

另请注意,目标文件(.o)不一定是单个编译单元的结果.可以将几个较小的目标文件部分链接到一个较大的文件中.

http://www.mihaiu.name/2002/library_development_linux/ - 在此页面中搜索"partial"


qrd*_*rdl 5

您可以使用从文件(目标文件)ar创建.a文件(静态库.o)

详情man ar请见.


小智 5

There is one more aspect of linking against .a vs .o files: when linking, all .os passed as arguments are included in the final executable, whereas entries from any .a arguments are only included in the linker output if they resolve a symbol dependency in the program.

More specifically, each .a file is an archive comprising multiple .o files. You can think of each .o being an atomic unit of code. If the linker needs a symbol from one of these units, the whole unit gets sucked into the final binary; but none of the others are unless they too are needed.

In contrast, when you pass a .o on the command line, the linker sucks it in because you requested it.

To illustrate this, consider the following example, where we have a static library comprising two objects a.o and b.o. Our program will only reference symbols from a.o. We will compare how the linker treats passing a.o and b.o together, vs. the static library which comprises the same two objects.

// header.hh
#pragma once

void say_hello_a();
void say_hello_b();
Run Code Online (Sandbox Code Playgroud)
// a.cc
#include "header.hh"
#include <iostream>

char hello_a[] = "hello from a";

void say_hello_a()
{
        std::cout << hello_a << '\n';
}
Run Code Online (Sandbox Code Playgroud)
// b.cc
#include "header.hh"
#include <iostream>

char hello_b[] = "hello from b";

void say_hello_b()
{
        std::cout << hello_b << '\n';
}
Run Code Online (Sandbox Code Playgroud)
// main.cc
#include "header.hh"

int main()
{
        say_hello_a();
}
Run Code Online (Sandbox Code Playgroud)

We can compile the code using this Makefile:

.PHONY = compile archive link all clean

all: link

compile:
        @echo ">>> Compiling..."
        g++ -c a.cc b.cc main.cc

archive: compile
        @echo ">>> Archiving..."
        ar crs lib.a a.o b.o

link: archive
        @echo ">>> Linking..."
        g++ -o main_o main.o a.o b.o
        g++ -o main_a main.o lib.a

clean:
        rm *.o *.a main_a main_o
Run Code Online (Sandbox Code Playgroud)

and obtain two executables main_o and main_a that differ in that the contents of a.cc and b.cc where provided through two .os in the first case and through a .a in the second.

Lastly we examine the symbols of the final executables using the nm tool:

$ nm --demangle main_o | grep hello
00000000000011e9 t _GLOBAL__sub_I_hello_a
000000000000126e t _GLOBAL__sub_I_hello_b
0000000000004048 D hello_a
0000000000004058 D hello_b
0000000000001179 T say_hello_a()
00000000000011fe T say_hello_b()
Run Code Online (Sandbox Code Playgroud)
$ nm --demangle main_a | grep hello
00000000000011e9 t _GLOBAL__sub_I_hello_a
0000000000004048 D hello_a
0000000000001179 T say_hello_a()
Run Code Online (Sandbox Code Playgroud)

and observe that main_a is in fact lacking the unneeded symbols from b.o. That is, the linker did not suck in the contents of b.o within the archive lib.a because none of the symbols from b.cc were referenced.

  • 这应该是公认的答案。写得很好,很容易理解,并且有很好的例子! (2认同)