共享对象(.so)、静态库(.a)和 DLL(.so)之间的区别?

2024-10-14 08:40:00
admin
原创
325
摘要:问题描述:我参与过一些有关 Linux 中的库的争论,并且想确认一些事情。据我了解(如果我错了,请纠正我,我稍后会编辑我的帖子),构建应用程序时有两种使用库的方法:静态库(.a 文件):在链接时,将整个库的副本放入最终应用程序中,以便调用应用程序始终可以使用库中的函数共享对象(.so 文件):在链接时,仅通过...

问题描述:

我参与过一些有关 Linux 中的库的争论,并且想确认一些事情。

据我了解(如果我错了,请纠正我,我稍后会编辑我的帖子),构建应用程序时有两种使用库的方法:

  1. 静态库(.a 文件):在链接时,将整个库的副本放入最终应用程序中,以便调用应用程序始终可以使用库中的函数

  2. 共享对象(.so 文件):在链接时,仅通过相应的头文件 (.h) 验证对象是否符合其 API。直到运行时才实际使用该库,此时需要它。

静态库的明显优势在于它们允许整个应用程序自包含,而动态库的好处在于可以替换“.so”文件(即,如果由于安全漏洞而需要更新它),而无需重新编译基础应用程序。

我听说有些人会区分共享对象和动态链接库 (DLL),尽管它们都是“.so”文件。在 Linux 或任何其他符合 POSIX 的操作系统(即 MINIX、UNIX、QNX 等)上进行 C/C++ 开发时,共享对象和 DLL 之间有什么区别吗?我听说一个关键区别(到目前为止)是共享对象仅在运行时使用,而 DLL 必须先使用应用程序中的 dlopen() 调用打开。

最后,我还听到一些开发人员提到“共享档案”,据我所知,它们本身也是静态库,但从未被应用程序直接使用。相反,其他静态库将链接到“共享档案”,以将共享档案中的一些(但不是全部)函数/资源拉入正在构建的静态库中。

更新


在向我提供这些术语的上下文中,它们实际上是一组必须学习 Linux 的 Windows 开发人员使用的错误术语。我试图纠正它们,但(错误的)语言规范仍然存在。

  1. 共享对象:程序启动时自动链接到程序的库,作为独立文件存在。库在编译时包含在链接列表中(即:LDOPTS+=-lmylib对于名为 的库文件mylib.so)。库必须在编译时以及应用程序启动时存在。

  2. 静态库:在构建单个(较大)应用程序时合并到实际程序本身的库,其中包含应用程序代码和库代码,在构建程序时会自动链接到程序中,而包含主程序和库本身的最终二进制文件作为单个独立二进制文件存在。库在编译时包含在链接列表中(即:LDOPTS+=-lmylib对于名为 的库文件mylib.a)。库必须在编译时存在。

  3. DLL:本质上与共享对象相同,但库不是在编译时包含在链接列表中,而是通过dlopen()/dlsym()命令加载,因此在构建时无需存在库即可编译程序。此外,库不需要(必然)在应用程序启动或编译时存在,因为它仅在进行dlopen/调用时才需要。dlsym

  4. 共享存档:本质上与静态库相同,但使用“export-shared”和“ -fPIC”标志进行编译。库在编译时包含在链接列表中(即:LDOPTS+=-lmylibS对于名为 的库文件mylibS.a)。两者之间的区别在于,如果共享对象或 DLL 想要将共享存档静态链接到其自己的代码中,并且能够使共享对象中的函数可供其他程序使用,而不仅仅是在 DLL 内部使用它们,则需要此附加标志。当有人为您提供静态库,而您希望将其重新打包为 SO 时,这很有用。库必须在编译时存在。

附加更新

DLL“ ” 和 “ ”之间的区别shared library只是我当时所在公司的一种(懒惰、不准确的)口语化说法(Windows 开发人员被迫转向 Linux 开发,因此这个术语保留了下来),遵循上述描述。

此外,在“共享档案”的情况下,库名称后面的尾随“ S”文字只是该公司使用的惯例,而不是整个行业的惯例。


解决方案 1:

静态库(.a)是可以直接链接到链接器生成的最终可执行文件中的库;它包含在其中,并且不需要在将要部署可执行文件的系统中拥有该库。

共享库(.so)是链接但未嵌入最终可执行文件的库,因此它将在启动可执行文件时加载,并且需要存在于部署可执行文件的系统中。

Windows 上的动态链接库(.dll)类似于Linux 上的共享库(.so),但两种实现之间存在一些与操作系统(Windows 与 Linux)相关的差异:

DLL可以定义两种函数:导出函数和内部函数。导出函数旨在由其他模块调用,也可以从定义它们的 DLL 内部调用。内部函数通常仅从定义它们DLL 内部调用。

Linux 上的SO库不需要特殊的导出语句来指示可导出符号,因为所有符号对于查询过程都是可用的。

解决方案 2:

我一直认为 DLL 和共享对象只是同一事物的不同术语 - Windows 将它们称为 DLL,而在 UNIX 系统上,它们是共享对象,通用术语 - 动态链接库 - 涵盖两者(甚至在 UNIX 上打开 .so 的函数dlopen()在“动态库”之后调用)。

它们确实只在应用程序启动时链接,但是您对头文件的验证概念是错误的。头文件定义了编译使用库的代码所需的原型,但在链接时,链接器会查看库本身以确保它所需的函数确实存在。链接器必须在链接时在某处找到函数体,否则会引发错误。它也在运行时执行此操作,因为正如您正确指出的那样,自程序编译以来,库本身可能已发生变化。这就是为什么 ABI 稳定性在平台库中如此重要的原因,因为 ABI 变化会破坏针对旧版本编译的现有程序。

