1130 字
6 分钟
动态库、静态库编译、打包

动态库、静态库编译、打包#

1、头文件守卫#

防止头文件被重复包含

#ifndef _HEAD_H_
#define _HEAD_H_
......
#endif

2、静态库的制作打包#

  1. 将 .c 生成 .o 文件
Terminal window
gcc -c add.c -o add.o
  1. 使用 ar 工具制作静态库
Terminal window
ar rcs lib库名.a add.o sub.o div.o
  1. 编译静态库到可执行文件中:
Terminal window
gcc test.c lib库名.a -o a.out

​ 4. 如果您的库依赖于其他静态库,您需要在这一步之前将所有依赖的库合并到您的库中。这可以通过使用 ld 工具的 --whole-archive 选项来实现,例如:

Terminal window
gcc -static -Wl,--whole-archive libdependency.a -Wl,--no-whole-archive -o libyourlibrary.a yourlibrary.o

​ 这个命令会将 libdependency.a 中的所有对象文件与 yourlibrary.o 合并成一个静态libyourlibrary.a。打包共享:将您的静态库 libyourlibrary.a 以及所有相关的头文件和文档打包,确保依赖库的版权和许可信息也被包含在内。

​ 在GCC中使用-Wl,--whole-archive选项,可以告诉链接器(通常是ld)将后续的静态库中的所有对象文件都包含进最终的可执行文件中,而不是只包含被引用的对象文件。这在创建包含多个库的静态链接的可执行文件时非常有用。例如,如果您有两个静态库libA.a和libB.a,并且您想要确保这两个库中的所有对象文件都被包含进最终的可执行文件中,即使libB.a中的某些对象文件没有被libA.a直接引用,您可以使用以下命令:

Terminal window
gcc -o my_program my_program.o -Wl,--whole-archive libA.a libB.a -Wl,--no-whole-archive

在这个例子中,-Wl,--whole-archive选项告诉链接器包含libA.a和libB.a中的所有对象文件,而-Wl,--no-whole-archive选项则关闭了这个行为,确保后续的库只包含被引用的对象文件。

请注意,-Wl选项是GCC的一个前缀,用于将后面的选项传递给链接器。因此,-Wl,--whole-archive实际上是在告诉GCC将--whole-archive选项传递给链接器ld。同样地,-Wl,--no-whole-archive告诉链接器停止--whole-archive行为。

使用--whole-archive时,需要谨慎,因为这将增加最终可执行文件的大小,并且可能会包含不必要的代码。此外,如果多个库中存在相同的符号定义,可能会导致链接时的问题。

3、动态库的制作打包#

  1. 将 .c 生成 .o 文件, (生成与位置无关的代码 -fPIC)
Terminal window
gcc -c add.c -o add.o -fPIC
  1. 使用 gcc -shared 制作动态库
Terminal window
gcc -shared -o lib库名.so add.o sub.o div.o
  1. 编译可执行程序时,指定所使用的动态库。 -l:指定库名(去掉lib前缀和.so后缀) -L:指定库路径。
Terminal window
gcc test.c -o a.out -lmymath -L./lib
  1. 运行可以执行程序 ./a.out 出错!!!!

    --- ldd a.out --> "not found" error while loading shared libraries: libxxx.so: cannot open shared object file: No such file or directory

例如,如果你有一个共享库位于/usr/local/lib目录,并且你想要编译的程序在运行时能够找到这个库,你可以使用如下的gcc命令显示指定动态库的搜索动态库路径

Terminal window
gcc -o my_program my_program.c -L/usr/local/lib -lmylib -Wl,-rpath,/usr/local/lib

这里,-L/usr/local/lib告诉编译器在编译时到哪里查找库,而-Wl,-rpath,/usr/local/lib则告诉链接器在运行时到哪里查找这个库。

需要注意的是,-rpath选项的用法可能因不同的系统和链接器而有所不同,上面的例子适用于使用GNU ld链接器的情况。在有些系统上,可能需要使用不同的选项或者不同的方式来指定运行时链接路径。

原因:

链接器: 工作于链接阶段, 工作时需要 -l 和 -L

动态链接器: 工作于程序运行阶段,工作时需要提供动态库所在目录位置。

解决方式:

【1】 通过环境变量: export LD_LIBRARY_PATH=动态库路径

./a.out 成功!!! (临时生效, 终端重启环境变量失效)

【2】 永久生效: 写入 终端配置文件。 .bashrc 建议使用绝对路径。

【3】 拷贝自定义动态库 到 /lib (标准C库所在目录位置)

【4】 配置文件法

Terminal window
sudo vi /etc/ld.so.conf

sudo ldconfig -v 使配置文件生效。

4)./a.out 成功

4、 复杂的打包实例#

include ./Makefile.config
SRCS=$(wildcard *.c)
OBJS_static=$(patsubst %.c, %.o, $(SRCS))
OBJS_dynamic=$(patsubst %.c, %.os, $(SRCS))
install:install_static install_dynamic
cp rsf.h $(LGLROOT)/include/
cp librsf.a $(LGLROOT)/lib/
cp libdrsf.so $(LGLROOT)/lib/
install_static:$(OBJS_static)
ar rc librsf.a $^
ranlib librsf.a
install_dynamic:$(OBJS_dynamic)
$(CC) -o libdrsf.so -fopenmp -shared $^ -lm -lblas -lcblas
%.os:%.c
$(CC) -o $@ -c -g -x c -Wall -fopenmp -fPIC -DRSF_VERSION='"4.0"' $<
%.o:%.c
$(CC) -o $@ -c -g -x c -Wall -fopenmp -DRSF_VERSION='"4.0"' $<
clean:
-rm -rf *.o *.os librsf.a libdrsf.so
realclean:clean
-rm -rf $(LGLROOT)/include/rsf.h $(LGLROOT)/lib/librsf.a $(LGLROOT)/lib/libdrsf.so
动态库、静态库编译、打包
https://tuoyuangui.github.io/website/posts/typora/gnu语言/动态库静态库的制作/
作者
椭圆规/tuoyuangui
发布于
2022-07-12
许可协议
CC BY-NC-SA 4.0