跳到主要内容

静态库与动态库

共享头文件的方法

1. 把头文件保存在标准目录中

把头文件放在/usr/local/include目录中,这样所有的程序都可以使用尖括号引用这个头文件。

2. 使用-I选项

gcc -I/usr/local/include -o program program.c

3. 使用完整路径

#include "/usr/local/include/header.h"

静态库

ar 命令创建静态库

# 创建静态库
ar -rcs libfoo.a foo1.o foo2.o
# r 表示插入文件
# c 表示创建库
# s 表示创建符号表
# libfoo.a 是库的名字
# foo1.o foo2.o 是要插入的文件
  • 命名规则:lib + 库名 + .a
  • 使用ar命令创建静态库时,库名必须以lib开头,否则链接时会报错。

库目录

  • /usr/local/lib:系统库,标准目录
  • 其他目录

当库文件不在标准目录中时,需要使用-L选项指定库目录。

gcc -o program program.c -L/usr/local/lib -lfoo

当库在标准目录中时,可以省略-L选项。

gcc -o program program.c -lfoo

从这里可以看出为什么库命名规则中要求库名以lib开头,-l选项会自动在库名前加上lib

nm 命令

nm命令可以列出目标文件和库文件中的符号表。

nm libfoo.a

用 ranlib 命令创建静态库的索引

动态库

创建动态库

# 首先,编译目标文件
gcc -I. -fPIC -c foo.c -o foo.o
# -c 表示编译,不链接
# -fPIC 表示生成位置无关的目标文件,但是大多数操作系统都不需要这个选项,如果警告说不需要这个选项,可以去掉这个选项

# 把目标文件转化为共享目标文件
gcc -shared foo.o -o libfoo.so
# -shared 表示生成动态库
# -o 表示输出文件
# libfoo.so 是库的名,记住名字前面要加上lib
# 一旦编译了库就不能再改变库的名字了,如果要改变库的名字,需要重新编译

在 Windows 上,动态库的扩展名是.dll,在 Linux 上,动态库的扩展名是.so,在 Mac OS 上,动态库的扩展名是.dylib

在 linux 中,编译器只会记录库的名字,而不包含路径,如果库不在标准目录中,只能把库目录添加到LD_LIBRARY_PATH环境变量中,或者使用-Wl,-rpath选项指定库的路径。

例如,如果你有一个名为 libexample.so 的动态库位于 /usr/local/lib 目录下,你希望你的程序在编译时链接到这个库,你可以使用以下命令:

gcc -o myprogram myprogram.c -Wl,-rpath=/usr/local/lib -lexample

在这个例子中,-Wl,-rpath=/usr/local/lib 告诉链接器在 /usr/local/lib 目录下查找 libexample.so 库。

请注意,-Wl,-rpath 只影响程序的运行时库搜索路径,不会改变程序的二进制文件。这意味着如果你的程序需要在其他机器上运行,而那台机器上没有安装对应的动态库,那么你的程序仍然无法运行。在这种情况下,你可能需要考虑将动态库与应用程序一起打包,或者在目标机器上预先安装好所需的动态库。

gcc -o program program.c -L. -lfoo -Wl,-rpath,.

动态库和静态库编译命令是一样的,只是生成的文件不一样。编译器不会在生成的可执行文件中包含库代码,而是在可执行文件中包含库的名字,当程序运行时,操作系统会在标准目录中查找库文件。

利用这样的机制,我们可以在不改变程序的情况下,出不同版本的程序,比如国内版和国际版。