LINUX.ORG.RU

[c++] Объектный интерфейс плагинов

 


0

1

Имеем common.h:

#ifndef _COMMON_H
#define _COMMON_H
#include <stdio.h>
using namespace std;

class Figure {
	public:
	virtual int draw(int x, int y) {
		printf("draw: %d %d\n", x, y);
	}
	virtual int print_hello() {
		printf("Hello World!\n");
	}
};

#endif
circle.cpp компилируется в circle.so, а класс Circle наследуется от Figure:
#include <stdio.h>
#include "common.h"

using namespace std;

class Circle : public Figure {
	public:
	virtual int draw(int x, int y) {
		printf("circle\n");
	}
};

Возможно ли теперь достать Figure из circle.co каким-нибудь похожим способом?

Figure *circle = loadPlugin("./circle.so");
circle->draw(0,0); // printf("Circle\n")
Важно, чтобы loader не приходилось перекомпилировать для новых плагинов. Сircle.cpp можете отредактировать как угодно (но все-таки желательно с сохранением идеи).

★★★

Важно, чтобы loader не приходилось перекомпилировать для новых плагинов.

Ога, и чтобы он понимал ABI разных компиляторов.

baverman ★★★
()

гм, да фиг его. может просто либу динамически подгузить? как-то ведь это можно сделать.. вызвать сишный метод стандартного для платформы лоадера, к примеру.

AndreyKl ★★★★★
()

Ё-моё, ну сколько можно — уже который раз такая тема lor/dev всплывает.

В плагине реализуешь класс. Делаешь функцию-фабрику, производящую объекты данного класса.

В коде, реализующем загрузку плагинов:
Грузишь модуль с плагином.
Получаешь имя функции из названия плагина. Получаешь адрес функции.
Используешь её для создания объектов указанного класса.

geekless ★★
()

В Си без плюсов можно сделать иначе — в *.so завести структуру, описывающую «методы» «объекта»:

/* Plugin descriptor. */
PluginClass dclock_plugin_class = {

    PLUGINCLASS_VERSIONING,

    type : "dclock",
    name : N_("Digital Clock"),
    version: "1.0",
    description : N_("Display digital clock and tooltip"),

    constructor : dclock_constructor,
    destructor  : dclock_destructor,
    config : dclock_configure,
    save : dclock_save_configuration,
    panel_configuration_changed : dclock_panel_configuration_changed
};

А в коде приложения грузить плагины следующим образом:

/* Load a dynamic plugin. */
static PluginClass * plugin_load_dynamic(const char * type, const gchar * path)
{
    PluginClass * pc = NULL;

    /* Load the external module. */
    GModule * m = g_module_open(path, G_MODULE_BIND_LAZY);
    if (m != NULL)
    {
        /* Formulate the name of the expected external variable of type PluginClass. */
        char class_name[128];
        g_snprintf(class_name, sizeof(class_name), "%s_plugin_class", type);

        /* Validate that the external variable is of type PluginClass. */
        gpointer tmpsym;
        if (( ! g_module_symbol(m, class_name, &tmpsym))        /* Ensure symbol is present */
        || ((pc = tmpsym) == NULL)
        || (pc->structure_size != sizeof(PluginClass))          /* Then check versioning information */
        || (pc->structure_version != PLUGINCLASS_VERSION)
        || (strcmp(type, pc->type) != 0))                       /* Then and only then access other fields; check name */
        {
            g_module_close(m);
            ERR("%s.so is not a lxpanel plugin\n", type);
            return NULL;
        }

        /* Register the newly loaded and valid plugin. */
        pc->gmodule = m;
        register_plugin_class(pc, TRUE);
    }
    return pc;
}


/* Create an instance of a plugin with a specified name, loading it if external. */
Plugin * plugin_load(char * type)
{
    /* Initialize static plugins on first call. */
    if (pcl == NULL)
        init_plugin_class_list();

    /* Look up the PluginClass. */
    PluginClass * pc = plugin_find_class(type);

#ifndef DISABLE_PLUGINS_LOADING
    /* If not found and dynamic loading is available, try to locate an external plugin. */
    if ((pc == NULL) && (g_module_supported()))
    {
        gchar path[PATH_MAX];
        g_snprintf(path, sizeof(path), PACKAGE_LIB_DIR "/lxpanel/plugins/%s.so", type);
        pc = plugin_load_dynamic(type, path);
    }
#endif  /* DISABLE_PLUGINS_LOADING */

    /* If not found, return failure. */
    if (pc == NULL)
        return NULL;

    /* Instantiate the plugin */
    Plugin * plug = g_new0(Plugin, 1);
    plug->class = pc;
    pc->count += 1;
    return plug;
}

geekless ★★
()
Ответ на: комментарий от geekless

мне одному показалось что это не просто си без плюсов а glib?

там тогда самый сок (который нужен автору) в содержании метода g_module_open. а всё что ты описал - это как раз то что описал темосоздатель (прости хосподи слово то какое.. может темодел?), только через [s]жопу[/s] без плюшек плюсов.

AndreyKl ★★★★★
()
Ответ на: комментарий от AndreyKl

> там тогда самый сок (который нужен автору) в содержании метода g_module_open

В кишках g_module_open() не ничего особенного. Очередная обертка над функциями dl*.

man dlopen — всё то же самое легко делается непосредственно через них.

geekless ★★
()
Ответ на: комментарий от geekless

ну да, именно man dlopen и был ответом на вопрос темодела. всё остальное он уже написал (в том числе и то что ты продублировал, только что он экземпляры не считает, но это дело десятое).

AndreyKl ★★★★★
()
Ответ на: комментарий от AndreyKl

> только через [s]жопу[/s] без плюшек плюсов.

Все плюшки плюсов — это синтаксических сахар. Весь сахар останется с тобой, тут нет никаких проблем. Но таки да: ссылку на синтаксический сахар получить проблематично. А вот на make-функции класса — запросто.

geekless ★★
()
Ответ на: комментарий от AndreyKl

> именно man dlopen и был ответом на вопрос темодела

Мне как-то в голову не пришло, что он не заглянул сначала в гугл, а потом в man dlopen.

geekless ★★
()
Ответ на: комментарий от geekless

ну да.. всё так, я тоже удивился когда нагуглил с первой попытки..

AndreyKl ★★★★★
()

Решено, всем спасибо :)

Minoru ★★★
() автор топика
Ответ на: комментарий от baverman

Так ведь под Linux все живые компиляторы имеют GCC 3+ ABI.

Deleted
()

man libdl. Ну и man Poco.

Deleted
()

В плюсцах с этим делом выйдет говно.

Вон MS, чтобы говна не выходило, изобрели целый COM. Но это те еще костыли. Поэтому они пошли дальше, и изобрели целый дотнет.

Короче, не юзай плюсцы.

lovesan

anonymous
()
Ответ на: комментарий от anonymous

>Вон MS, чтобы говна не выходило, изобрели целый COM

Но вышло всё равно говно

Uter
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.