目录
动态库和静态库
在linux中查看库,我们可以使用ldd命令,查看可执行程序,比如上面文件中我们写的mytest可执行程序
[wjy@VM-24-9-centos 30]$ ldd mytest
linux-vdso.so.1 => (0x00007ffeb5562000)
libc.so.6 => /lib64/libc.so.6 (0x00007fe8a82e7000)
/lib64/ld-linux-x86-64.so.2 (0x00007fe8a86b5000)
而这个库它存在于一个目录的路径下的,这里是一个软连接,而这个2.17指向的就是一个C的库。查看这个文件可以看到,c库有2156592个文件。所谓的库是系统上真正存在的一个文件,
[wjy@VM-24-9-centos 30]$ ls /lib64/libc.so.6 -l
lrwxrwxrwx 1 root root 12 Nov 23 17:52 /lib64/libc.so.6 -> libc-2.17.so
[wjy@VM-24-9-centos 30]$ ls /lib64/libc-2.17.so -l
-rwxr-xr-x 1 root root 2156592 Oct 14 2021 /lib64/libc-2.17.so
Linux中,一般库分两种库,动态库和静态库
- 如果是动态库,库文件是以.so作为后缀的。
- 如果是静态库,库文件是以.a作为后缀的。
ps1:动静态库它们就是文件,它们就是在磁盘上的一个文件。
ps2:库的真实名字:去掉lib前缀,去掉.a/.so之后包含的后缀,剩下的就是库的名字。
需要注意的一点是,在编写C++程序的时候,C++的程序名只能由三种后缀:.cpp/.cc/.cxx这三种,如果是其他的后缀如.cyy编译就会报错
[wjy@VM-24-9-centos 30]$ touch test.cc
[wjy@VM-24-9-centos 30]$ vim test.cc
[wjy@VM-24-9-centos 30]$ cat test.cc
#include <iostream>
int main()
{
std::cout<<"hello world!"<<std::endl;
return 0;
}
[wjy@VM-24-9-centos 30]$ g++ test.cc
[wjy@VM-24-9-centos 30]$ ./a.out
hello world!
[wjy@VM-24-9-centos 30]$ mv test.cc test.cpp
[wjy@VM-24-9-centos 30]$ g++ test.cpp
[wjy@VM-24-9-centos 30]$ ./a.out
hello world!
[wjy@VM-24-9-centos 30]$ mv test.cpp test.cxx
[wjy@VM-24-9-centos 30]$ g++ test.cxx
[wjy@VM-24-9-centos 30]$ ./a.out
hello world!
[wjy@VM-24-9-centos 30]$ mv test.cxx test.cyy
[wjy@VM-24-9-centos 30]$ g++ test.cyy
test.cyy: file not recognized: File format not recognized
collect2: error: ld returned 1 exit status
[wjy@VM-24-9-centos 30]$
当我们使用静编译,编写makefile文件的时候,在后面要加-static选项。
默认gcc动态链接编译:在上面我们写过一个test.c代码是c语言的,并且它的编译方式是gcc -o $@ $^,通过file操作可以发现,它是动态编译的。
gcc静态链接编译:如果编译静态链接,用file查看它是静态的链接。如果静态编译出现这样的错误:/usr/bin/ld: cannot find -lc,那么输入这个命令:sudo yum install glibc-static,就可以搞定啦。我们同时也发现,静态链接的体积非常大。
那为什么有时候会报错呢?因为一般服务器,可能美欧内置语言的静态库,而只有动态库。
动态库和静态库的区别
实际上我们在代码中运用库函数,如C中的printf,我们需要通过链接库的方式,那么链接库的方式有两种,一种是静态的,一种是动态的。
静态库一般就是把库中的内容拷贝进可执行程序,这样如果拷贝到执行程序,执行城区之后的代码将不再依赖库,同时也造成了可执行程序非常大。
而动态库,只是把要关联的函数关联起来,不会进行拷贝的行为,当需要执行库函数代码,我们直接跳转到库当中就可以执行了。那么动态库是怎么实现每个程序都可以用呢,就是通过地址空间和动态库的映射,实现共享,所以我们通过file查看的动态库可以看到上面写着share共享。所以动态库它生成的体积小,但是可移植性是存在问题的,如果库缺失了,那么对应的函数就找不到了。而静态库最然体积大,但是不依赖第三方库,哪怕删掉也没有关系。
动静态库的制作
库本身就是二进制的文件,我们如何得知一个库给我们提供了什么方法呢?
一套完整的库包含两个东西(其实还有一个说明文档,但这里我们不关心)
- 1.库文件本身
- 2.头文件.h :会说明库中暴露出来的方法的基本使用。它被安装在/usr/include目录下。其中就有我们最熟悉的stdio.h,查看stdio.h文档里面是文本文档,并不是二进制。
我们在C/C++中,为什么写代码,有时候把声明放在.h中,把实现放入.c/.cpp中呢?为什么这么设计?
因为我们要制作库,库的好处除了方便使用,还有最重要的一点是私密。
静态库的制作
先在当前目录下新建一个目录test_lib保存我们自己写的库文件。其中我们写两个.c文件和两个.h文件
[wjy@VM-24-9-centos test_lib]$ ll
total 16
-rw-rw-r-- 1 wjy wjy 60 May 1 15:49 add.c
-rw-rw-r-- 1 wjy wjy 66 May 1 15:49 add.h
-rw-rw-r-- 1 wjy wjy 61 May 1 16:42 sub.c
-rw-rw-r-- 1 wjy wjy 66 May 1 16:42 sub.h
[wjy@VM-24-9-centos test_lib]$ cat add.h
#pragma once
#include <stdio.h>
extern int my_add(int x,int y);
[wjy@VM-24-9-centos test_lib]$ cat add.c
#include "add.h"
int my_add(int x,int y)
{