构建目标可以采用多种形式,但通常它们代表两种可能性之一:
可执行目标executable- 我们可以运行的程序 (包含main函数)
库目标library - 编译和/或运行时(取决于动态还是静态)可由executable使用的库(不含main函数)
库
在windows和Linux下都存在着大量的库,库是什么呢?本质上来说,库时一种可执行代码的二进制形式,可以被操作系统载入内存执行。
库有什么用呢?
我们通常将一些公用函数写成函数库,所以库是别人写好的,现有的,成熟的,可以服用的代码,你可以使用但要必须得遵守许可协议。在我们现实开发过程中,不可能每一份代码都从头编写,当我们拥有库时,我们就可以直接将我们所需要的文件链接到我们的程序中。可以为我们节省大量的时间,提高开发效率。所以,哭的存在意义是不可藐视的。
Linux下的库
Linux下库分为两种,静态库和动态库。
区别
这两种库相同点是两种库都是由.o文件生成的,下边讨论一下它们的不同点:
-
静态库
静态库文件名的命名方式是“libxxx.a”,库名前加”lib”,后缀用”.a”,“xxx”为静态库名。
链接时间: 静态库的代码是在编译过程中被载入程序中。
链接方式:静态库的链接是将整个函数库的所有数据都整合进了目标代码。这样做优点是在编译后的执行程序不在需要外部的函数库支持,因为所使用的函数都已经被编进去了。缺点是,如果所使用的静态库发生更新改变,你的程序必须重新编译。 -
动态库
动态库的命名方式与静态库类似,前缀相同,为“lib”,后缀变为“.so”。所以为“libmytime.so”
链接时间:动态库在编译的时候并没有被编译进目标代码,而是当你的程序执行到相关函数时才调用该函数库里的相应函数。这样做缺点是因为函数库并没有整合进程序,所以程序的运行环境必须提供相应的库。优点是动态库的改变并不影响你的程序,所以动态函数库升级比较方便。
它们两个还有很明显的不同点:当同一个程序分别使用静态库,动态库两种方式生成两个可执行文件时,静态链接所生成的文件所占用的内存要远远大于动态链接所生成的文件。(因为静态链接是在编译时将所有的函数都编译进了程序。而动态链接是在运行是才调用库里相应函数)
--------------------- 本文来自 LLZK_ 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/LLZK_/article/details/55519242?utm_source=copy
一般从C源文件到可执行代码要经过以下4个步骤:预编译(preprocess gcc -E,生成.i文件),编译(compile gcc -S,生成.s文件),汇编(assemble gcc -c,生成.o文件),链接(link 生成可执行文件)。这里只讨论最后两个步骤,汇编和链接。、
库文件究竟是什么呢?其实就是汇编后的二进制代码,是别人写好的超级牛逼的代码汇编以后放在那里让我们使用的。但是这个汇编后的二进制代码和我们自己生成的还有些不同,具体来说有两种。
库文件本身分为两种:静态库文件(static library)和动态库文件(dynamic library),linux下,静态库文件以.a结尾(archive),动态库文件以.so结尾(shared object)。
静态库文件其实就是汇编后的二进制代码的一个压缩文件(archive),里面可以有一个或者N个.o文件。比如上面的magic.c,可以这样生成静态库文件:
首先汇编:gcc -c magic.c ,生成magic.o,然后使用压缩文件命令(ar)生成静态库文件:ar rc libmagic.a magic.o ,其中rc是压缩选项,libmagic.a是给静态库文件起的名字,magic.o 就是用来生成静态库文件的二进制文件,当然后面可以接很多个.o文件,把他们压缩成一个静态库文件给别人使用。
libmagic.a 弄好以后就可以和main的二进制文件链接在一起了: gcc -o main main.o -lmagic -L.
-o main 选项是把产生的可执行文件命名为main,没有的话默认名字是a.out,-lmagic表示使用库文件libmagic.so(后面介绍)或者libmagic.a,如果都存在的话使用.so文件。现在还没有libmagic.so文件,所以链接了libmagic.a里面的magic函数。
动态库文件有些不同,直接使用gcc生成,首先还是汇编:gcc -fPIC -c magic.c ,因为汇编后的二进制代码要拿去做动态库,所以多了一个-fPIC选项,用来确定库中函数的链接位置。然后从二进制文件生成动态库文件:gcc -shared -o libmagic.so magic.o。后面可以接很多.o文件。
动态库的链接的命令和静态库一样,但是做的事情不一样。链接静态库文件是把库里面的函数复制了到了可执行文件里面,所以可执行文件生成以后有没有静态库文件就不重要了。而动态链接只是在可执行文件里面记录了那个函数需要使用的动态库文件,真正的链接是在运行(run)的时候,只有运行我们生成的可执行文件,到了要使用动态库文件里面函数的时候,那个函数才会被加载到内存中再执行。所以涉及到了操作系统寻找动态链接库的路径问题。可以使用ldd程序查看我们的程序都用到了哪些动态库文件: ldd main,输出如下:
linux-vdso.so.1 => (0x00007fff8c9dd000)
libmagic.so => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb0f846c000)
/lib64/ld-linux-x86-64.so.2 (0x00007fb0f8829000)
可以看到libmagic.so没有找到,所以如果运行main也会报错:./main: error while loading shared libraries: libmagic.so: cannot open shared object file: No such file or directory 。要让系统找到动态库文件就必须设置动态库文件的路径了(不同于可执行文件路径PATH,头文件路径INCLUDE 哦)(其实这些就是环境变量,告诉系统在哪里找到文件),如果要在动态库文件的搜寻路径里面加上当前路径,可以如下设置:
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:. /* 当前路径是. */
export LD_LIBRARY_PATH
设置好路径以后动态库文件就能被找到了,再运行ldd main,输出下面的结果:
linux-vdso.so.1 => (0x00007fffb55ff000)
libmagic.so (0x00007ff515fa7000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff515bec000)
/lib64/ld-linux-x86-64.so.2 (0x00007ff5161ab000)
关于链接再多说一句吧,gcc的链接是调用了另一个程序:ld。可以自己手动调用ld或者写在Makefile里面,不过一般不用那么麻烦,用gcc就好了。
由于链接方法不用,所以链接静态库文件后的可执行文件一般都比较大,比如上面的例子,链接静态库文件后的main大小是8498个字节,而链接动态库文件后的main的大小是8401字节。好像文件大小没少多少,那是因为我们的magic函数小,大一点区别就很明显了。
https://blog.csdn.net/high_high/article/details/7193264