在c++中创建类库时,可以在动态(.dll, .so)和静态(.dll, .so)之间进行选择。Lib, .a)库。它们之间的区别是什么?什么时候使用哪个比较合适?


当前回答

如果你在嵌入式项目或专门的平台上工作,静态库是唯一的方法,而且很多时候它们编译到你的应用程序中不是那么麻烦。同时,拥有包含一切的项目和makefile会让生活更快乐。

其他回答

Ulrich Drepper关于“如何编写共享库”的论文也是一个很好的资源,详细介绍了如何最好地利用共享库,或者他所说的“动态共享对象”(DSOs)。本文主要讨论ELF二进制格式的共享库,但有些讨论也适用于Windows dll。

其他人已经充分解释了静态库是什么,但我想指出一些使用静态库的注意事项,至少在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 contains a.obj and b.obj and your DLL/EXE only references functions or variables from a.obj, the entirety of b.obj will get discarded by the linker. If b.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 that type_info is "singleton" data and uses &typeid() or type_info::before(), you may get undesirable and surprising results.


创建静态库

$$:~/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]>

创建动态库

$$:~/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]>

我给出一个一般的经验法则,如果你有一个很大的代码库,所有的代码库都建立在较低层次的库(例如Utils或Gui框架)之上,你想把它们划分成更易于管理的库,然后让它们成为静态库。动态库实际上不会为您带来任何东西,而且惊喜也更少——单个实例只有一个实例。

如果你有一个完全独立于其他代码库的库(例如第三方库),那么考虑将其作为一个dll。如果库是LGPL,由于许可条件,您可能无论如何都需要使用dll。

如果你在嵌入式项目或专门的平台上工作,静态库是唯一的方法,而且很多时候它们编译到你的应用程序中不是那么麻烦。同时,拥有包含一切的项目和makefile会让生活更快乐。