静态库只是直接从编译器中提取的目标文件包,就像您在项目编译过程中自己构建的那些一样,因此它们以完全相同的方式被拉入并提供给链接器,未使用的位以完全相同的方式被删除。

解决方案 3:

我可以详细说明 Windows 中 DLL 的细节,以帮助向 *NIX-land 中的朋友们澄清这些谜团……

DLL 类似于共享对象文件。两者都是图像,可由相应操作系统的程序加载器加载到内存中。图像附带各种元数据,以帮助链接器和加载器进行必要的关联并使用代码库。

Windows DLL 有一个导出表。导出可以按名称进行,也可以按表位置(数字)进行。后一种方法被认为是“老式的”,而且更加脆弱——重建 DLL 并更改函数在表中的位置将导致灾难,而如果按名称链接入口点,则不会出现真正的问题。所以,忘掉这个问题吧,但只要注意,如果你使用“恐龙”代码(例如第三方供应商库),它就在那里。

Windows DLL 是通过编译和链接构建的,就像 EXE(可执行应用程序)一样,但 DLL 并非独立存在,就像 SO 是由应用程序使用一样,无论是通过动态加载还是通过链接时绑定(对 SO 的引用嵌入在应用程序二进制文件的元数据中,操作系统程序加载器将自动加载引用的 SO)。DLL 可以引用其他 DLL,就像 SO 可以引用其他 SO 一样。

在 Windows 中,DLL 将只提供特定的入口点。这些入口点称为“导出”。开发人员可以使用特殊的编译器关键字使符号在外部可见(对其他链接器和动态加载器而言),或者可以在模块定义文件中列出导出,该文件在创建 DLL 本身时用于链接。现代做法是使用关键字修饰函数定义以导出符号名称。还可以创建带有关键字的头文件,该头文件将声明该符号将从当前编译单元之外的 DLL 导入。查找关键字 __declspec(dllexport) 和 __declspec(dllimport) 以获取更多信息。

DLL 的一个有趣特性是它们可以声明一个标准的“加载/卸载时”处理函数。无论何时加载或卸载 DLL,DLL 都可以执行一些初始化或清理,视情况而定。这很好地映射到将 DLL 用作面向对象的资源管理器,例如设备驱动程序或共享对象接口。

当开发人员想要使用已构建的 DLL 时,她必须引用 DLL 开发人员在创建 DLL 时创建的“导出库”(*.LIB),或者必须在运行时显式加载 DLL 并通过 LoadLibrary() 和 GetProcAddress() 机制按名称请求入口点地址。大多数情况下,链接到 LIB 文件(仅包含 DLL 导出入口点的链接器元数据)是使用 DLL 的方式。动态加载通常用于在程序行为(访问附加组件或后来定义的功能,又称“插件”)中实现“多态性”或“运行时可配置性”。

Windows 的做事方式有时会造成一些混乱;系统使用 .LIB 扩展名来引用普通静态库(档案,如 POSIX .a 文件)和在链接时将应用程序绑定到 DLL 所需的“导出存根”库。因此,应始终查看 .LIB 文件是否有同名的 .DLL 文件;如果没有,则很可能 .LIB 文件是静态库档案,而不是 DLL 的导出绑定元数据。

解决方案 4:

您说得对,静态文件在链接时被复制到应用程序,而共享文件只是在链接时进行验证并在运行时加载

dlopen如果应用程序希望在运行时代表它执行此操作,则调用不仅适用于共享对象,否则共享对象会在应用程序启动时自动加载。DLLS 和是.so同一回事。存在dlopen是为了为进程添加更细粒度的动态加载能力。您不必亲自dlopen打开/使用 DLL,这也会在应用程序启动时发生。

解决方案 5:

我怀疑这里存在某种误解,但头文件(至少是用于编译源代码的 .h 类型的头文件)在链接时肯定不会被检查。

.h 和 .c/.cpp 文件只在编译阶段(包括预处理)才会出现。一旦创建了目标代码,头文件在链接器开始处理之前就已经消失了。

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1120  
  IPD(Integrated Product Development,集成产品开发)流程是一种广泛应用于高科技和制造业的产品开发方法论。它通过跨职能团队的紧密协作,将产品开发周期缩短,同时提高产品质量和市场成功率。在IPD流程中,CDCP(Concept Decision Checkpoint,概念决策检查点)是一个关...
IPD培训课程   75  
  研发IPD(集成产品开发)流程作为一种系统化的产品开发方法,已经在许多行业中得到广泛应用。它不仅能够提升产品开发的效率和质量,还能够通过优化流程和资源分配,显著提高客户满意度。客户满意度是企业长期成功的关键因素之一,而IPD流程通过其独特的结构和机制,能够确保产品从概念到市场交付的每个环节都围绕客户需求展开。本文将深入...
IPD流程   66  
  IPD(Integrated Product Development,集成产品开发)流程是一种以跨职能团队协作为核心的产品开发方法,旨在通过优化资源分配、提高沟通效率以及减少返工,从而缩短项目周期并提升产品质量。随着企业对产品上市速度的要求越来越高,IPD流程的应用价值愈发凸显。通过整合产品开发过程中的各个环节,IPD...
IPD项目管理咨询   76  
  跨部门沟通是企业运营中不可或缺的一环,尤其在复杂的产品开发过程中,不同部门之间的协作效率直接影响项目的成败。集成产品开发(IPD)作为一种系统化的项目管理方法,旨在通过优化流程和增强团队协作来提升产品开发的效率和质量。然而,跨部门沟通的复杂性往往成为IPD实施中的一大挑战。部门之间的目标差异、信息不对称以及沟通渠道不畅...
IPD是什么意思   70  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用