使用 libdl 的 C 插件架构

发布于 2024-09-02 14:17:43 字数 603 浏览 4 评论 0原文

我一直在尝试用 C 语言编写一个小型 IRC 框架,现在我将扩展它的一些核心功能 - 但除此之外,我希望它可以通过插件进行扩展!

到目前为止,每当我写一些与 IRC 相关的东西(我写了很多东西,现在大约有 6 种不同的语言......我很着火!)并且实际上继续实现一个插件架构,它是在一种解释性语言中有这样做的设施(阅读:滥用),比如通过 Ruby 中的 eval 干扰整个脚本文件(糟糕!)。

现在我想滥用 C 语言中的一些东西!

基本上,我可以做三件事:

  1. 在程序中定义一个简单的脚本语言,
  2. 使用现有的脚本语言,嵌入解释器,
  3. 使用 libdl 在运行时加载 *.so 模块,

我喜欢第三个,并且如果有的话,请避免使用其他两个选项可能的。也许我是某种受虐狂,但我认为这对于学习目的来说既有趣又有用。

从逻辑上讲,明显的“疼痛链”将是(从最低到最高)2 -> 1。 1-> 3、原因很简单,libdl 正在处理的原始代码可能(并且将会)经常在我面前爆炸。

所以这个问题向你提出,stackoverflow 的其他用户,你认为 libdl 能够胜任这项任务吗?甚至是一个现实的想法吗?

I've been toying around, writing a small IRC framework in C that I'm now going to expand with some core functionality - but beyond that, I'd like it to be extensible with plugins!

Up until now, whenever I wrote something IRC related (and I wrote a lot, in about 6 different languages now... I'm on fire!) and actually went ahead to implement a plugin architecture, it was inside an interpreted language that had facilities for doing (read: abusing) so, like jamming a whole script file trough eval in Ruby (bad!).

Now I want to abuse something in C!

Basically there's three things I could do

  1. define a simple script language inside of my program
  2. use an existing one, embedding an interpreter
  3. use libdl to load *.so modules on runtime

I'm fond of the third one and raather avoid the other two options if possible. Maybe I'm a masochist of some sort, but I think it could be both fun and useful for learning purposes.

Logically thinking, the obvious "pain-chain" would be (lowest to highest) 2 -> 1 -> 3, for the simple reason that libdl is dealing with raw code that can (and will) explode in my face more often than not.

So this question goes out to you, fellow users of stackoverflow, do you think libdl is up to this task, or even a realistic thought?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

几度春秋 2024-09-09 14:17:43

libdl 非常适合插件架构 - 在一定的范围内:-)。它在许多不同的软件中被大量用于此类目的。它适用于主程序和插件之间有明确定义的 API/接口,并且许多不同的插件实现相同的 API/接口的情况。例如,您的 IRC 客户端可能具有实现不同 IM 协议(Jabber、MSN、Sametime 等)的网关的插件 - 所有这些都非常相似,因此您可以定义一个具有“发送消息”等功能的 API ”、“检查回复”等 - 并编写一堆插件,每个插件都实现不同的协议。

它工作得不太好的情况是您希望插件对主程序的行为进行任意更改 - 例如,Firefox 插件可以更改浏览器选项卡的行为、它们的外观、添加/删除按钮等。这种事情在动态语言中更容易实现(这就是为什么 Firefox 的大部分都是用 javascript 实现的),如果这是您想要的自定义类型,您可能会更好地使用您的选项(2),并编写一个很多用户界面都是用脚本语言编写的...

libdl is very well suited to plug-in architectures - within certain boundaries :-). It is used a lot for exactly this sort of purpose in a lot of different software. It works well in situations where there is a well-defined API/interface between the main program and the plug-in, and a number of different plug-ins implement the same API/interface. For instance, your IRC client might have plug-ins that implement gateways to different IM protocols (Jabber, MSN, Sametime etc...) - all of these are very similar, so you could define an API with functions such as "send message", "check for reply" etc - and write a bunch of plug-ins that each implemented a different one of the protocols.

The situation where it works less well is where you want to have the plug-ins make arbitrary changes to the behaviour of the main program - in the way that, for instance, Firefox plug-ins can change the behaviour of browser tabs, their appearance, add/remove buttons, and so on. This sort of thing is much easier to achieve in a dynamic language (hence why much of Firefox is implemented in javascript), and if this is the sort of customisation you want you may be better off with your option (2), and writing a lot of your UI in the scripting language...

我不在是我 2024-09-09 14:17:43

dlopen() / dlsym() 可能是最简单的方法。一些愚蠢的伪代码:

int run_module(const char *path, char **args)
{
   void *module;
   void (*initfunc)(char **agrs);
   int rc = 0;

   module = dlopen(path, RTLD_NOW);
   if (module == NULL)
      err_out("Could not open module %s", path);

   initfunc = dlsym(module, "module_init");
   if (initfunc == NULL) {
      dlclose(module);
      err_out("Could not find symbol init_func in %s", path);
   }

   rc = initfunc(args);

   dlclose(module);

   return rc;
}

当然,您会想要更多的错误检查方式,以及实际上做了一些有用的事情的代码:)但是,编写一个代码极其非常容易和方便围绕这对的插件架构,并发布一个简单的规范,供其他人做同样的事情。

您可能想要更多类似 load_module() 的东西,上面只是加载 SO,寻找入口点并阻塞,直到该入口点退出。

这并不是说编写自己的脚本语言是一个坏主意。人们可以编写复杂的过滤器、响应器等,而不必经历很多麻烦。也许两者都是个好主意。我不知道您是否想要一个成熟的 LUA 解释器..也许您可以想出一些东西,使基于正则表达式的操作变得简单。

尽管如此,插入模块不仅会让你的生活变得更简单,它们还会帮助你建立一个围绕你所做的东西开发东西的社区。

dlopen() / dlsym() are probably the easiest way to go. Some silly psuedo code:

int run_module(const char *path, char **args)
{
   void *module;
   void (*initfunc)(char **agrs);
   int rc = 0;

   module = dlopen(path, RTLD_NOW);
   if (module == NULL)
      err_out("Could not open module %s", path);

   initfunc = dlsym(module, "module_init");
   if (initfunc == NULL) {
      dlclose(module);
      err_out("Could not find symbol init_func in %s", path);
   }

   rc = initfunc(args);

   dlclose(module);

   return rc;
}

You would, of course, want much more in the way of error checking, as well as code that actually did something useful :) It is, however extremely easy and convenient to write a plug-in architecture around the pair and publish an easy spec for others to do the same.

You'd probably want something more along the lines of load_module(), the above just loads the SO, seeks an entry point and blocks until that entry point exits.

That's not to say that writing your own scripting language is a bad idea. People could write complex filters, responders, etc without having to go through a lot of trouble. Perhaps both would be a good idea. I don't know if you'd want a full fledged LUA interpreter .. maybe you could come up with something that makes taking actions based on regular expressions simple.

Still, plug in modules will not only make your life simpler, they'll help you grow a community of people developing stuff around whatever you make.

洛阳烟雨空心柳 2024-09-09 14:17:43

有大量现有的 C 程序使用 dlopen() / dlsym() 来实现插件架构(包括多个与 IRC 相关的架构);所以是的,这绝对可以完成任务。

There are plenty of existing C programs out there that use dlopen() / dlsym() to implement a plugin architecture (including more than one IRC-related one); so yes, it is definitely up to the task.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文