库:本质上来说是一种可执行代码的二进制格式,可以被载入内存中执行,分为静态库和动态库两类。另外,需要知道的是,由于windowsLinux是两款操作系统,因此,二者的库是不兼容的。

 

静态函数库:

后缀通常为***.a,利用静态库编译的程序有着一定的优点,即编译后的执行程序不需要外部的函数库支持,因为所有使用的函数都已经被编译进去,但这会造成另外一个问题,如果静态库发生改变,程序就需要重新编译,同时,静态库编译程序生成的文件较大,因为整个函数库的所有数据都会被整合进目标代码中。

利用静态库编译,通常情况下是因为我们希望我们的程序需要有更好的移植性。

动态函数库:

后缀通常为***.so,动态函数库在编译的时候并没有被编译进目标代码,只有当程序执行到相关函数时才调用该函数库里的相应函数,因此动态函数库所产生的可执行文件比较小。关于平台的问题上,如果利用动态库编译的程序希望得到运行,那么该运行环境中必须要有相应的库来支持,动态函数库并不影响程序,所以动态函数库升级更加方便。

 

二者的最大不同之处在于库代码被在于内存的时刻不同,静态库通常在编译时刻就被载入可执行程序,动态库是在程序运行时载入内存的,编译过程中只是简单的引用。


gcc生成静态链接库实例:

在当前目录下,有如下几个文件,Makefile暂不关心。

wKioL1i5eE6wdbVGAAAXGO5hn_I986.png

前三个文件内容如下:

wKiom1i5eE_xYYkyAACvcg0dugE110.png



要生成静态库文件,首先我们需要将源代码转换为二进制目标文件(hello.c -- > hello.o

[muhui@bogon mylib]$ gcc -c hello.c -o hello.o

接下来我们需要将hello.o依照静态库命名规范【注1】转化为静态库文件 libmyhello.a

[muhui@bogon mylib]$ ar cr libmyhello.a hello.o

得到静态库文件之后,就可以使用gcc命令生成最终目标文件时指明静态库名,gcc将会从静态库中将共用函数链接到目标文件。【注2

[muhui@bogon mylib]$ gcc -o hello main.c -L. -lmyhello 

# -L.指定了静态库文件目录在当前目录下

完成了gcc编译的任务之后,我们需要做一件事,来验证是否我们成功使用了静态库。我们尝试将静态库文件删除,看生成的可执行程序是否还能正确运行。

    [muhui@bogon mylib]$ rm -f libmyhello.a

    [muhui@bogon mylib]$ ./hello

    hello world

程序运行正常,表明静态库文件已经被添加进入目标文件。

最后这里我们留意一下生成的目标文件大小:

    [muhui@bogon mylib]$ ll

    总用量 652

    -rwxrwxr-x. 1 muhui muhui 645220 2月  18 08:44 hello

    -rw-rw-r--. 1 muhui muhui     81 2月  17 18:17 hello.c

    -rw-rw-r--. 1 muhui muhui    108 2月  17 18:15 hello.h

    -rw-rw-r--. 1 muhui muhui    856 2月  18 08:36 hello.o

    -rw-rw-r--. 1 muhui muhui     63 2月  17 18:19 main.c

 

gcc生成动态链接库实例:

同样还是和上面一样,使用同一个例子。

动态库文件依旧需要由.o文件来创建,首先我们清理当前工作目录。

    [muhui@bogon mylib]$ ls

    hello  hello.c  hello.h  hello.o  main.c  Makefile

    [muhui@bogon mylib]$ rm -f hello

    [muhui@bogon mylib]$ ls

    hello.c  hello.h  hello.o  main.c  Makefile

 

这里保留的hello.o文件,同时也遵守动态库文件命名规范【注3】,创建动态库文件libmuhello.so

    [muhui@bogon mylib]$ gcc -shared -fPCI -o libmyhello.so hello.o

    [muhui@bogon mylib]$ ls

    hello.c  hello.h  hello.o  libmyhello.so  main.c  Makefile

 

接下来在程序中使用动态库文件,使用动态库和使用静态库文件方式完全一样,如下

[muhui@bogon mylib]$ gcc -o hello main.c -L. -lmyhello

[muhui@bogon mylib]$ ls

hello  hello.c  hello.h  hello.o  libmyhello.so  main.c  Makefile

[muhui@bogon mylib]$ ./hello

./hello: error while loading shared libraries: libmyhello.so: cannot open shared object file: No such file or directory

 

报错!原因说的很清楚,没有找到动态库文件。程序运行时,通常还在/usr/lib /lib 目录下查找所需要的动态库文件,所以这里我们需要将我们生成的动态库文件移动到/usr/lib 目录下(需要root权限)

    [muhui@bogon mylib]$ sudo mv libmyhello.so /usr/lib/

    [sudo] password for muhui:

    [muhui@bogon mylib]$ ls

    hello  hello.c  hello.h  hello.o  main.c  Makefile

    [muhui@bogon mylib]$ ./hello

    hello world

完成之后,我们再次查看目标文件大小

    [muhui@bogon mylib]$ ll

    总用量 28

    -rwxrwxr-x. 1 muhui muhui 4888 2月  18 09:06 hello

    -rw-rw-r--. 1 muhui muhui   81 2月  17 18:17 hello.c

    -rw-rw-r--. 1 muhui muhui  108 2月  17 18:15 hello.h

    -rw-rw-r--. 1 muhui muhui  856 2月  18 08:36 hello.o

    -rw-rw-r--. 1 muhui muhui   63 2月  17 18:19 main.c

两次对比,就会发现,使用动态库文件的话,生成的目标文件就会小的多。

 

 

这里需要强调的一点是,如果我们同时生成静态库和动态库文件的话,操作系统一般会优先选择动态库。

 

 

 

 

 

 

 

 

 

【注1】静态库命名规范:以lib为前缀,紧接着跟静态库名,扩展名为.a

【注2gcc会在静态库名前加上lib前缀,然后追加扩展名.a,得到的静态库文件名来查找静态库文件,注意下面静态库名的变化,前缀lib变为l,同时省略后缀。

【注3】动态库命名规范:以lib为前缀,紧接着跟动态库名,扩展名为.so


补充一点的是,如果在编译过程中发现会有报错产生,很可能是因为缺少一个叫做glib-static的库,可以直接使用

yum -y install glibc-static

安装该文件,推荐直接使用网络yum源下载,个人尝试,搭建的本地yum源,安装失败,具体原因应该是该库在镜像B的问题,这里不深究。




    ------muhuizz整理