简体   繁体   English

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

[英]Difference between shared objects (.so), static libraries (.a), and DLL's (.so)?

I have been involved in some debate with respect to libraries in Linux, and would like to confirm some things.我参与了一些关于 Linux 库的辩论,并想确认一些事情。

It is to my understanding (please correct me if I am wrong and I will edit my post later), that there are two ways of using libraries when building an application:据我了解(如果我错了,请纠正我,稍后我会编辑我的帖子),在构建应用程序时有两种使用库的方法:

  1. Static libraries (.a files): At link time, a copy of the entire library is put into the final application so that the functions within the library are always available to the calling application静态库(.a 文件):在链接时,将整个库的副本放入最终应用程序中,以便库中的函数始终可供调用应用程序使用<\/li>
  2. Shared objects (.so files): At link time, the object is just verified against its API via the corresponding header (.h) file.共享对象(.so 文件):在链接时,对象只是通过相应的头文件 (.h) 对其 API 进行验证。 The library isn't actually used until runtime, where it is needed.该库直到运行时才真正使用,在需要它的地方。<\/li><\/ol>

    The obvious advantage of static libraries is that they allow the entire application to be self-contained, while the benefit of dynamic libraries is that the ".so" file can be replaced (ie: in case it needs to be updated due to a security bug) without requiring the base application to be recompiled.静态库的明显优势是它们允许整个应用程序是自包含的,而动态库的好处是可以替换“.so”文件(即:如果由于安全原因需要更新它bug) 无需重新编译基础应用程序。

    I have heard some people make a distinction between shared objects and dynamic linked libraries (DLL's), even though they are both ".so" files.我听说有些人区分共享对象和动态链接库 (DLL),即使它们都是“.so”文件。 Is there any distinction between shared objects and DLLs when it comes to C\/C++ development on Linux or any other POSIX compliant OS (ie: MINIX, UNIX, QNX, etc)?在 Linux 或任何其他符合 POSIX 的操作系统(即:MINIX、UNIX、QNX 等)上进行 C\/C++ 开发时,共享对象和 DLL 之间有什么区别吗? I am told that one key difference (so far) is that shared objects are just used at runtime, while DLL's must be opened first using the dlopen() call within the application.有人告诉我,一个关键的区别(到目前为止)是共享对象只在运行时使用,而 DLL 必须首先使用应用程序中的 dlopen() 调用打开。

    Finally, I have also heard some developers mention "shared archives", which, to my understanding, are also static libraries themselves, but are never used by an application directly.最后,我还听到一些开发人员提到“共享档案”,据我了解,它本身也是静态库,但从未被应用程序直接使用。 Instead, other static libraries will link against the "shared archives" to pull some (but not all) functions\/resources from the shared archive into the static library being built.相反,其他静态库将链接到“共享档案”,以将一些(但不是全部)功能\/资源从共享档案中提取到正在构建的静态库中。

    Thank you all in advance for your assistance.预先感谢大家的帮助。

    Update更新<\/h1>

    In the context in which these terms were provided to me, it was effectively erroneous terms used by a team of Windows developers that had to learn Linux.<\/strong>在向我提供这些术语的上下文中,实际上是一组必须学习 Linux 的 Windows 开发人员使用的错误术语。<\/strong> I tried to correct them, but the (incorrect) language norms stuck.<\/strong>我试图纠正它们,但(不正确的)语言规范卡住了。<\/strong>

    1. Shared Object: A library that is automatically linked into a program when the program starts, and exists as a standalone file.共享对象:程序启动时自动链接到程序中的库,并作为独立文件存在。 The library is included in the linking list at compile time (ie: LDOPTS+=-lmylib<\/code> for a library file named mylib.so<\/code> ).该库在编译时包含在链接列表中(即: LDOPTS+=-lmylib<\/code>用于名为mylib.so<\/code>的库文件)。 The library must be present at compile time, and when the application starts.<\/strong>该库必须在编译时以及应用程序启动时存在。<\/strong><\/li>
    2. Static Library: A library that is merged into the actual program itself at build time for a single (larger) application containing the application code and the library code that is automatically linked into a program when the program is built, and the final binary containing both the main program and the library itself exists as a single standalone binary file.静态库:在构建时合并到实际程序本身的库,用于单个(更大)应用程序,其中包含应用程序代码和在构建程序时自动链接到程序中的库代码,以及包含两者的最终二进制文件主程序和库本身作为一个独立的二进制文件存在。 The library is included in the linking list at compile time (ie: LDOPTS+=-lmylib<\/code> for a library file named mylib.a).该库在编译时包含在链接列表中(即: LDOPTS+=-lmylib<\/code>用于名为 mylib.a 的库文件)。 The library must be present at compile time.<\/strong>该库必须在编译时存在。<\/strong><\/li>
    3. DLL: Essentially the same as a shared object, but rather than being included in the linking list at compile time, the library is loaded via dlopen()<\/code> \/ dlsym()<\/code> commands so that the library does not need to be present at build time for the program to compile. DLL:本质上与共享对象相同,但不是在编译时包含在链接列表中,而是通过dlopen()<\/code> \/ dlsym()<\/code>命令加载库,因此该库不需要在构建时出现要编译的程序。 Also, the library does not need to be present (necessarily) at application startup or compile time<\/strong> , as it is only needed at the moment the dlopen<\/code> \/ dlsym<\/code> calls are made.此外,在应用程序启动或编译时不需要(必然)存在该库<\/strong>,因为它仅dlopen<\/code> \/ dlsym<\/code>调用时才需要。<\/li>
    4. Shared Archive: Essentially the same as a static library, but is compiled with the "export-shared" and "-fPIC" flags.共享存档:本质上与静态库相同,但使用“export-shared”和“-fPIC”标志进行编译。 The library is included in the linking list at compile time (ie: LDOPTS+=-lmylibS<\/code> for a library file named mylibS.a<\/code> ).该库在编译时包含在链接列表中(即: LDOPTS+=-lmylibS<\/code>用于名为mylibS.a<\/code>的库文件)。 The distinction between the two is that this additional flag is required if a shared object or DLL wants to statically link the shared archive into its own code AND be able to make the functions in the shared object available to other programs, rather than just using them internal to the DLL.两者之间的区别在于,如果共享对象或 DLL 想要将共享存档静态链接到它自己的代码中并且能够使共享对象中的函数对其他程序可用,而不仅仅是使用它们,则需要这个附加标志DLL 内部。 This is useful in the case when someone provides you with a static library, and you wish to repackage it as an SO.这在有人为您提供静态库并且您希望将其重新打包为 SO 的情况下很有用。 The library must be present at compile time.<\/strong>该库必须在编译时存在。<\/strong><\/li><\/ol>

      Additional Update额外更新<\/h1>

      The distinction between " DLL<\/code> " and " shared library<\/code> " was just a (lazy, inaccurate) colloquialism in the company I worked in at the time (Windows developers being forced to shift to Linux development, and the term stuck), adhering to the descriptions noted above. DLL<\/code> ”和“ shared library<\/code> ”之间的区别只是我当时工作的公司的一种(懒惰、不准确的)俗语(Windows 开发人员被迫转向 Linux 开发,并且这个术语卡住了),坚持描述如上所述。

      Additionally, the trailing " S<\/code> " literal after the library name, in the case of "shared archives" was just a convention used at that company, and not in the industry in general.此外,在“共享档案”的情况下,库名称后面的尾随“ S<\/code> ”文字只是该公司使用的惯例,而不是一般行业中的惯例。

      "

A static library(.a) is a library that can be linked directly into the final executable produced by the linker,it is contained in it and there is no need to have the library into the system where the executable will be deployed. 静态库(.a)是一个可以直接链接到链接器生成的最终可执行文件的库,它包含在其中,并且不需要将库放入将部署可执行文件的系统中。

A shared library(.so) is a library that is linked but not embedded in the final executable, so will be loaded when the executable is launched and need to be present in the system where the executable is deployed. 共享库(.so)是一个链接但未嵌入最终可执行文件的库,因此将在可执行文件启动时加载,并且需要在部署可执行文件的系统中存在。

A dynamic link library on windows(.dll) is like a shared library(.so) on linux but there are some differences between the two implementations that are related to the OS (Windows vs Linux) : Windows(.dll)上动态链接库就像linux上的共享库(.so),但是与OS相关的两个实现之间存在一些差异(Windows vs Linux):

A DLL can define two kinds of functions: exported and internal. DLL可以定义两种功能:导出和内部。 The exported functions are intended to be called by other modules, as well as from within the DLL where they are defined. 导出的函数旨在由其他模块调用,也可以在定义它们的DLL中调用。 Internal functions are typically intended to be called only from within the DLL where they are defined. 内部函数通常仅用于在定义它们的DLL中调用。

An SO library on Linux doesn't need special export statement to indicate exportable symbols, since all symbols are available to an interrogating process. Linux上的SO库不需要特殊的导出语句来指示可导出的符号,因为所有符号都可用于询问过程。

I've always thought that DLLs and shared objects are just different terms for the same thing - Windows calls them DLLs, while on UNIX systems they're shared objects, with the general term - dynamically linked library - covering both (even the function to open a .so on UNIX is called dlopen() after 'dynamic library'). 我一直认为DLL和共享对象只是同一个东西的不同术语--Windows称之为DLL,而在UNIX系统上它们是共享对象,通用术语 - 动态链接库 - 覆盖两者(甚至是在UNIX上打开一个.so在'动态库'之后被称为dlopen() )。

They are indeed only linked at application startup, however your notion of verification against the header file is incorrect. 它们确实只在应用程序启动时链接,但是您对头文件的验证概念不正确。 The header file defines prototypes which are required in order to compile the code which uses the library, but at link time the linker looks inside the library itself to make sure the functions it needs are actually there. 头文件定义了编译使用库的代码所需的原型,但是在链接时链接器查看库本身以确保它所需的功能实际存在。 The linker has to find the function bodies somewhere at link time or it'll raise an error. 链接器必须在链接时找到函数体,否则会引发错误。 It ALSO does that at runtime, because as you rightly point out the library itself might have changed since the program was compiled. 它也可以在运行时执行此操作,因为正如您正确指出的那样,自编译程序以来,库本身可能已经发生了变化。 This is why ABI stability is so important in platform libraries, as the ABI changing is what breaks existing programs compiled against older versions. 这就是为什么ABI稳定性在平台库中如此重要的原因,因为ABI的变化是破坏针对旧版本编译的现有程序的原因。

Static libraries are just bundles of object files straight out of the compiler, just like the ones that you are building yourself as part of your project's compilation, so they get pulled in and fed to the linker in exactly the same way, and unused bits are dropped in exactly the same way. 静态库只是直接来自编译器的目标文件包,就像你在项目编译过程中自己构建的一样,所以它们以完全相同的方式被拉入并提供给链接器,未使用的位是以完全相同的方式掉落。

I can elaborate on the details of DLLs in Windows to help clarify those mysteries to my friends here in *NIX-land... 我可以详细说明Windows中DLL的细节,以帮助澄清这些神秘事物给我在这里的朋友* NIX-land ...

A DLL is like a Shared Object file. DLL就像一个共享对象文件。 Both are images, ready to load into memory by the program loader of the respective OS. 两者都是图像,准备通过相应OS的程序加载器加载到存储器中。 The images are accompanied by various bits of metadata to help linkers and loaders make the necessary associations and use the library of code. 图像伴随着各种元数据,以帮助链接器和加载器进行必要的关联并使用代码库。

Windows DLLs have an export table. Windows DLL具有导出表。 The exports can be by name, or by table position (numeric). 导出可以是名称,也可以是表位(数字)。 The latter method is considered "old school" and is much more fragile -- rebuilding the DLL and changing the position of a function in the table will end in disaster, whereas there is no real issue if linking of entry points is by name. 后一种方法被认为是“老派”并且更加脆弱 - 重建DLL并改变表中函数的位置将以灾难告终,而如果按名称链接入口点则没有实际问题。 So, forget that as an issue, but just be aware it's there if you work with "dinosaur" code such as 3rd-party vendor libs. 所以,忘记这是一个问题,但只要知道它就在那里,如果你使用“恐龙”代码,如第三方供应商的库。

Windows DLLs are built by compiling and linking, just as you would for an EXE (executable application), but the DLL is meant to not stand alone, just like an SO is meant to be used by an application, either via dynamic loading, or by link-time binding (the reference to the SO is embedded in the application binary's metadata, and the OS program loader will auto-load the referenced SO's). Windows DLL是通过编译和链接构建的,就像您对EXE(可执行应用程序)一样,但DLL本身并不孤立,就像SO应用程序要通过动态加载一样使用,或者通过链接时绑定(对SO的引用嵌入在应用程序二进制文件的元数据中,OS程序加载器将自动加载引用的SO)。 DLLs can reference other DLLs, just as SOs can reference other SOs. DLL可以引用其他DLL,就像SO可以引用其他SO一样。

In Windows, DLLs will make available only specific entry points. 在Windows中,DLL仅提供特定的入口点。 These are called "exports". 这些被称为“出口”。 The developer can either use a special compiler keyword to make a symbol an externally-visible (to other linkers and the dynamic loader), or the exports can be listed in a module-definition file which is used at link time when the DLL itself is being created. 开发人员可以使用特殊的编译器关键字使符号在外部可见(对其他链接器和动态加载器),或者导出可以在模块定义文件中列出,该文件定义文件在链接时使用,当DLL本身是被创造。 The modern practice is to decorate the function definition with the keyword to export the symbol name. 现代的做法是用关键字装饰函数定义以导出符号名称。 It is also possible to create header files with keywords which will declare that symbol as one to be imported from a DLL outside the current compilation unit. 也可以使用关键字创建头文件,该关键字将该符号声明为从当前编译单元外部的DLL导入的符号。 Look up the keywords __declspec(dllexport) and __declspec(dllimport) for more information. 查找关键字__declspec(dllexport)和__declspec(dllimport)以获取更多信息。

One of the interesting features of DLLs is that they can declare a standard "upon load/unload" handler function. DLL的一个有趣特性是它们可以声明标准的“加载/卸载”处理函数。 Whenever the DLL is loaded or unloaded, the DLL can perform some initialization or cleanup, as the case may be. 无论何时加载或卸载DLL,DLL都可以执行一些初始化或清理,视情况而定。 This maps nicely into having a DLL as an object-oriented resource manager, such as a device driver or shared object interface. 这很好地映射到将DLL作为面向对象的资源管理器,例如设备驱动程序或共享对象接口。

When a developer wants to use an already-built DLL, she must either reference an "export library" (*.LIB) created by the DLL developer when she created the DLL, or she must explicitly load the DLL at run time and request the entry point address by name via the LoadLibrary() and GetProcAddress() mechanisms. 当开发人员想要使用已经构建的DLL时,她必须引用DLL开发人员在创建DLL时创建的“导出库”(* .LIB),或者她必须在运行时显式加载DLL并请求通过LoadLibrary()和GetProcAddress()机制按名称输入入口点地址。 Most of the time, linking against a LIB file (which simply contains the linker metadata for the DLL's exported entry points) is the way DLLs get used. 大多数情况下,链接LIB文件(其中只包含DLL导出的入口点的链接器元数据)是DLL的使用方式。 Dynamic loading is reserved typically for implementing "polymorphism" or "runtime configurability" in program behaviors (accessing add-ons or later-defined functionality, aka "plugins"). 动态加载通常用于在程序行为中实现“多态性”或“运行时可配置性”(访问附加组件或后来定义的功能,也称为“插件”)。

The Windows way of doing things can cause some confusion at times; Windows的做事方式有时会引起一些混乱; the system uses the .LIB extension to refer to both normal static libraries (archives, like POSIX *.a files) and to the "export stub" libraries needed to bind an application to a DLL at link time. 系统使用.LIB扩展名来引用常规静态库(存档,如POSIX * .a文件)和链接时将应用程序绑定到DLL所需的“导出存根”库。 So, one should always look to see if a *.LIB file has a same-named *.DLL file; 因此,应始终查看* .LIB文件是否具有相同名称的* .DLL文件; if not, chances are good that *.LIB file is a static library archive, and not export binding metadata for a DLL. 如果没有,* .LIB文件是静态库存档的可能性很大,而不是DLL的导出绑定元数据。

You are correct in that static files are copied to the application at link-time, and that shared files are just verified at link time and loaded at runtime. 您是正确的,因为静态文件在链接时被复制到应用程序,并且该共享文件仅在链接时验证并在运行时加载。

The dlopen call is not only for shared objects, if the application wishes to do so at runtime on its behalf, otherwise the shared objects are loaded automatically when the application starts. dlopen调用不仅适用于共享对象,如果应用程序希望在运行时代表它,则在应用程序启动时自动加载共享对象。 DLLS and .so are the same thing. DLLS和.so是一回事。 the dlopen exists to add even more fine-grained dynamic loading abilities for processes. dlopen的存在是为了为进程添加更细粒度的动态加载能力。 You dont have to use dlopen yourself to open/use the DLLs, that happens too at application startup. 您不必自己使用dlopen打开/使用DLL,这在应用程序启动时也会发生。

I suspect some kind of misunderstanding here, but header files, at least of the .h variety used for compiling source code, are most definitely NOT checked during link time.我怀疑这里存在某种误解,但头文件,至少是用于编译源代码的 .h 文件,绝对不会在链接时检查。

.h, and for that matter, .c/.cpp files, are only involved during the compilation phase, which includes preprocessing. .h 和 .c/.cpp 文件仅在编译阶段涉及,其中包括预处理。 Once the object code has been created the header file is long gone well before the linker gets around to dealing with things.一旦创建了目标代码,在链接器开始处理事情之前,头文件早就消失了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM