在 C 或 C++ 中实现插件系统 [关闭]
Posted
技术标签:
【中文标题】在 C 或 C++ 中实现插件系统 [关闭]【英文标题】:Implementing A Plugin System in C or C++ [closed] 【发布时间】:2009-04-02 06:34:03 【问题描述】:您对实现插件样式系统有什么建议?
【问题讨论】:
相关 - 如果不重复 - ***.com/questions/384121/… 看看this tutorial。他们已将本教程作为一个名为 Pluga 的工作跨平台项目发布,该项目使用名为 LibSourcey 的库。 【参考方案1】:在 C 中(我也认为是 C++,虽然我自己没有做过),这通常是使用动态加载的模块来完成的。这些 API:s 取决于平台。
在 POSIX (Linux) 上,您使用 @987654321@
系列函数。基本上你单独构建你的插件,然后在运行时加载它,按名称查找它的符号,然后可以调用它们。
对于 Win32,@987654322@
的作用非常相似,您将代码构建到 DLL 中。
有关使所有这些变得简单和透明的便捷包装器,请查看 GLib 的 GModule API。
【讨论】:
对于 Win32,我建议 LoadLibraryEx 设置 LOAD_WITH_ALTERED_SEARCH_PATH 标志。 我就是这样做的。 C++ 没有定义的 ABI,因此您不能可靠地使用它来动态加载 C++ 类。而 c 确实如此。如果你需要 c++ 加载,你必须用一个 c 接口暴露你所有的模块(例如 COM 通过暴露 4 个函数来实现) 整个混乱的另一个包装是 Qt 的插件系统。它执行所有幕后操作,让您可以安全地从模块加载 C++ 内容。 所以在基础级别,插件基本上是dll,可以由程序加载。该程序可以在启动时或在运行时(如果添加了新插件)枚举其所有插件,并将功能添加到原始程序。但是它们是如何添加到基础程序中的呢?我的猜测是:挂钩。【参考方案2】:在 '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。
【讨论】:
你的论文有链接吗?还是某处的参考资料? 这个想法是,如果您更改基类,它可能会破坏所有派生类 - 但是,我认为这适用于所有 oo 插件。它当然适用于 jscript.net:blogs.msdn.com/ericlippert/archive/2004/01/07/… 这里引用了我的一篇论文:citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.51.418 在底部页面有一个查看或下载链接以获取 .pdf:citeseerx.ist.psu.edu/viewdoc/… 我现在写了一篇博文来总结这一切:17 年后修复 C++ 运行时可扩展性是否为时已晚? humbleblogger.blogspot.com/2009/04/…【参考方案3】:我能给出的最好的平台和语言中立建议是:
围绕插件 SDK 设计您的整个应用程序。
IMO,插件 SDK 不应该是事后的想法。如果您将您的应用设计为基本上是一个加载插件的空壳,那么核心功能在您自己的 SDK 中实现,您将获得以下好处:
组件高度模块化,目的明确分离(这会迫使您的架构变得更好) 它迫使您的 SDK 非常好 它还允许其他第三方开发人员制作极其强大的核心级功能 新开发人员/新员工无需接触主应用即可轻松开始一项主要新功能的工作 - 他们可以在插件中完成所有工作(这可以防止他们搞砸其他任何事情)在 C/C++ 中,您可能会使用动态链接库和函数指针 (C) 或接口(对于 C++,仅由纯虚方法组成的类)。但是,即使您使用 javascript,我仍然会推荐上述架构。
【讨论】:
【参考方案4】:Qt 提供 QPluginLoader: http://qt-project.org/doc/qt-4.8/qpluginloader.html
如果您需要/想要更细粒度的控制,Qt 还提供了一种使用 QLibrary 动态加载库的方法: http://qt-project.org/doc/qt-4.8/qlibrary.html
更好的是,它们可以跨平台移植。
【讨论】:
【参考方案5】:这可能不是您想要的,但您可以在您的应用程序中嵌入脚本语言,例如 Lua。 Lua 旨在嵌入到其他程序中,并用作编写插件的脚本语言。我相信将 Lua 解释器添加到您的程序中是相当容易的,尽管我不了解 Lua,所以我不能保证这将是多么有效的解决方案。其他对 Lua 有更多经验的人,请添加 cmets 关于您将 Lua 嵌入另一个应用程序的经验。
当然,这意味着您的插件需要用 Lua 编写。如果您不喜欢 Lua,那么 de-facto 标准 Perl、Python 和 Ruby 解释器都是用 C 编写的,并且可以嵌入到 C 程序中。我知道有许多程序使用这些语言作为脚本语言扩展。
但是,我不知道您在寻找什么,因为您的问题有点含糊。也许有关您希望人们能够使用所述插件做什么的更多信息是合适的。对于某些任务,成熟的脚本语言可能有点矫枉过正。
【讨论】:
【参考方案6】:我写了一篇关于如何使用动态链接库实现插件系统的文章。本文是从 Windows 程序员的角度编写的,但该技术可以应用于 Linux/Unix 类型的环境。
文章可以在这里找到:http://3dgep.com/?p=1759
重点是,您应该创建一个由主应用程序(核心应用程序)和插件实现隐式链接的“通用”DLL。然后,核心应用程序可以在运行时显式链接和动态加载插件。
本文还展示了如何使用“通用”DLL 在多个 DLL 之间安全地共享一个类的静态(单例)实例。
本文还展示了如何从 DLL 导出“C”函数或变量,并在运行时在应用程序中使用导出的函数。
【讨论】:
【参考方案7】:最好使用像 ACE (http://www.cs.wustl.edu/~schmidt/ACE.html) 这样的框架,它可以(尽可能好地)保护您免受平台特定编码的影响。
ACE 包含一个基于共享库的插件框架,您可以使用它来创建动态组装的应用程序。
如需更高级别的抽象,请查看 CIAO (http://www.cs.wustl.edu/~schmidt/CIAO.html) CORBA 组件模型的开源 C++ 实现。
【讨论】:
链接已失效...【参考方案8】:看看Poco Class Loader,这对你来说可能很有趣。
【讨论】:
【参考方案9】:我编写了一个插件库Pugg,它从 dll 文件加载 C++ 类,这是我使用的逻辑:
用户从具有唯一名称的 dll 中导出一个 c 函数。此名称必须足够唯一,因为在从 dll 加载时无法使用其参数区分函数。
C 函数注册一个或多个称为“驱动程序”的工厂类。每个 Driver 类都与一个字符串相关联。当主应用程序想要创建一个类时,它使用关联的字符串收集相关的工厂类。我还实现了一个版本检查系统来不加载旧插件。
Dll 加载是使用 LoadLibraryA 和 GetProcAddress 函数完成的(Pugg 目前在 Windows 上工作)。
值得一提的是,应该使用相同的编译器和相同的编译选项(发布/调试模式、优化设置、stl 版本等)编译主应用程序和 dll。否则类的映射可能会出现问题。
【讨论】:
【参考方案10】:我使用相当幼稚的系统取得了一些成功:
为插件创建 API 规范 使用单例插件管理器 使用基于 LoadLibrary/GetProcAddress 的运行时动态链接 实现基于控制反转的事件处理以通知插件【讨论】:
【参考方案11】:This podcast on plugin architectures 也可能很有趣。
【讨论】:
以上是关于在 C 或 C++ 中实现插件系统 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章
在 Angular 2、4、5、6 中实现插件架构/插件系统/可插拔框架
PHP 警告:count():参数必须是在 C:\\htdocs\my.php 中实现 Countable 的数组或对象 [关闭]