views:

226

answers:

3

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?

A: 

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.

caf
+1  A: 

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...

psmears
Changes to the main function are no-go - I'd just implement functions like "on_channel_message(...)" -on another thought.. can libraries loaded with libdl access functions defined in the main program?
LukeN
Sometimes they can, but it's safest to assume not (because (a) sometimes you have to pass special compilation flags to enable it, and (b) you generally don't want them messing with arbitrary functions in the main program!). Usually the best thing to do is to pass in a structure that contains a list of function pointers that the plugin can call.
psmears
A: 

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.

Tim Post