Linux 共享对象 (.so)、静态库 (.a) 和 DLL (.so) 之间的区别?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9688200/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Difference between shared objects (.so), static libraries (.a), and DLL's (.so)?
提问by Cloud
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:
据我所知(如果我错了,请纠正我,我稍后会编辑我的帖子),在构建应用程序时有两种使用库的方法:
- 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
- Shared objects (.so files): At link time, the object is just verified against its API via the corresponding header (.h) file. The library isn't actually used until runtime, where it is needed.
- 静态库(.a 文件):在链接时,将整个库的副本放入最终应用程序,以便库中的函数始终可供调用应用程序使用
- 共享对象(.so 文件):在链接时,对象只是通过相应的头文件 (.h) 对其 API 进行验证。直到运行时才实际使用该库,在那里需要它。
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. 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)? 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),即使它们都是“.so”文件。在 Linux 或任何其他符合 POSIX 的操作系统(即:MINIX、UNIX、QNX 等)上进行 C/C++ 开发时,共享对象和 DLL 之间有什么区别吗?有人告诉我,一个主要区别(到目前为止)是共享对象仅在运行时使用,而 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
更新
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. I tried to correct them, but the (incorrect) language norms stuck.
在向我提供这些术语的上下文中,实际上是一组必须学习 Linux 的 Windows 开发人员使用的错误术语。我试图纠正它们,但(不正确的)语言规范卡住了。
- 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
for a library file namedmylib.so
). The library must be present at compile time, and when the application starts. - 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
for a library file named mylib.a). The library must be present at compile time. - 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()
/dlsym()
commands so that the library does not need to be present at build time for the program to compile. Also, the library does not need to be present (necessarily) at application startup or compile time, as it is only needed at the moment thedlopen
/dlsym
calls are made. - Shared Archive: Essentially the same as a static library, but is compiled with the "export-shared" and "-fPIC" flags. The library is included in the linking list at compile time (ie:
LDOPTS+=-lmylibS
for a library file namedmylibS.a
). 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. This is useful in the case when someone provides you with a static library, and you wish to repackage it as an SO. The library must be present at compile time.
- 共享对象:程序启动时自动链接到程序中的库,并作为独立文件存在。该库在编译时包含在链接列表中(即:
LDOPTS+=-lmylib
对于名为 的库文件mylib.so
)。该库必须在编译时和应用程序启动时存在。 - 静态库:在构建时合并到实际程序本身的库,用于包含应用程序代码和构建程序时自动链接到程序的库代码的单个(较大)应用程序,以及包含两者的最终二进制文件主程序和库本身作为一个独立的二进制文件存在。该库在编译时包含在链接列表中(即:
LDOPTS+=-lmylib
对于名为 mylib.a 的库文件)。该库必须在编译时存在。 - DLL:本质上与共享对象相同,但不是在编译时包含在链接列表中,而是通过
dlopen()
/dlsym()
命令加载库,以便程序编译时无需在构建时存在库。此外,库不需要(必须)在应用程序启动或编译时出现,因为它只在dlopen
/dlsym
调用时才需要。 - 共享存档:本质上与静态库相同,但使用“export-shared”和“-fPIC”标志编译。该库在编译时包含在链接列表中(即:
LDOPTS+=-lmylibS
对于名为 的库文件mylibS.a
)。两者之间的区别在于,如果共享对象或 DLL 想要将共享存档静态链接到其自己的代码中并且能够使共享对象中的函数可供其他程序使用,而不是仅仅使用它们,则需要此附加标志DLL 内部。当有人为您提供静态库,而您希望将其重新打包为 SO 时,这很有用。该库必须在编译时存在。
Additional Update
额外更新
The distinction between "DLL
" and "shared library
" 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
”和“ shared library
”之间的区别只是我当时工作的公司中的(懒惰的,不准确的)口语(Windows开发人员被迫转向Linux开发,并且该术语被卡住了),遵循上述描述。
Additionally, the trailing "S
" 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
“共享档案”的情况下,库名称后面的尾随“ ”文字只是该公司使用的惯例,而不是一般行业使用的惯例。
采纳答案by Matthew Walton
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.
静态库只是直接从编译器中输出的目标文件包,就像您在项目编译过程中自己构建的那些一样,因此它们以完全相同的方式被拉入并提供给链接器,未使用的位是以完全相同的方式下降。
回答by rapadura
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. DLLS and .so are the same thing. the dlopen exists to add even more fine-grained dynamic loading abilities for processes. You dont have to use dlopen yourself to open/use the DLLs, that happens too at application startup.
dlopen 调用不仅适用于共享对象,如果应用程序希望在运行时代表它这样做,否则在应用程序启动时会自动加载共享对象。DLLS 和 .so 是一回事。dlopen 的存在是为了为进程添加更细粒度的动态加载能力。您不必自己使用 dlopen 来打开/使用 DLL,这在应用程序启动时也会发生。
回答by aleroot
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.
甲共享库(。所以)是链接而不是嵌入在最终的可执行库,当所述可执行启动和需要存在于其中的可执行部署系统,以便将被加载。
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),但与操作系统(Windows 与 Linux)相关的两种实现之间存在一些差异:
A DLLcan define two kinds of functions: exported and internal. The exported functions are intended to be called by other modules, as well as from within the DLL where they are defined. Internal functions are typically intended to be called only from within the DLL where they are defined.
甲DLL可以定义两种功能:出口和内部。导出的函数旨在由其他模块调用,以及从定义它们的 DLL 中调用。内部函数通常旨在仅从定义它们的 DLL 中调用。
An SOlibrary on Linux doesn't need special export statement to indicate exportable symbols, since all symbols are available to an interrogating process.
Linux 上的SO库不需要特殊的 export 语句来指示可导出的符号,因为所有符号都可用于查询进程。
回答by JoGusto
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 领域的朋友们澄清这些谜团......
A DLL is like a Shared Object file. Both are images, ready to load into memory by the program loader of the respective 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.
DLL 就像一个共享对象文件。两者都是图像,准备由相应操作系统的程序加载器加载到内存中。图像伴随着各种元数据,以帮助链接器和加载器进行必要的关联并使用代码库。
Windows DLLs have an export table. 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. 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 DLL 有一个导出表。导出可以按名称或按表位置(数字)。后一种方法被认为是“老派”并且更加脆弱——重建 DLL 并改变函数在表中的位置将以灾难告终,而如果按名称链接入口点,则没有真正的问题。因此,请忘记这是一个问题,但请注意,如果您使用“恐龙”代码(例如 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). DLLs can reference other DLLs, just as SOs can reference other SOs.
Windows DLL 是通过编译和链接构建的,就像您对 EXE(可执行应用程序)所做的那样,但 DLL 并不是独立的,就像 SO 旨在由应用程序使用一样,通过动态加载,或通过链接时绑定(对 SO 的引用嵌入在应用程序二进制文件的元数据中,OS 程序加载器将自动加载引用的 SO)。DLL 可以引用其他 DLL,就像 SO 可以引用其他 SO。
In Windows, DLLs will make available only specific entry points. 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. 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. Look up the keywords __declspec(dllexport) and __declspec(dllimport) for more information.
在 Windows 中,DLL 将仅提供特定的入口点。这些被称为“出口”。开发人员可以使用特殊的编译器关键字使符号外部可见(对其他链接器和动态加载器),或者可以在模块定义文件中列出导出,该文件在链接时使用,而 DLL 本身是正在创建。现代的做法是用关键字修饰函数定义以导出符号名称。还可以创建带有关键字的头文件,这些关键字将将该符号声明为要从当前编译单元之外的 DLL 导入的符号。查找关键字 __declspec(dllexport) 和 __declspec(dllimport) 以获取更多信息。
One of the interesting features of DLLs is that they can declare a standard "upon load/unload" handler function. Whenever the DLL is loaded or unloaded, the DLL can perform some initialization or cleanup, as the case may be. This maps nicely into having a DLL as an object-oriented resource manager, such as a device driver or shared object interface.
DLL 的一个有趣特性是它们可以声明一个标准的“加载/卸载时”处理函数。每当加载或卸载 DLL 时,DLL 都可以执行一些初始化或清理,视具体情况而定。这很好地映射到将 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. 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. Dynamic loading is reserved typically for implementing "polymorphism" or "runtime configurability" in program behaviors (accessing add-ons or later-defined functionality, aka "plugins").
当开发人员想要使用已构建的 DLL 时,她必须要么引用由 DLL 开发人员在创建 DLL 时创建的“导出库”(*.LIB),要么必须在运行时显式加载 DLL 并请求通过 LoadLibrary() 和 GetProcAddress() 机制按名称输入入口点地址。大多数时候,链接到 LIB 文件(它只包含 DLL 导出入口点的链接器元数据)是使用 DLL 的方式。动态加载通常保留用于在程序行为中实现“多态性”或“运行时可配置性”(访问附加组件或以后定义的功能,又名“插件”)。
The Windows way of doing things can cause some confusion at times; 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. So, one should always look to see if a *.LIB file has a same-named *.DLL file; if not, chances are good that *.LIB file is a static library archive, and not export binding metadata for a DLL.
Windows 的做事方式有时会引起一些混乱;系统使用 .LIB 扩展名来指代普通静态库(档案,如 POSIX *.a 文件)和在链接时将应用程序绑定到 DLL 所需的“导出存根”库。因此,应该始终查看 *.LIB 文件是否具有同名的 *.DLL 文件;如果不是,*.LIB 文件很可能是静态库存档,而不是导出 DLL 的绑定元数据。