2010-05-21 14 views
6

He estado jugando, escribiendo un pequeño marco IRC en C que ahora voy a expandir con algunas funcionalidades básicas, pero más allá de eso, me gustaría que sea extensible con complementos !Arquitectura de complementos en C usando libdl

Hasta ahora, cada vez que escribía algo relacionado con IRC (y escribí mucho, en aproximadamente 6 idiomas diferentes ahora ... ¡estoy en llamas!) Y en realidad seguí adelante para implementar una arquitectura de complemento, estaba dentro un lenguaje interpretado que tenía facilidades para hacer (leer: abusar) así que, como bloquear un archivo de script completo a través de eval en Ruby (¡mal!).

¡Ahora quiero abusar de algo en C!

Básicamente hay tres cosas que podía hacer

  1. definir un lenguaje script sencillo dentro de mi programa
  2. utilizar una ya existente, la incorporación de un intérprete
  3. uso libdl para cargar * .so módulos en tiempo de ejecución

Me gusta el tercero y, si es posible, evito las otras dos opciones. Tal vez soy un masoquista de algún tipo, pero creo que podría ser divertido y útil para el aprendizaje.

Pensando lógicamente, la "cadena de dolor" obvia sería (de menor a mayor) 2 -> 1 -> 3, por la sencilla razón de que libdl está tratando con código sin procesar que puede (y explotará) en mi cara más a menudo que no.

Así que esta pregunta va para ustedes, usuarios de stackoverflow, ¿creen que libdl está a la altura de esta tarea, o incluso una idea realista?

Respuesta

3

libdl es muy adecuado para las arquitecturas de plug-in, dentro de ciertos límites :-). Se usa mucho para exactamente este tipo de propósito en muchos programas diferentes. Funciona bien en situaciones donde existe una API/interfaz bien definida entre el programa principal y el complemento, y una cantidad de complementos diferentes implementan la misma API/interfaz. Por ejemplo, su cliente de IRC puede tener complementos que implementan puertas de enlace a diferentes protocolos de mensajería instantánea (Jabber, MSN, Sametime, etc.). Todos estos son muy similares, por lo que podría definir una API con funciones como "enviar mensaje". "," verifique la respuesta ", etc., y escriba un montón de complementos que implementan uno diferente de los protocolos.

La situación en la que no funciona bien es donde desea que los complementos realicen cambios arbitrarios en el comportamiento del programa principal, de forma que, por ejemplo, los complementos de Firefox pueden cambiar el comportamiento del navegador pestañas, su apariencia, agregar/quitar botones, etc. Este tipo de cosas es mucho más fácil de lograr en un lenguaje dinámico (de ahí por qué gran parte de Firefox se implementa en JavaScript), y si este es el tipo de personalización que desea, puede ser mejor con su opción (2) y escribir un gran parte de su interfaz de usuario en el lenguaje de scripting ...

+0

Los cambios en la función principal son nulos; simplemente implementaría funciones como "on_channel_message (...)" -en otro pensamiento ... ¿pueden las bibliotecas cargadas con funciones de acceso libdl definirse en el programa principal? – LukeN

+0

A veces pueden, pero es más seguro suponer que no (porque (a) a veces hay que pasar banderas de compilación especiales para habilitarlo, y (b) ¡generalmente no quiere que se mezclen con funciones arbitrarias en el programa principal!). Por lo general, lo mejor que se puede hacer es pasar una estructura que contiene una lista de indicadores de función que el complemento puede llamar. – psmears

1

Existen muchos programas C existentes que usan dlopen()/dlsym() para implementar una arquitectura de complemento (que incluye más de un relacionado con IRC); así que sí, definitivamente depende de la tarea.

3

dlopen()/dlsym() son probablemente la forma más fácil de hacerlo.Parte del código pseudo tonta:

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; 
} 

Se podría, por supuesto, quiero mucho más en el camino de la comprobación de errores, así como el código que realmente hizo algo útil :) Es, sin embargo extremadamente fácil y conveniente escriba una arquitectura de plug-in alrededor del par y publique una especificación fácil para que otros hagan lo mismo.

Probablemente desee algo más en la línea de load_module(), lo anterior solo carga el SO, busca un punto de entrada y bloquea hasta que ese punto de entrada salga.

Eso no quiere decir que escribir su propio lenguaje de scripting sea una mala idea. La gente podría escribir filtros complejos, respondedores, etc. sin tener que pasar por un montón de problemas. Tal vez ambos serían una buena idea. No sé si querrías un intérprete LUA completo ... tal vez podrías encontrar algo que haga que tomar acciones basadas en expresiones regulares sea simple.

Aún así, los módulos con enchufes no solo simplificarán su vida, sino que también le ayudarán a desarrollar una comunidad de personas que desarrollen todo lo que haga.

Cuestiones relacionadas