C++ 何时使用动态库与静态库
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/140061/
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
When to use dynamic vs. static libraries
提问by Morten Christiansen
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?
在 C++ 中创建类库时,您可以在动态 ( .dll
, .so
) 和静态 ( .lib
, .a
) 库之间进行选择。它们之间有什么区别,什么时候使用哪个合适?
采纳答案by Orion Adrian
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 ifthe 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).
大多数情况下,动态库被认为是更好的方法,但最初它们有一个主要缺陷(谷歌 DLL 地狱),最近的 Windows 操作系统(尤其是 Windows XP)几乎消除了这种缺陷。
回答by bk1e
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:
其他人已经充分解释了什么是静态库,但我想指出使用静态库的一些注意事项,至少在 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.
单例:如果某些东西需要是全局的/静态的和唯一的,那么在将它放入静态库时要非常小心。如果多个 DLL 链接到该静态库,则它们每个都将获得自己的单例副本。但是,如果您的应用程序是没有自定义 DLL 的单个 EXE,则这可能不是问题。
未引用代码删除:当您链接静态库时,只有 DLL/EXE 引用的静态库部分才会链接到您的 DLL/EXE。
例如,如果
mylib.lib
包含a.obj
和b.obj
并且您的 DLL/EXE 仅引用来自 的函数或变量a.obj
,b.obj
则链接器将丢弃其全部内容。如果b.obj
包含全局/静态对象,它们的构造函数和析构函数将不会被执行。如果这些构造函数/析构函数有副作用,你可能会对它们的缺席感到失望。同样,如果静态库包含特殊的入口点,您可能需要注意它们实际上是否包含在内。在嵌入式编程(好吧,不是 Windows)中的一个例子是标记为位于特定地址的中断处理程序。您还需要将中断处理程序标记为入口点,以确保它不会被丢弃。
这样做的另一个后果是,静态库可能包含由于未解析的引用而完全无法使用的对象文件,但在您从这些对象文件中引用函数或变量之前,它不会导致链接器错误。这可能会在编写库很久之后发生。
调试符号:您可能希望每个静态库都有一个单独的 PDB,或者您可能希望将调试符号放置在目标文件中,以便将它们卷入 DLL/EXE 的 PDB。Visual C++ 文档解释了必要的选项。
RTTI:
type_info
如果您将单个静态库链接到多个 DLL,您可能最终会得到同一个类的多个对象。如果您的程序假定这type_info
是“单例”数据并使用&typeid()
或type_info::before()
,您可能会得到不希望的和令人惊讶的结果。
回答by Franci Penov
A lib is a unit of code that is bundled within your application executable.
lib 是捆绑在应用程序可执行文件中的代码单元。
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 是一个独立的可执行代码单元。只有在对该代码进行调用时才会在进程中加载它。一个 dll 可以被多个应用程序使用并加载到多个进程中,同时硬盘驱动器上仍然只有一份代码副本。
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 优点:可用于在多个产品之间重用/共享代码;按需加载进程内存,不需要时可以卸载;可以独立于程序的其余部分进行升级。
Dll cons: performance impact of the dll loading and code rebasing; versioning problems ("dll hell")
Dll cons: dll 加载和代码变基对性能的影响;版本问题(“dll 地狱”)
Lib pros: no performance impact as code is always loaded in the process and is not rebased; no versioning problems.
Lib 优点:没有性能影响,因为代码总是在进程中加载并且不会重新定位;没有版本问题。
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.
Lib 缺点:可执行文件/进程“膨胀” - 所有代码都在您的可执行文件中,并在进程启动时加载;没有重用/共享 - 每个产品都有自己的代码副本。
回答by rburhum
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.
例如,如果您使用 LGPL 许可代码并且您静态链接到 LGPL 库(从而创建一个大的二进制文件),您的代码将自动成为开源(免费的)LGPL 代码。如果您链接到共享对象,那么您只需要 LGPL 对您对 LGPL 库本身所做的改进/错误修复。
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).
例如,如果您决定如何编译您的移动应用程序(在 Android 中您可以选择静态与动态,而在 iOS 中您没有 - 它始终是静态的),这将成为一个更重要的问题。
回答by tcb
C++ programs are built in two phases
C++ 程序分两个阶段构建
- Compilation - produces object code (.obj)
- Linking - produces executable code (.exe or .dll)
- 编译 - 生成目标代码 (.obj)
- 链接 - 生成可执行代码(.exe 或 .dll)
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.
静态库 (.lib) 只是一堆 .obj 文件,因此不是一个完整的程序。它尚未经历构建程序的第二(链接)阶段。另一方面,DLL 类似于 exe,因此是完整的程序。
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++).
如果您构建一个静态库,它尚未链接,因此您的静态库的使用者将必须使用与您使用的相同的编译器(如果您使用 g++,他们将必须使用 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.
相反,如果您构建了一个 dll(并正确构建了它),那么您就构建了一个所有消费者都可以使用的完整程序,无论他们使用哪种编译器。但是,如果需要交叉编译器兼容性,从 dll 导出有几个限制。
回答by Vijay
Creating a static library
创建静态库
$$:~/static [32]> cat foo.c
#include<stdio.h>
void foo()
{
printf("\nhello world\n");
}
$$:~/static [33]> cat foo.h
#ifndef _H_FOO_H
#define _H_FOO_H
void foo();
#endif
$$:~/static [34]> cat foo2.c
#include<stdio.h>
void foo2()
{
printf("\nworld\n");
}
$$:~/static [35]> cat foo2.h
#ifndef _H_FOO2_H
#define _H_FOO2_H
void foo2();
#endif
$$:~/static [36]> cat hello.c
#include<foo.h>
#include<foo2.h>
void main()
{
foo();
foo2();
}
$$:~/static [37]> cat makefile
hello: hello.o libtest.a
cc -o hello hello.o -L. -ltest
hello.o: hello.c
cc -c hello.c -I`pwd`
libtest.a:foo.o foo2.o
ar cr libtest.a foo.o foo2.o
foo.o:foo.c
cc -c foo.c
foo2.o:foo.c
cc -c foo2.c
clean:
rm -f foo.o foo2.o libtest.a hello.o
$$:~/static [38]>
creating a dynamic library
创建动态库
$$:~/dynamic [44]> cat foo.c
#include<stdio.h>
void foo()
{
printf("\nhello world\n");
}
$$:~/dynamic [45]> cat foo.h
#ifndef _H_FOO_H
#define _H_FOO_H
void foo();
#endif
$$:~/dynamic [46]> cat foo2.c
#include<stdio.h>
void foo2()
{
printf("\nworld\n");
}
$$:~/dynamic [47]> cat foo2.h
#ifndef _H_FOO2_H
#define _H_FOO2_H
void foo2();
#endif
$$:~/dynamic [48]> cat hello.c
#include<foo.h>
#include<foo2.h>
void main()
{
foo();
foo2();
}
$$:~/dynamic [49]> cat makefile
hello:hello.o libtest.sl
cc -o hello hello.o -L`pwd` -ltest
hello.o:
cc -c -b hello.c -I`pwd`
libtest.sl:foo.o foo2.o
cc -G -b -o libtest.sl foo.o foo2.o
foo.o:foo.c
cc -c -b foo.c
foo2.o:foo.c
cc -c -b foo2.c
clean:
rm -f libtest.sl foo.o foo
2.o hello.o
$$:~/dynamic [50]>
回答by Corey Trager
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.
如果有两个应用程序使用共享代码,您是否要强制这些应用程序一起更改,以防它们需要相互兼容?然后使用dll。所有的 exe 都将使用相同的代码。
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,并且并非所有 exe 都与它兼容。
回答by Jordan Parmer
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.
静态库被编译到客户端。.lib 在编译时使用,库的内容成为消费可执行文件的一部分。
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.
动态库在运行时加载,而不是编译到客户端可执行文件中。动态库更加灵活,因为多个客户端可执行文件可以加载 DLL 并利用其功能。这也将客户端代码的整体大小和可维护性保持在最低限度。
回答by spotcatbug
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.
静态库必须链接到最终的可执行文件中;它成为可执行文件的一部分,无论它走到哪里都跟随它。每次执行可执行文件时都会加载动态库,并作为 DLL 文件与可执行文件分开。
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).
当您希望能够更改库提供的功能而无需重新链接可执行文件(只需替换 DLL 文件,而不必替换可执行文件)时,您将使用 DLL。
You would use a static library whenever you don't have a reason to use a dynamic library.
每当您没有理由使用动态库时,您就会使用静态库。
回答by Void
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 ELFbinary format, but some discussions are suitable for Windows DLLs as well.
Ulrich Drepper 关于“如何编写共享库”的论文也是很好的资源,详细介绍了如何最好地利用共享库,或者他所说的“动态共享对象”(DSO)。它更多地关注ELF二进制格式的共享库,但一些讨论也适用于 Windows DLL。