连接:静态链接 vs 动态链接

7
在我的应用程序中,有三个主要部分:
  • Exe:一个可执行文件
  • Lib_A:包含一个单例类和一个基类的库,用于在单例类中使用一些计算
  • Lib_B:包含从Lib_A基类派生出来的多个类
我将派生类放在Lib_B中的原因是,我想在运行时从Exe编译Lib_B。我需要在计算过程中生成派生类,而不终止整个系统。这对我来说非常重要。这意味着最初我可能会动态加载Lib_B1,也可能编译其他版本的Lib_B,如Lib_B2、Lib_B3、Lib_B4等,并动态加载它们。所有的Lib_Bx库都将具有导出其中类的入口点函数。
考虑以下事实:
  • 在运行时,将有各种数量的文件共享相同的Lib_A。
  • 应用程序必须在Windows和Linux中运行。所以部分跨平台性是一个问题。
  • 我将使用一些库,如TBB、Boost、Qt,它们可能有自己的库,如tbb.dll等。
静态或动态链接Lib_A与Exe和Lib_Bx之间的优缺点是什么?性能、系统大小等会受到影响吗?除了每个操作系统需要使用相同的编译器来编译Exe、Lib_A和Lib_Bx之外,我可能会遇到什么危险或困难的情况。
整个系统的设计对我来说是一个非常困难的问题,所以任何评论都将不胜感激。
4个回答

6
据我理解,根据你的项目描述,你应该动态链接Lib_A:如果你将Lib_A静态链接到每个Lib_Bx共享库中,你将会复制x倍的Lib_A代码和静态变量。
比如,如果你在Lib_A中有一个类,形式如下:
class BaseKlass
{
  static int instance_count;
  ...
};
instance_count 将在所有共享库中重复,因此无法让 BaseKlass 计算其实例。
您可能会遇到更微妙的问题,如虚拟表或RTTI(dynamic_cast)等。
您应该查看这个boost.python文档,其中描述了我提到的问题。
Boost.python 允许创建要在同一进程中加载的 Python 模块(动态库)。如果使用 boost.python 创建的每个 Python 模块需要在 C++ 级别上相互通信,例如从一个模块中派生类 B 从另一个模块中的类 A,则应该动态链接到 boost.python 库以避免问题。

3
静态链接的最大优势在于您不必发布一堆DLL文件。除非您打算发布一个裸的可执行文件,否则我认为这不是一个问题。
动态链接具有一些巨大的优势。每次更改时,您只需要重新编译已修改的DLL文件,而不是整个应用程序。只要它们ABI兼容,您可以将更新的dll文件与其余应用程序分开分发。
在Windows和Linux上使用相同的编译器可能更简单,但您绝对不必使用相同的编译器。
只要坚持使用便携式库,Windows和Linux之间的最大区别通常在于构建系统。一些开发人员维护完全独立的构建系统,但有很多跨平台构建系统,如cmake。

我想在Windows中使用MSVC++编译器,在Linux中使用Intel C++编译器。我认为两者都比GCC生成更优化的代码。这个应用程序只是供我使用,我不想出售它。 - ali_bahoo
@ephermient:目前我不会分发我的应用程序。但如果将来我要出售它,那么显然客户将提供自己的编译器副本。我知道这听起来不好,但这是获得编译二进制代码速度的技巧。目前我使用VC和ICC还可以。在最坏的情况下,我可以使用GCC分发应用程序,对吧? :) - ali_bahoo
@sad_man,除非你在进行一些重度数值计算,否则你不会注意到编译器之间的差异。你应该知道,英特尔运行时故意在非英特尔芯片上使用次优例程。 - mikerobi
1
@sad_man,祝你好运,如果客户无法提供编译器,请为他们提供定制版本。 - mikerobi
1
@ephemient,我不认识很多人会关心编译器的许可条款。这与您正在编译的应用程序的许可证无关。标准库的许可证可能很重要,但GNU库具有宽松的许可证。 - mikerobi
显示剩余2条评论

1

你想在运行时创建新的类吗?C++ 不是为这样的工作而设计的。C++ 类是静态的,应该在编译时存在。共享的、动态可加载的库并不能解决这个问题。

最简单的解决方案可能是嵌入一个具有动态类型的语言解释器(例如 Lua),并在其中编写运行时动态对象。

如果你真的想以平台无关的方式与运行时编译的模块进行交互,那么最好使用一些语言中立和平台中立的接口,如 CORBA。然后在你的 Linux 和 Windows 上编译和运行的东西都可以相互交互,并编译新成员加入到团队中。


但是这样我可能无法享受C++的速度和灵活性。 - ali_bahoo
任何应用程序的速度主要取决于开发人员的高超技能。不应期望从用户输入运行时生成的代码具有高效性,但在不需要高效性的情况下(如原型设计),可能会有所帮助。因此,我建议使用一些脚本解释器。 - Öö Tiib
从用户输入生成的代码在运行时不应该期望具有高效性,但是从用户输入编译出的二进制代码应该比脚本解释器中的代码快得多。 - ali_bahoo
是的,一旦编译完成就可以。调用编译器也不是免费的。就像我说的C++假定静态类型,因此您无法在运行时创建新的C++类。也许您应该尝试使用一些语言中立的接口(如CORBA)与这样的运行时生成模块进行交互。 - Öö Tiib
你希望它运行得有多快?我认为Lua的速度与C ++相当。如果你在做一些过度占用CPU且复杂的事情,那么Lua可能会变慢,但对于大多数事情,包括路径查找算法,它仍然相当快。Python是另一个选择,AngelCode也是一个选项(Wolfire团队在他们的新游戏中广泛使用)。 - user29053

0

原则上,如果所有三个都是DLL,则可以从您的应用程序触发编译器,然后动态加载新的DLL。这实际上就像任何其他插件架构一样(将Lib_Bx DLL视为插件)。

我会质疑这是否是明智的方法。您是否需要C ++编译器的完全灵活性来解决问题?您是否已经分析了解决问题的不同方法?如果您正在进行数值处理,那么类似OpenCL的东西是否更好?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接