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.c并world.c转换为对象,然后将它们存档到库中.根据平台的不同,您可能还需要运行一个名为的实用程序ranlib来生成存档上的目录.
一个有趣的旁注:.a文件在技术上是归档文件而不是库.它们类似于没有压缩的zip文件,尽管它们使用的是更旧的文件格式.由实用程序生成的目录ranlib是使归档成为库的原因.Java归档文件(.jar)的类似之处在于它们是具有Java归档程序创建的一些特殊目录结构的zip文件.
bst*_*rre 11
D Shawley的答案很好,我只想补充几点,因为其他答案反映了对正在发生的事情的不完全理解.
请记住,存档文件(.a)不限于包含目标文件(.o).它们可能包含任意文件.通常不常用,但请参阅存档中嵌入的动态链接器依赖信息,以获取愚蠢的链接器技巧.
另请注意,目标文件(.o)不一定是单个编译单元的结果.可以将几个较小的目标文件部分链接到一个较大的文件中.
http://www.mihaiu.name/2002/library_development_linux/ - 在此页面中搜索"partial"
小智 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.
| 归档时间: |
|
| 查看次数: |
28547 次 |
| 最近记录: |