C++ 为什么共享库和静态库是不同的?

C++ 为什么共享库和静态库是不同的?,c++,static-linking,dynamic-linking,C++,Static Linking,Dynamic Linking,对于应用程序开发人员来说,共享(.so)库和静态(.a)库之间的区别完全在于如何使用它们——粗略地说,是将所需的库代码复制到程序中,还是仅从程序中引用然后在运行时加载 从概念上(天真地)似乎只有一种库。在构建自己的应用程序时,可以选择静态链接还是动态链接.so和.a之间的技术区别是什么?它们要求在构建库时而不是在构建应用程序时进行选择? 打个比方:在餐馆里,你可以点食物留下或带走,但这是你如何“使用”食物的选择;厨师给你做同样的汉堡包 它是特定于操作系统的 在Linux上,共享库具有一些静态库没

对于应用程序开发人员来说,共享(.so)库和静态(.a)库之间的区别完全在于如何使用它们——粗略地说,是将所需的库代码复制到程序中,还是仅从程序中引用然后在运行时加载

从概念上(天真地)似乎只有一种库。在构建自己的应用程序时,可以选择静态链接还是动态链接.so和.a之间的技术区别是什么?它们要求在构建库时而不是在构建应用程序时进行选择?


打个比方:在餐馆里,你可以点食物留下或带走,但这是你如何“使用”食物的选择;厨师给你做同样的汉堡包

它是特定于操作系统的

在Linux上,共享库具有一些静态库没有的特性

  • 共享库是一个共享对象文件

  • 共享库的某些错误发生在运行时(在
    ld linux.so

  • 将共享库更新为更新版本(用于修复bug)对应用程序来说非常简单和透明(升级共享库后,只需重新启动使用它的应用程序)

  • 共享库由多个进程共享(它们使用磁盘上的同一文件,并且大部分内存,特别是它们的内存,都是共享的)
  • 您可以将一个共享库链接到另一个共享库(但不能将静态库真正链接到另一个静态库;您可以将其成员复制到另一个静态库)
  • 您可以使用
    可见性
    属性限制已定义名称对该共享库的可见性
  • 您可以使用
    dlopen
  • 您应该按照
    的方式构建共享库(理论上,您不必创建PIC共享库。但实际上,出于性能和技术原因,您应该这样做)。
    这就是为什么您需要以不同于静态库的方式构建共享库的原因
  • ELF符号版本控制与共享库有关
静态库几乎变得毫无用处(至少在原则上是如此)。在实践中,它们主要用于构建您不想依赖外部资源(例如
libc.so
ld linux.so
)的少数可执行文件(例如
/bin/sash
),或者当您想避免

开发人员还应注意不要加载同一个共享库,即
mmap
-ed-两次(但是
dlopen
ld-linux。因此
通常非常关心这一点)。当这种情况发生时,数据段可能会被复制并发生混乱

一个更好的提问方式可以是“我什么时候应该避免共享库”?答案几乎是“永远不会”(除了少数例外)

读到


顺便说一句,它主要是一个历史文物。在Linux 1(或Linux 0.99)内核的旧时代(1990年至1995年),内核还不支持ELF,而且
a.out
共享库非常痛苦(当时没有PIC,您必须全局决定使用的地址段)。而且,在当时,处理器的运行时间比现在慢了数百倍,因此运行时链接启动时间可能会有所不同。

这与食物完全不同,因为共享库是共享的。你几乎不会点一个汉堡包,任何给定数量的人都会在你吃的时候吃。这就是为什么您需要不同的库实现,它们要么驻留在其他人可以访问它们的内存中,要么加载供您专用。

在构建库时(或者更准确地说,在安装库时,或者在构建二进制包时),可以选择构建静态库、共享库或两者兼而有之。如果依赖项仅存在于一个表单中,则可以选择仅生成(并安装)该表单,或者重新生成/重新安装所需格式的依赖项。应用程序的构建者/安装者面临同样的选择。影响安装选择的库之间唯一的技术区别是已安装依赖项的状态。或者,换一种说法,没有技术上的差异会影响到建造哪一个的决定。(磁盘空间、运行时延迟等问题除外,但这些决定将推迟到构建应用程序之后。)


换句话说,选择是在构建应用程序时做出的

IMO的主要区别在于,动态库可以由已构建的应用程序加载。这意味着,如果dll中存在错误,那么可以通过只重建库来修复错误(只要不弄乱符号)。
此外,运行时链接允许dll作为扩展应用程序功能的插件。应用程序会在一个目录中搜索它们,并加载所有它们,只要它们的界面是相同的。

所以我看到了很多关于为什么要使用共享库而不是静态库的答案,但我想你的问题是,为什么它们现在甚至是不同的东西,也就是说,为什么不能将共享库用作静态库,并在构建时从中提取所需内容

以下是一些原因。其中一些是历史性的——请记住,像二进制格式这样的基本格式在计算机系统中变化非常缓慢

编译方式不同 代码可以编译为依赖于它所在的地址(位置相关)或独立(位置独立)。这会影响全局常量的加载、函数调用等。如果位置相关代码没有按预期的地址加载,则需要进行修复,即加载程序必须遍历代码并实际更改偏移量

执行董事