C语言静态动态库

172 阅读4分钟

创建静态库的过程通常包括以下几个步骤:

  1. 编写源代码:编写要包含在静态库中的C源文件。
  2. 编译为目标文件:将源代码编译为目标文件(.o)。
  3. 创建静态库:使用 ar 工具将目标文件打包成静态库(.a)。
  4. 使用静态库:在其他程序中链接和使用这个静态库。

示例演示

1. 编写源代码

假设你有两个源文件,分别是 foo.cbar.c,内容如下:

foo.c:

#include <stdio.h>void foo() {
    printf("This is function foo.\n");
}

bar.c:

#include <stdio.h>void bar() {
    printf("This is function bar.\n");
}

2. 编译为目标文件

使用 gccfoo.cbar.c 编译为目标文件 foo.obar.o

gcc -c foo.c -o foo.o
gcc -c bar.c -o bar.o

3. 创建静态库

使用 ar 工具将编译好的目标文件 foo.obar.o 打包成静态库 libmylib.a

ar rcs mylib.a foo.o bar.o
  • r 表示插入文件到库中。
  • c 表示创建库文件。
  • s 表示创建索引(这个对性能优化有帮助)。

这将创建一个名为 mylib.a 的静态库文件。

4. 使用静态库

现在,你可以在另一个 C 程序中使用这个静态库。

假设你有一个 main.c 文件:

main.c:

void foo();
void bar();
​
int main() {
    foo();
    bar();
    return 0;
}

编译并链接这个程序时,指定静态库的路径:

gcc main.c -L. -l:mylib.a -o main
  • -L. 表示库文件所在的目录是当前目录。
  • -l:mylib.a 表示链接 mylib.a 静态库。

运行生成的可执行文件:

./main

输出应为:

This is function foo.
This is function bar.

总结

以上演示了如何创建并使用一个静态库。静态库的优势在于它们可以在编译时链接到程序中,从而减少了程序在运行时对外部库的依赖。

创建和使用动态库(也称为共享库)通常涉及以下几个步骤:

  1. 编写源代码:编写要包含在动态库中的C源文件。
  2. 编译为目标文件:将源代码编译为目标文件,并指定生成共享库的选项。
  3. 创建动态库:将目标文件打包成动态库(.so 文件)。
  4. 使用动态库:在其他程序中链接和使用这个动态库。

示例演示

1. 编写源代码

假设你有两个源文件,分别是 foo.cbar.c,内容如下:

foo.c:

#include <stdio.h>void foo() {
    printf("This is function foo.\n");
}

bar.c:

#include <stdio.h>void bar() {
    printf("This is function bar.\n");
}

2. 编译为目标文件

使用 gcc 编译源文件并生成位置无关代码(Position Independent Code, PIC),这是动态库的要求:

gcc -fPIC -c foo.c -o foo.o
gcc -fPIC -c bar.c -o bar.o
  • -fPIC 选项生成位置无关代码,使得代码可以在动态库中被加载到任意内存地址。

3. 创建动态库

使用 gcc 将目标文件打包成共享库 libmylib.so

gcc -shared -o mylib.so foo.o bar.o
  • -shared 选项告诉 gcc 生成一个共享库。

这将创建一个名为 mylib.so 的动态库文件。

4. 使用动态库

现在,你可以在另一个 C 程序中使用这个动态库。

假设你有一个 main.c 文件:

main.c:

void foo();
void bar();

int main() {
    foo();
    bar();
    return 0;
}

编译并链接这个程序时,指定动态库的路径:

gcc main.c -L. -lmylib -o main
  • -L. 表示库文件所在的目录是当前目录。
  • -l:mylib.so 表示链接 mylib.so 动态库。

运行生成的可执行文件时,需要确保动态库能被找到。在运行时,可以通过设置 LD_LIBRARY_PATH 环境变量来指定动态库所在的路径:

export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
./main

输出应为:

This is function foo.
This is function bar.

总结

以上演示了如何创建并使用一个动态库。动态库的优势在于它们在运行时加载,可以减少可执行文件的体积,并允许库的更新而无需重新编译程序。不过,使用动态库时需要注意库路径的设置,以确保程序能够找到并加载库。

提示:

形如这种gcc main.c -L. -l:mylib.a -o main的链接静态库编译的代码,main源文件一定要在前面,不能放在最后,如果放在最后,链接时链接器ld.exe会提示undefined reference错误,即找不到库函数定义。因为它的工作过程是这样的,当解析man.c文件时会发现未解析的符号,会记住这个符号,后面看到 -l:mylib.a链接了库文件,看看这个库文件中是否有之前未解析的符号,如果有就复制库文件函数代码,然后取消记住这个符号,最终如果没有剩余任何未解析符号,则成功,否则报有未解析的符号的错误。