何时使用动态库与静态库
在 C++ 中创建类库时,可以选择动态(.dll
、.so
)和静态(.lib
、) .a
)库。 它们之间有什么区别,什么时候适合使用哪个?
When creating a class library in C++, you can choose between dynamic (.dll
, .so
) and static (.lib
, .a
) libraries. What is the difference between them and when is it appropriate to use which?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(20)
静态库会增加二进制文件中代码的大小。 它们总是被加载,并且无论您编译的代码版本是什么,都是将运行的代码版本。
动态库单独存储和版本控制。 如果更新被视为与原始版本二进制兼容,则加载的动态库版本可能不是代码附带的原始版本。
此外,动态库不一定要加载——它们通常在第一次调用时加载——并且可以在使用同一库的组件之间共享(多个数据加载,一个代码加载)。
动态库在大多数情况下被认为是更好的方法,但最初它们有一个重大缺陷(google DLL hell),该缺陷几乎已被更新的 Windows 操作系统(特别是 Windows XP)所消除。
Static libraries increase the size of the code in your binary. They're always loaded and whatever version of the code you compiled with is the version of the code that will run.
Dynamic libraries are stored and versioned separately. It's possible for a version of the dynamic library to be loaded that wasn't the original one that shipped with your code if the update is considered binary compatible with the original version.
Additionally dynamic libraries aren't necessarily loaded -- they're usually loaded when first called -- and can be shared among components that use the same library (multiple data loads, one code load).
Dynamic libraries were considered to be the better approach most of the time, but originally they had a major flaw (google DLL hell), which has all but been eliminated by more recent Windows OSes (Windows XP in particular).
其他人已经充分解释了静态库是什么,但我想指出使用静态库的一些注意事项,至少在 Windows 上:
单例:如果某些东西需要是全局的/static 且唯一,将其放入静态库时要非常小心。 如果多个 DLL 链接到该静态库,它们将各自获得自己的单例副本。 但是,如果您的应用程序是没有自定义 DLL 的单个 EXE,这可能不是问题。
未引用的代码删除:当您链接到静态库时,只有 DLL/EXE 引用的静态库部分才会链接到您的 DLL/EXE 中。
例如,如果
mylib.lib
包含a.obj
和b.obj
并且您的DLL/EXE仅引用来自a.obj
,整个b.obj
将被链接器丢弃。 如果b.obj
包含全局/静态对象,它们的构造函数和析构函数将不会被执行。 如果这些构造函数/析构函数有副作用,您可能会对它们的缺失感到失望。同样,如果静态库包含特殊入口点,您可能需要注意它们是否确实包含在内。 嵌入式编程(好吧,不是 Windows)中的一个例子是标记为位于特定地址的中断处理程序。 您还需要将中断处理程序标记为入口点,以确保它不会被丢弃。
这样做的另一个后果是,静态库可能包含由于未解析的引用而完全无法使用的对象文件,但在您引用这些对象文件中的函数或变量之前,它不会导致链接器错误。 这可能会在编写库后很长时间内发生。
调试符号:您可能希望每个静态库都有一个单独的 PDB,或者您可能希望将调试符号放置在目标文件中,以便将它们滚动到 DLL/的 PDB 中EXE文件。 Visual C++ 文档解释了必要的选项。
RTTI:如果将单个静态库链接到多个 DLL,您最终可能会得到同一个类的多个
type_info
对象。 如果您的程序假设type_info
是“单例”数据并使用&typeid()
或type_info::before()
,您可能会得到不良且令人惊讶的结果。Others have adequately explained what a static library is, but I'd like to point out some of the caveats of using static libraries, at least on Windows:
Singletons: If something needs to be global/static and unique, be very careful about putting it in a static library. If multiple DLLs are linked against that static library they will each get their own copy of the singleton. However, if your application is a single EXE with no custom DLLs, this may not be a problem.
Unreferenced code removal: When you link against a static library, only the parts of the static library that are referenced by your DLL/EXE will get linked into your DLL/EXE.
For example, if
mylib.lib
containsa.obj
andb.obj
and your DLL/EXE only references functions or variables froma.obj
, the entirety ofb.obj
will get discarded by the linker. Ifb.obj
contains global/static objects, their constructors and destructors will not get executed. If those constructors/destructors have side effects, you may be disappointed by their absence.Likewise, if the static library contains special entrypoints you may need to take care that they are actually included. An example of this in embedded programming (okay, not Windows) would be an interrupt handler that is marked as being at a specific address. You also need to mark the interrupt handler as an entrypoint to make sure it doesn't get discarded.
Another consequence of this is that a static library may contain object files that are completely unusable due to unresolved references, but it won't cause a linker error until you reference a function or variable from those object files. This may happen long after the library is written.
Debug symbols: You may want a separate PDB for each static library, or you may want the debug symbols to be placed in the object files so that they get rolled into the PDB for the DLL/EXE. The Visual C++ documentation explains the necessary options.
RTTI: You may end up with multiple
type_info
objects for the same class if you link a single static library into multiple DLLs. If your program assumes thattype_info
is "singleton" data and uses&typeid()
ortype_info::before()
, you may get undesirable and surprising results.静态库被编译到客户端中。 .lib 在编译时使用,库的内容成为消费可执行文件的一部分。
动态库在运行时加载,不会编译到客户端可执行文件中。 动态库更加灵活,因为多个客户端可执行文件可以加载 DLL 并利用其功能。 这还可以将客户端代码的整体大小和可维护性降至最低。
A static library gets compiled into the client. A .lib is used at compile time and the contents of the library become part of the consuming executable.
A dynamic library is loaded at runtime and not compiled into the client executable. Dynamic libraries are more flexible as multiple client executables can load a DLL and utilize its functionality. This also keeps the overall size and maintainability of your client code to a minimum.
Ulrich Drepper 关于“如何编写共享库”的论文也是很好的资源,详细介绍了如何最好地编写共享库利用共享库,或者他所说的“动态共享对象”(DSO)。 它更多地关注 ELF 二进制格式的共享库,但有些讨论适用于 Windows DLL,例如出色地。
Ulrich Drepper's paper on "How to Write Shared Libraries" is also good resource that details how best to take advantage of shared libraries, or what he refers to as "Dynamic Shared Objects" (DSOs). It focuses more on shared libraries in the ELF binary format, but some discussions are suitable for Windows DLLs as well.
您应该仔细考虑随时间的变化、版本控制、稳定性、兼容性等。
如果有两个应用程序使用共享代码,您是否想强制这些应用程序一起更改,以防它们需要彼此兼容? 然后使用dll。 所有 exe 将使用相同的代码。
或者您想将它们彼此隔离,以便您可以更改其中一个并确信您没有破坏另一个。 然后使用静态库。
DLL 地狱是指您可能应该使用静态库,但您却使用了 dll,并且并非所有的 exe 都与其兼容。
You should think carefully about changes over time, versioning, stability, compatibility, etc.
If there are two apps that use the shared code, do you want to force those apps to change together, in case they need to be compatible with each other? Then use the dll. All the exe's will be using the same code.
Or do you want to isolate them from each other, so that you can change one and be confident you haven't broken the other. Then use the static lib.
DLL hell is when you probably SHOULD HAVE used a static lib, but you used a dll instead, and not all the exes are comaptible with it.
静态库必须链接到最终的可执行文件中; 它成为可执行文件的一部分并跟随它无论走到哪里。 每次执行可执行文件时都会加载动态库,并作为 DLL 文件与可执行文件分开。
当您希望能够更改库提供的功能而无需重新链接可执行文件(只需替换 DLL 文件,而无需替换可执行文件)时,您可以使用 DLL。
每当您没有理由使用动态库时,您都会使用静态库。
A static library must be linked into the final executable; it becomes part of the executable and follows it wherever it goes. A dynamic library is loaded every time the executable is executed and remains separate from the executable as a DLL file.
You would use a DLL when you want to be able to change the functionality provided by the library without having to re-link the executable (just replace the DLL file, without having to replace the executable file).
You would use a static library whenever you don't have a reason to use a dynamic library.
有关此主题的精彩讨论,请阅读此来自 Sun 的文章。
它涉及所有好处,包括能够插入插入库。 有关插入的更多详细信息,请参阅本文。
For an excellent discussion of this topic have a read of this article from Sun.
It goes into all the benefits including being able to insert interposing libraries. More detail on interposing can be found in this article here.
如果库是静态的,则在链接时代码将与可执行文件链接。 这使得您的可执行文件更大(比您采用动态路线时更大)。
如果库是动态的,则在链接时对所需方法的引用将内置到可执行文件中。 这意味着您必须发送可执行文件和动态库。 您还应该考虑对库中代码的共享访问是否安全,首选加载地址是否安全。
如果您可以接受静态库,那就使用静态库。
If the library is static, then at link time the code is linked in with your executable. This makes your executable larger (than if you went the dynamic route).
If the library is dynamic then at link time references to the required methods are built in to your executable. This means that you have to ship your executable and the dynamic library. You also ought to consider whether shared access to the code in the library is safe, preferred load address among other stuff.
If you can live with the static library, go with the static library.
我们在项目中使用了很多 DLL(> 100)。 这些 DLL 相互依赖,因此我们选择动态链接的设置。 然而它有以下缺点:
也许更好的设置是使所有内容成为静态库(因此您只有一个)可执行)。 仅当不发生代码重复时这才有效。 测试似乎支持这个假设,但我找不到官方的 MSDN 引用。 例如,使用以下命令 make 1 exe:
2 共享库2 的代码和变量应该仅在最终合并的可执行文件中出现一次。 有人可以支持这个问题吗?
We use a lot of DLL's (> 100) in our project. These DLL's have dependencies on each other and therefore we chose the setup of dynamic linking. However it has the following disadvantages:
Maybe a better setup was to make everything a static library (and therefore you just have one executable). This works only if no code duplication takes place. A test seems to support this assumption, but i couldn't find an official MSDN quote. So for example make 1 exe with:
The code and variables of shared_lib2 should be present in the final merged executable only once. Can anyone support this question?
静态库是包含库的目标代码的档案,当链接到应用程序时,该代码被编译为可执行文件。 共享库的不同之处在于它们不会编译成可执行文件。 相反,动态链接器会搜索一些目录来查找所需的库,然后将其加载到内存中。
多个可执行文件可以同时使用同一个共享库,从而减少内存使用量和可执行文件大小。 但是,还有更多文件可以与可执行文件一起分发。 您需要确保将库安装到链接器可以找到它的使用系统上的某个位置,静态链接消除了这个问题,但会产生更大的可执行文件。
Static libraries are archives that contain the object code for the library, when linked into an application that code is compiled into the executable. Shared libraries are different in that they aren't compiled into the executable. Instead the dynamic linker searches some directories looking for the library(s) it needs, then loads that into memory.
More then one executable can use the same shared library at the same time, thus reducing memory usage and executable size. However, there are then more files to distribute with the executable. You need to make sure that the library is installed onto the uses system somewhere where the linker can find it, static linking eliminates this problem but results in a larger executable file.
如果您从事嵌入式项目或专用平台静态库是唯一的出路,而且很多时候将它们编译到您的应用程序中也不那么麻烦。 拥有包含一切的项目和 makefile 让生活更快乐。
If your working on embedded projects or specialized platforms static libraries are the only way to go, also many times they are less of a hassle to compile into your application. Also having projects and makefile that include everything makes life happier.
我给出的一般经验法则是,如果您有一个大型代码库,所有代码库都构建在较低级别的库(例如 Utils 或 Gui 框架)之上,您希望将其划分为更易于管理的库,然后将它们设为静态库。 动态库实际上不会给你带来任何东西,而且惊喜也更少——例如,只会有一个单例实例。
如果您有一个与代码库的其余部分完全独立的库(例如第三方库),那么请考虑将其设为 dll。 如果库是 LGPL,由于许可条件,您可能仍然需要使用 dll。
I'd give a general rule of thumb that if you have a large codebase, all built on top of lower level libraries (eg a Utils or Gui framework), which you want to partition into more manageable libraries then make them static libraries. Dynamic libraries don't really buy you anything and there are fewer surprises -- there will only be one instance of singletons for instance.
If you have a library that is entirely separate to the rest of the codebase (eg a third party library) then consider making it a dll. If the library is LGPL you may need to use a dll anyway due to the licensing conditions.
除了其他人提到的所有要点之外,我在特定用例中使用静态库来:
换句话说,假设我的产品中有两个库,A 和 B。A 使用 B 服务并依赖于它。 但 B 是一个通用库,包含许多可以单独使用的有用服务。 为了避免我的最终用户直接从 B 中受益(他们应该为其许可证付费!),我通常将 B 编译为静态库并将其直接放在 A 中。因此,B 服务将完全为 A 私有,并且不能被由最终用户使用。
Apart from all the points that have been mentioned by others, I use static libraries in a specific use-case to:
In other words, suppose that I have two libraries in my product, A and B. A uses B services and depends on it. But B is a general-purpose library including lots of helpful services that can be used separately. To avoid my end users to benefit from B directly (they should pay for its license!), I usually compile B as a static library and put it directly inside A. As a result, B services would be totally private to A and cannot be used by end users.
动态:部分可以单独升级,错误修复无需等待整个程序升级。
静态:它可以轻松地永远工作。
因此,当没有简单的方法在不破坏程序的情况下升级共享库时,请尽可能长时间地使用动态,而使用静态。
Dynamic: Parts can be upgraded separately, bug fixes don't wait for a whole program upgrade.
Static: It just works forever, easily.
So use dynamic as long as possible, and static when there is no easy way to upgrade shared libraries without programs breaking.
如果您的库要在多个可执行文件之间共享,则使其动态化以减少可执行文件的大小通常是有意义的。 否则,一定要使其静态。
使用 dll 有几个缺点。 加载和卸载它会产生额外的开销。 还有一个额外的依赖项。 如果您更改 dll 使其与您的可执行文件不兼容,它们将停止工作。 另一方面,如果更改静态库,使用旧版本编译的可执行文件不会受到影响。
If your library is going to be shared among several executables, it often makes sense to make it dynamic to reduce the size of the executables. Otherwise, definitely make it static.
There are several disadvantages of using a dll. There is additional overhead for loading and unloading it. There is also an additional dependency. If you change the dll to make it incompatible with your executalbes, they will stop working. On the other hand, if you change a static library, your compiled executables using the old version will not be affected.
实际上,您(在大型项目中)所做的权衡是初始加载时间,库将在某个时间进行链接,必须做出的决定是链接是否需要足够长的时间以供编译器需要硬着头皮预先完成,或者动态链接器可以在加载时完成。
Really the trade off you are making (in a large project) is in initial load time, the libraries are going to get linked at one time or another, the decision that has to be made is will the link take long enough that the compiler needs to bite the bullet and do it up front, or can the dynamic linker do it at load time.
除了静态库与动态库的技术影响(静态文件将所有内容捆绑在一个大的二进制文件中,而动态库允许在多个不同的可执行文件之间共享代码)之外,还有法律影响。
例如,如果您使用 LGPL 许可代码,并且静态链接到 LGPL 库(从而创建一个大的二进制文件),您的代码将自动成为开源代码 (自由如自由) LGPL 代码。 如果您链接到共享对象,那么您只需要对 LGPL 库本身进行的改进/错误修复进行 LGPL 即可。
例如,如果您正在决定如何编译移动应用程序(在 Android 中您可以选择静态还是动态,但在 iOS 中则不能 - 它始终是静态的),这将成为一个更加重要的问题。
Besides the technical implications of static vs dynamic libraries (static files bundle everything in one big binary vs dynamic libraries that allow code sharing among several different executables), there are the legal implications.
For example, if you are using LGPL licensed code and you link statically against a LGPL library (and thus create one big binary), your code automatically becomes Open Sourced (free as in freedom) LGPL code. If you link against a shared objects, then you only need to LGPL the improvements / bug fixes that you make to the LGPL library itself.
This becomes a far more important issue if you are deciding how to compile you mobile applications for example (in Android you have a choice of static vs dynamic, in iOS you do not - it is always static).
lib 是捆绑在应用程序可执行文件中的代码单元。
dll 是可执行代码的独立单元。 仅当调用该代码时,它才会加载到进程中。 一个 dll 可以被多个应用程序使用并在多个进程中加载,同时在硬盘上仍然只有一份代码副本。
Dll pros:可用于在多个产品之间重用/共享代码; 按需加载到进程内存中,不需要时可以卸载; 可以独立于程序的其余部分进行升级。
DLL 缺点:DLL 加载和代码变基的性能影响; 版本控制问题(“dll 地狱”)
Lib 优点:不会影响性能,因为代码始终在进程中加载并且不会重新设置基础; 没有版本控制问题。
库缺点:可执行文件/进程“膨胀” - 所有代码都在可执行文件中,并在进程启动时加载; 不可重用/共享 - 每个产品都有自己的代码副本。
A lib is a unit of code that is bundled within your application executable.
A dll is a standalone unit of executable code. It is loaded in the process only when a call is made into that code. A dll can be used by multiple applications and loaded in multiple processes, while still having only one copy of the code on the hard drive.
Dll pros: can be used to reuse/share code between several products; load in the process memory on demand and can be unloaded when not needed; can be upgraded independently of the rest of the program.
Dll cons: performance impact of the dll loading and code rebasing; versioning problems ("dll hell")
Lib pros: no performance impact as code is always loaded in the process and is not rebased; no versioning problems.
Lib cons: executable/process "bloat" - all the code is in your executable and is loaded upon process start; no reuse/sharing - each product has its own copy of the code.
C++ 程序分两个阶段构建
静态库 (.lib) 只是一组 .obj 文件,因此不是完整的程序。 它尚未经历构建程序的第二(链接)阶段。 另一方面,Dll 与 exe 类似,因此是完整的程序。
如果您构建静态库,它尚未链接,因此静态库的使用者将必须使用您使用的相同编译器(如果您使用 g++,他们将必须使用 g++)。
相反,如果您构建了一个 dll(并正确构建了它 ),您已经构建了一个所有消费者都可以使用的完整程序,无论他们使用哪种编译器。 但是,如果需要交叉编译器兼容性,则从 dll 导出时存在一些限制。
C++ programs are built in two phases
Static library (.lib) is just a bundle of .obj files and therefore isn't a complete program. It hasn't undergone the second (linking) phase of building a program. Dlls, on the other hand, are like exe's and therefore are complete programs.
If you build a static library, it isn't linked yet and therefore consumers of your static library will have to use the same compiler that you used (if you used g++, they will have to use g++).
If instead you built a dll (and built it correctly), you have built a complete program that all consumers can use, no matter which compiler they are using. There are several restrictions though, on exporting from a dll, if cross compiler compatibility is desired.
创建静态库
创建动态库
Creating a static library
creating a dynamic library