【发布时间】:2009-04-02 06:34:03
【问题描述】:
您对实现插件样式系统有什么建议?
【问题讨论】:
-
相关 - 如果不重复 - stackoverflow.com/questions/384121/…
-
看看this tutorial。他们已将本教程作为一个名为 Pluga 的工作跨平台项目发布,该项目使用名为 LibSourcey 的库。
您对实现插件样式系统有什么建议?
【问题讨论】:
在 C 中(我也认为是 C++,虽然我自己没有做过),这通常是使用动态加载的模块来完成的。这些 API:s 取决于平台。
在 POSIX (Linux) 上,您使用 @987654321@ 系列函数。基本上你单独构建你的插件,然后在运行时加载它,按名称查找它的符号,然后可以调用它们。
对于 Win32,@987654322@ 的作用非常相似,您将代码构建到 DLL 中。
有关使所有这些变得简单和透明的便捷包装器,请查看 GLib 的 GModule API。
【讨论】:
在 '92/'93 时间框架内,我为 Aldus PageMaker 开发了一个插件架构,它是用 C++ 编码的。 PageMaker 建立在称为 VAMP 的 C++ OOP 框架之上,有助于其在 Mac OS 和 Windows 之间的可移植性。
所以我们尝试利用 C++ 的特性来构建插件架构。由于所谓的脆基类问题,这被证明对于 C++ 类来说是非常有问题的。我继续写了一篇发表在期刊上的论文,并在 OOPSLA '93 的反思研讨会上发表。我还在波特兰举行的 Usenix 会议上与 Bjarne Stroustrup 取得了联系,并与他进行了几个月的对话,在那里他代表我支持处理脆弱的基类问题。 (唉,当时认为其他问题更重要。)
Microsoft 推出了 COM/DCOM 系统,并针对该平台被视为解决该问题的可行解决方案。通过用于定义 COM 接口的抽象类,C++ 可以用作 COM 的实现语言。
但是,这些天来,开发人员避开了 COM/DCOM。
相比之下,NeXT 在 90 年代初期在 NeXT Step 框架中使用 Objective C 设计了一个插件架构。今天,它在 Apple 计算机和 iPhone 等重要平台上的 Mac OS X 中充满活力。
我提交了启用 Objective C 以更好地解决插件问题。
我个人认为C++脆弱的基类问题是它最致命的缺陷。
如果要使用基于 C 的语言系列构建插件架构,那么会使用 Objective C。
【讨论】:
我能给出的最好的平台和语言中立建议是:
围绕插件 SDK 设计您的整个应用程序。
IMO,插件 SDK 不应该是事后的想法。如果您将您的应用设计为基本上是一个加载插件的空壳,那么核心功能在您自己的 SDK 中实现,您将获得以下好处:
在 C/C++ 中,您可能会使用动态链接库和函数指针 (C) 或接口(对于 C++,仅由纯虚方法组成的类)。但是,即使您使用 Javascript,我仍然会推荐上述架构。
【讨论】:
Qt 提供 QPluginLoader: http://qt-project.org/doc/qt-4.8/qpluginloader.html
如果您需要/想要更细粒度的控制,Qt 还提供了一种使用 QLibrary 动态加载库的方法: http://qt-project.org/doc/qt-4.8/qlibrary.html
更好的是,它们可以跨平台移植。
【讨论】:
这可能不是您想要的,但您可以在您的应用程序中嵌入脚本语言,例如 Lua。 Lua 旨在嵌入到其他程序中,并用作编写插件的脚本语言。我相信将 Lua 解释器添加到您的程序中是相当容易的,尽管我不了解 Lua,所以我不能保证这将是多么有效的解决方案。其他对 Lua 有更多经验的人,请添加 cmets 关于您将 Lua 嵌入另一个应用程序的经验。
当然,这意味着您的插件需要用 Lua 编写。如果您不喜欢 Lua,那么 de-facto 标准 Perl、Python 和 Ruby 解释器都是用 C 编写的,并且可以嵌入到 C 程序中。我知道有许多程序使用这些语言作为脚本语言扩展。
但是,我不知道您在寻找什么,因为您的问题有点含糊。也许有关您希望人们能够使用所述插件做什么的更多信息是合适的。对于某些任务,成熟的脚本语言可能有点矫枉过正。
【讨论】:
我写了一篇关于如何使用动态链接库实现插件系统的文章。本文是从 Windows 程序员的角度编写的,但该技术可以应用于 Linux/Unix 类型的环境。
文章可以在这里找到:http://3dgep.com/?p=1759
重点是,您应该创建一个由主应用程序(核心应用程序)和插件实现隐式链接的“通用”DLL。然后,核心应用程序可以在运行时显式链接和动态加载插件。
本文还展示了如何使用“通用”DLL 在多个 DLL 之间安全地共享一个类的静态(单例)实例。
本文还展示了如何从 DLL 导出“C”函数或变量,并在运行时在应用程序中使用导出的函数。
【讨论】:
最好使用像 ACE (http://www.cs.wustl.edu/~schmidt/ACE.html) 这样的框架,它可以(尽可能好地)保护您免受平台特定编码的影响。
ACE 包含一个基于共享库的插件框架,您可以使用它来创建动态组装的应用程序。
如需更高级别的抽象,请查看 CIAO (http://www.cs.wustl.edu/~schmidt/CIAO.html) CORBA 组件模型的开源 C++ 实现。
【讨论】:
看看Poco Class Loader,这对你来说可能很有趣。
【讨论】:
我编写了一个插件库Pugg,它从 dll 文件加载 C++ 类,这是我使用的逻辑:
用户从具有唯一名称的 dll 中导出一个 c 函数。此名称必须足够唯一,因为在从 dll 加载时无法使用其参数区分函数。
C 函数注册一个或多个称为“驱动程序”的工厂类。每个 Driver 类都与一个字符串相关联。当主应用程序想要创建一个类时,它使用关联的字符串收集相关的工厂类。我还实现了一个版本检查系统来不加载旧插件。
Dll 加载是使用 LoadLibraryA 和 GetProcAddress 函数完成的(Pugg 目前在 Windows 上工作)。
值得一提的是,应该使用相同的编译器和相同的编译选项(发布/调试模式、优化设置、stl 版本等)编译主应用程序和 dll。否则类的映射可能会出现问题。
【讨论】:
我使用相当幼稚的系统取得了一些成功:
【讨论】:
【讨论】: