前言:我们写的方法如何给别人用
当我们写了一些通用方法,想给别人使用时,通常有两种选择:
-
方法一:直接提供源码(.h + .c)
- 将头文件和源文件一并发给对方,对方可以直接编译使用。但问题是:别人能直接看到你的代码实现,劳动成果暴露无遗!
-
方法二:提供头文件 + 打包后的库文件(.h + 库)
- 将源文件编译并打包成库文件,再连同头文件一并提供。这样:别人只能使用你提供的接口,而看不到实现细节!
补充说明:
- 头文件(.h)是必须公开的,它就像“说明书”,告诉别人该怎么使用你的函数接口;
- 而源文件(.c)中真正的函数实现,则可以通过打包成静态库或动态库来进行“封装”。
1 静态链接
1.1 什么是静态库?
静态库就是 .a
文件(在 Linux 下),例如 libmath.a,其本质是多个 .o
文件(目标文件)的打包集合。
当我们用 main.c 编写自己的主程序时,编译器会:
- 把 main.c 编译为 main.o
- 然后把别人提供的 libXXX.a(静态库)一起链接
- 最终生成可执行程序
这样就不再需要源码,也能正常使用库中方法,实现了功能复用与源码保护的双赢。
1.2 静态库的原理
原理:把我们写的方法相关 .c
源文件先编译为 .o
,然后通过工具打包成 .a
文件。
命令行操作:
gcc -c add.c # 将源文件编译为目标文件 add.o
gcc -c sub.c # 将源文件编译为目标文件 sbu.o
ar -rc libmath.a add.o sub.o # 将多个.o文件打包成静态库libmath.a
ar
是用于操作静态库的工具- 其中
-rc
表示:r(replace)替换已有文件、c(create)创建新文件
1.3 静态库制作和公开
可以完成静态库的制作,然后可以公开出去,变成一个lib文件夹给用户
1.4 库使用及路径问题
如果文件都在当前路径,也可以:
前面两个路径不能省略!!!(它只会去默认路径寻找,不会去当前路径寻找!!!)
1.5 errno的理解
2 动态链接
2.1 动态库的原理和命令
动态库的原理和静态库一样,因为最后都要链接,所以都是先把-c变成-o,然后再用命令打包起来。
和静态库的区别:
- gcc编译多了一个选项 -fPIC :
gcc -fPIC -c mylog.c
生成.o
文件 gcc -shared -o libmymethod.so *.o
把所有的.o
文件打包成.so
文件,前面多了一个-shared
2.2 尝试动静态库分离
dy-lib=libmymethod.so
static-lib=libmymath.a
.PYONY:all // 一次生成两个可执行文件
all: $(dy-lib) $(static-lib)
$(static-lib):mymath.o // 打包所有,点o文件,形成静态库
ar -rc $@ $^ // ar -rc 是静态库打包特有的
mymath.o:mymath.c
gcc -c $^ // 不写$@,默认生成,点o文件
$(dy-lib):mylog.o myprint.o // 打包所有,点o文件,形成动态库
gcc -shared -o $@ $^ // -shared是打包动态库特有的
mylog.o:mylog.c
gcc -fPIC -c $^ // -fPIC 是动态库形成点o文件特头的
myprint.o:myprint.c
gcc -fPIC -c $^
.PYONY:clean
clean:
rm -rf *.o *.a *.so mylib
.PYONY:output
output:
mkdir -p mylib/include
mkdir -p mylib/lib
cp *.h mylib/include
cp *.a mylib/lib
cp *.so mylib/lib
make; make output
后,动态库就形成了。
gcc main.c -I mylib/include/ -L mylib/lib/ -l mymethod
可以形成可执行程序 a.out
文件,但是这个可执行不能直接运行!!!
问题:为什么明明形成了a.out 却还是出现这种情况呢?
我曾经告诉过编译器动态库在哪里,编译器也帮我生成了可执行程序,但是当形成可执行程序之后,就和编译器一无关了,可执行程序运行不了,是因为我们没用告诉系统(加载器)动态库在哪。
2.3 解决加载找不到动态库的方法
方法一:动态库直接拷贝到系统默认的库路径/usr/lib
方法二:在系统的默认库路径/usr/lib 建立软连接
sudo ln -s /home/hyq/HYQ/hyq9/mylib/lib/libmymethod.so /lib/libmymethod.so
方法三:将自己库所在的路径,添加到环境变量LD_LIBRARY_PATH(搜索用户自定义库路径)中
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/hyq/HYQ/hyq9/mylib/lib
缺点:关闭shell之后就会失效!!!
其实还有方法四:/etc/ld.so.conf.d 建立自己的动态库路径的配置文件,然后ldconfig一下(没懂意思,算了,不写了)