我正在尝试了解文件系统层次结构标准。我已经查找了二进制文件和库,并且据我目前的理解:
二进制文件是二进制格式的计算机可读代码文件,它们直接用位控制CPU和处理器。
为了方便起见,库是可由各种程序使用的函数-例如,当您需要PHP Javascript中的模块时。
这种理解正确吗?如果是这样,为什么我们仍将库和二进制文件分开?有些库是二进制文件,对不对?还有一些二进制文件(cat,less,date,rm,cp等)被使用和重用,就好像它们是库一样。有人可以帮助解释它们的区别,并帮助我为这两个单词找到更好的定义吗?谢谢。
您的理解大体上是正确的,但还需要考虑一些其他事项:
/lib
都将是编译成机器代码的库。cat
的东西在外壳脚本中使用,例如对库中的代码的调用,但它们并不是FHS的库,因为它们可以自己运行。由于上述几点,在不编写标准文档的人们中,更常见的术语是:
.o
扩展名,除非它们属于其他类别之一,并且除构建软件外,在大多数系统上几乎从未见过。我在这里列出了它们,因为它们对于理解以下几条内容很重要。cat
,bash
和python
,都是这种类型的可执行文件),也可以由本身是可执行文件的某些中间程序来解释(Minecraft pydoc
,和cowsay
都是示例)这类可执行文件)。第一种可执行文件在UNIX系统上几乎没有文件扩展名,而第二种可执行文件则可能有也可能没有。这就是FHS所谓的“二进制文件”。他们可以从其他可执行文件运行,但需要调用特殊功能调用它们(fork()
以及exec()
在C和C ++,东西出来的subprocess
Python等模块),并作为单独的进程运行。.a
扩展名。静态库的概念在编译的编程语言之外并不存在。.so
在UNIX 上具有扩展名(.dll
Windows 上是标准扩展名),该文件在运行时由使用它的可执行文件加载。/lib
在生产系统上可以找到的大多数是动态库。http.server
有关示例,请参见Python标准库)。另外附上一篇比较完整的讲解各种文件区别的文章。
头文件和库文件区别,动态库和静态库的区别,动静态库的生成
头文件是包含函数声明,宏定义,类的声明的文件。
在linux中一般头文件会在/usr/include中,如果没有可以使用 locate命令查找文件所在位置。
库文件是一种目标文件,静态库是可重定位目标文件,动态库是共享目标文件。(后面有解释)
一般在/usr/lib、/usr/lib64、/lib、/lib64都包含库文件
头文件是在预处理时使用;库文件是链接时使用。
头文件内容还是高级语言内容;库文件是二进制文件。
在解释静态库和动态库之前,需要简单了解一下什么是目标文件。目标文件常常按照特定格式来组织,在linux下,它是ELF格式(Executable Linkable Format,可执行可链接格式),而在windows下是PE(Portable Executable,可移植可执行)。
而通常目标文件有三种形式:
可执行目标文件。即我们通常所认识的,可直接运行的二进制文件。
可重定位目标文件。包含了二进制的代码和数据,可以与其他可重定位目标文件合并,并创建一个可执行目标文件。
共享目标文件。它是一种在加载或者运行时进行链接的特殊可重定位目标文件。
使用readelf -a filename 可以查看目标文件的ELF格式
静态库在linux中是以.a(archive)为后缀,作用是在进行链接生成可执行文件时,从静态库文件中拷贝需要的内容到最终的可执行文件中。
//在使用gcc编译时采用 -static选项来进行静态文件的链接:
gcc -c main.c
gcc -static -o main main.o
动态库在linux中是以.so(shared object)为后缀,它并不在链接时将需要的二进制代码都拷贝到可执行文件中,而是拷贝一些重定位和符号表信息,当程序运行时需要的时候再通过符号表从动态库中获取。
//使用gcc编译默认采用动态链接
gcc -o main main.c
首先要熟悉程序编译过程
预处理->编译->汇编->链接
gcc -E -o main.i main.c
gcc -S -o main.S main.i
gcc -c -o main.o main.S
gcc -o main main.o
静态链接的可执行文件要比动态链接的可执行文件大得多,因为它将需要用到的代码从二进制文件中拷贝了一份,而动态链接仅仅是复制了一些重定位和符号表信息。
如果有多个可执行文件,那么静态库中的同一个函数的代码就会被复制多次,而动态库只有一份,因此使用静态库占用的磁盘空间相对比动态库要大。
如果静态库中某个函数的实现变了,那么可执行文件必须重新编译,而对于动态链接生成的可执行文件,只需要更新动态库本身即可,不需要重新编译可执行文件。正因如此,使用动态库的程序方便升级和部署。
静态连接的可执行文件不需要依赖其他的内容即可运行,而动态链接的可执行文件必须依赖动态库的存在。所以如果你在安装一些软件的时候,提示某个动态库不存在的时候也就不奇怪了。
即便如此,系统中一般存在一些大量公用的库,所以使用动态库并不会有什么问题。
相对来说,动态库的处理要比静态库要复杂,例如如何在运行时确认地址?多个进程如何共享一个动态库?当然,作为调用者我们不需要关注,另外动态库版本的管理也是一项技术活。这也不在本文的讨论范围。
由于静态库在链接时就和可执行文件在一块了,而动态库在加载或者运行时才链接,因此,对于同样的程序,静态链接的要比动态链接加载更快。所以选择静态库还是动态库是空间和时间的考量。但是通常来说,牺牲这点性能来换取程序在空间上的节省和部署的灵活性是值得的。再加上局部性原理,牺牲的性能并不多。(局部性原理是指CPU访问存储器时,无论是存取指令还是存取数据,所访问的存储单元都趋于聚集在一个较小的连续区域中。)
//1.先写出相应的.h文件和对应的.c文件
//2.编译.c文件
//3.使用ar工具将.o文件归档生成.a静态库文件
[root@localhost linux]# ls
add.c add.h main.c sub.c sub.h
[root@localhost linux]# gcc -c add.c -o add.o
[root@localhost linux]# gcc -c sub.c -o sub.o
生成静态库
[root@localhost linux]# ar -rc libmymath.a add.o sub.o
ar是gnu归档工具,rc表示(replace and create)
查看静态库中的目录列表
[root@localhost linux]# ar -tv libmymath.a
rw-r–r-- 0/0 1240 Sep 15 16:53 2017 add.o
rw-r–r-- 0/0 1240 Sep 15 16:53 2017 sub.o
t:列出静态库中的文件
v:verbose 详细信息
[root@localhost linux]# gcc main.c -L. -lmymath
-L 指定库路径
-l 指定库名
测试目标文件生成后,静态库删掉,程序照样可以运行。
注意:静态库文件和动态库文件的命名规则是libxxxx.so/libxxxx.a,在进行 链接时只用lxxxx即可
示例:
[root@localhost linux]# gcc -fPIC -c sub.c add.c
[root@localhost linux]# gcc -shared -o libmymath.so *.o
[root@localhost linux]# ls
add.c add.h add.o libmymath.so main.c sub.c sub.h sub.o
静态库和动态库的具体链接方式并没在本文讨论,本文仅仅介绍动静态库的区别和是什么和怎么生成,对于我来说已经足够。更多内容需要读者自行阅读相关书籍。