二进制文件和库之间有什么区别?

问题

我正在尝试了解文件系统层次结构标准。我已经查找了二进制文件和库,并且据我目前的理解:

二进制文件是二进制格式的计算机可读代码文件,它们直接用位控制CPU和处理器。

为了方便起见,是可由各种程序使用的函数-例如,当您需要PHP Javascript中的模块时。

这种理解正确吗?如果是这样,为什么我们仍将库和二进制文件分开?有些库二进制文件,对不对?还有一些二进制文件(cat,less,date,rm,cp等)被使用和重用,就好像它们是库一样。有人可以帮助解释它们的区别,并帮助我为这两个单词找到更好的定义吗?谢谢。

回答

您的理解大体上是正确的,但还需要考虑一些其他事项:

  1. “二进制”是指人类无法理解的东西。这通常是指机器代码,但是从这个意义上讲,许多其他文件也是二进制文件,其中大多数多媒体格式就是一个很好的例子。但是,FHS对于该术语有更具体的用法。
  2. 库可以是二进制代码。实际上,其中的大部分内容/lib都将是编译成机器代码的库。
  3. 尽管诸如此类cat的东西在外壳脚本中使用,例如对库中的代码的调用,但它们并不是FHS的库,因为它们可以自己运行。

由于上述几点,在不编写标准文档的人们中,更常见的术语是:

  • 目标文件:这些是本机编译的机器代码,但是甚至无法运行或不可调用。它们通常具有.o扩展名,除非它们属于其他类别之一,并且除构建软件外,在大多数系统上几乎从未见过。我在这里列出了它们,因为它们对于理解以下几条内容很重要。
  • 可执行文件:这些文件主要由可直接运行的自包含代码组成。它们可以是可以由内核直接加载的特殊格式的目标文件(诸如catbashpython,都是这种类型的可执行文件),也可以由本身是可执行文件的某些中间程序来解释(Minecraft pydoc,和cowsay都是示例)这类可执行文件)。第一种可执行文件在UNIX系统上几乎没有文件扩展名,而第二种可执行文件则可能有也可能没有。这就是FHS所谓的“二进制文件”。他们可以从其他可执行文件运行,但需要调用特殊功能调用它们(fork()以及exec()在C和C ++,东西出来的subprocess Python等模块),并作为单独的进程运行。
  • 库:这些文件包含可重用的代码,这些代码可被另一个库或可执行文件调用。一旦加载了库(在谈论已编译的代码时称为“链接”),库中的代码就会(通常)被其他代码直接调用,并在与调用它的代码相同的过程中运行。共有三种类型的库:
    1. 静态库:这些是原始库。它们由一个归档文件(通常为AR格式)组成,内部有大量目标文件,每个目标函数对应一个。目标文件被链接到使用它们的可执行文件中,因此仅使用静态库的可执行文件本质上100%独立于任何其他代码。在UNIX系统上,它们通常具有.a扩展名。静态库的概念在编译的编程语言之外并不存在。
    2. 动态库:这些是当今最常用的库类型。动态库是一个特殊的对象文件,通常.so在UNIX 上具有扩展名(.dllWindows 上是标准扩展名),该文件在运行时由使用它的可执行文件加载。/lib在生产系统上可以找到的大多数是动态库。
    3. 模块:这相当于解释语言的动态库。处理与编译语言略有不同,并且与编译语言不同,文件可能既是模块又是可执行文件(http.server有关示例,请参见Python标准库)。

另外附上一篇比较完整的讲解各种文件区别的文章。

头文件和库文件区别,动态库和静态库的区别,动静态库的生成

  • 一、什么是头文件?什么是库文件?有什么区别?
    • 先说总结
    • 目标文件
  • 二、什么是静态库?什么是动态库?有什么区别?
  • 三、为什么只用在程序头部写上包含的头文件,头文件中并没有实现内容就可以使用声明的函数呢?
    • 动静态库区别
        • 1.可执行文件大小不一样
        • 2.占用磁盘大小不一样
        • 3.拓展性与兼容性不一样
        • 4.依赖不一样
        • 5.复杂性不一样
        • 6.加载速度不一样
  • 四、如何生成动静态库文件
      • 静态库的生成
      • 库文件的搜索路径
      • 动态库的生成
        • 总结
  • 参考

一、什么是头文件?什么是库文件?有什么区别?

先说总结

头文件是包含函数声明,宏定义,类的声明的文件。

在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

三、为什么只用在程序头部写上包含的头文件,头文件中并没有实现内容就可以使用声明的函数呢?

首先要熟悉程序编译过程

预处理->编译->汇编->链接

  • 预处理(preprocessing)的时候把头文件内容包含进来。

gcc -E -o main.i main.c

  • 编译,但不包括汇编(compilation, do not assemble)将预处理后的文件转换成汇编代码。

gcc -S -o main.S main.i

  • 汇编将编译后的程序转换为二进制文件,也就是可重定向目标文件。

gcc -c -o main.o main.S

  • 链接将具体的动态库或者静态库中的代码(也就是包的头文件中的代码实现部分)拷贝代码或拷贝符号表的方式,生成可执行目标文件。

gcc -o main main.o

动静态库区别

1.可执行文件大小不一样

静态链接的可执行文件要比动态链接的可执行文件大得多,因为它将需要用到的代码从二进制文件中拷贝了一份,而动态链接仅仅是复制了一些重定位和符号表信息。

2.占用磁盘大小不一样

如果有多个可执行文件,那么静态库中的同一个函数的代码就会被复制多次,而动态库只有一份,因此使用静态库占用的磁盘空间相对比动态库要大。

3.拓展性与兼容性不一样

如果静态库中某个函数的实现变了,那么可执行文件必须重新编译,而对于动态链接生成的可执行文件,只需要更新动态库本身即可,不需要重新编译可执行文件。正因如此,使用动态库的程序方便升级和部署。

4.依赖不一样

静态连接的可执行文件不需要依赖其他的内容即可运行,而动态链接的可执行文件必须依赖动态库的存在。所以如果你在安装一些软件的时候,提示某个动态库不存在的时候也就不奇怪了。

即便如此,系统中一般存在一些大量公用的库,所以使用动态库并不会有什么问题。

5.复杂性不一样

相对来说,动态库的处理要比静态库要复杂,例如如何在运行时确认地址?多个进程如何共享一个动态库?当然,作为调用者我们不需要关注,另外动态库版本的管理也是一项技术活。这也不在本文的讨论范围。

6.加载速度不一样

由于静态库在链接时就和可执行文件在一块了,而动态库在加载或者运行时才链接,因此,对于同样的程序,静态链接的要比动态链接加载更快。所以选择静态库还是动态库是空间和时间的考量。但是通常来说,牺牲这点性能来换取程序在空间上的节省和部署的灵活性是值得的。再加上局部性原理,牺牲的性能并不多。(局部性原理是指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即可

库文件的搜索路径

  • 从左往右搜索-L指定的目录
  • 有环境变量指定的目录(LIBRAY_PATH)
  • 由系统指定的目录
    • /usr/lib
    • /usr/local/lib

动态库的生成

  • shared:表示生成共享库格式
  • fPIC:产生位置无关码(position independent code)

示例:

[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

总结

静态库和动态库的具体链接方式并没在本文讨论,本文仅仅介绍动静态库的区别和是什么和怎么生成,对于我来说已经足够。更多内容需要读者自行阅读相关书籍。

你可能感兴趣的:(C语言,C++,bash,开发语言)