pad*_*ony 11 c linux linker compilation clang
假设我有以下程序(hello.c
):
#include <stdio.h>
#include <math.h>
#define NAME "ashoka"
int main(int argc, char *argv[])
{
printf("Hello, world! My name is %s\n", NAME);
}
Run Code Online (Sandbox Code Playgroud)
所以,据我所知,编译这个程序的过程是:
预处理:将复制粘贴stdio.h和math.h函数声明并替换NAME
为"ashoka"
.
clang -E hello.c
Run Code Online (Sandbox Code Playgroud)编译:将c代码转换为汇编代码
clang -S hello.c
Run Code Online (Sandbox Code Playgroud)
生成的文件:hello.s
组装:将汇编代码转换为目标代码
clang -c hello.s
Run Code Online (Sandbox Code Playgroud)
生成的文件:hello.o
链接:将目标文件合并到一个我们将要执行的文件中.
clang hello.o -lm
Run Code Online (Sandbox Code Playgroud)
或者(假设我也想链接hello2.o)
clang hello.o hello2.o
Run Code Online (Sandbox Code Playgroud)所以,问题来了:
该过程描述的是正确的吗?
在链接阶段,我们将.o
(对象代码)文件链接在一起.我知道它math.h
位于/usr/include
目录中.在哪里math.o
?链接器如何找到它?
Linux 中的.a
(静态库)和.so
(动态库)是什么?它们如何与.o
文件和链接阶段相关?
假设我想与世界共享一个图书馆.我有一个mylib.c
文件,我在其中声明并实现了我的功能.我怎么会去分享这个让人们会做将它包含在他们的项目#include <mylib.h>
还是#include "mylib.h"
?
clang
),优化等.math.h
只定义标准数学库libm.a
(与之链接-lm
)的原型.这些函数本身存在于内部存档的目标文件中libm.a
(见下文).ar
(例如,ar -t
列出库中的目标文件).动态(或共享)库不包含在输出二进制文件中.相反,您的代码所需的符号在运行时加载.您只需使用extern
ed原型创建一个头文件:
#ifndef MYLIB_H
#define MYLIB_H
extern int mylib_something(char *foo, int baz);
#endif
Run Code Online (Sandbox Code Playgroud)
并将其与您的图书馆一起发货.当然,开发人员还必须(与你的库)链接(dinamically).
静态库的优点是可靠性:没有任何意外,因为您已经将代码与您确定可以使用的确切版本相关联.其他可能有用的情况是,当您使用不常见或前沿的库并且您不希望将它们安装为共享时.这是以增加二进制大小为代价的.
共享库生成较小的二进制文件(因为库不在二进制文件中),RAM占用空间较小(因为操作系统可以加载一次库并在多个进程之间共享),但它们需要更加小心以确保您正在加载正是你想要的(例如,请参阅Windows上的DLL Hell).
正如@iharob所说,他们的优势并不仅仅停留在二进制大小上.例如,如果在共享库中修复了错误,则所有程序都将从中受益(只要它不会破坏兼容性).此外,共享库提供外部接口和实现之间的抽象.例如,假设OS为应用程序提供了一个库以与其进行交互.通过更新,操作系统界面会发生变化,库实现会跟踪这些更改.如果它被编译为静态库,则必须使用新版本重新编译所有程序.如果它是一个共享库,他们甚至都不会注意到它(只要外部接口保持不变).另一个示例是Linux库,它将系统/特定于发行版的方面包装到公共接口.
归档时间: |
|
查看次数: |
316 次 |
最近记录: |