LINUX.ORG.RU

«Статическая» модульность


0

0

Дано: язык C++, программа и модулей main.cpp, m1.cpp, m2.cpp, m3.cpp... Требуется: изменением одного единственного конфигурационного файла собирать программу с разным набором модулей из m1...mN. Поддрежка работы указанных модулей должна быть полной и не зависимой от самих модулей.

Кто чего умного посоветует? Книги там какие или примеры как сделать...

Я пока придумал только так: каждый модуль определяет некую функцию init_module(), некий препроцессор создаёт массив из указателей на эти функции, который просматривается в main.cpp для поиска нужного модуля. Подход можно развивать и детализировать.


Кстати, а в других языках как такое делается? Питон, наример, или Java... А может Lisp?

yz
() автор топика

> Кто чего умного посоветует?

"Я тебе один умный вещь скажу, ты только не обижайся" (c): если хочешь, чтобы тебе ответили - задавай вопросы понятно.

tailgunner ★★★★★
()

а чем так - не выход?

class AbstractModuleParent{}; - абстрактный класс, определяемый в головной программе

class Module : private AbstractModuleParent{}; -- класс, сожержащий код модуля.

AbstractModuleParent ** modules; -- массив модулей.

int modules_count; -- счетчик числа модулей

и в конструкторе модуля пишем:

Module::Module() { modules[modules_count] = this; modules_count ++; //ну и соответственно все операции с памятью по выделению места для массива. }

ну и естественно в тексте модуля определяем переменную

Module my_module;

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

ну а файлом конфигурационным будет соответственно твой Makefile - указывай список файлов для компиляции - и все.

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

> А что не понятно?

Что значит "собирать программу" в данном случае - собирать бинарь? Если да, то чем не устраивает обычный препроцессорный #ifdef? Что живет в модулях - каждый предоставляет разные API или они "примерно одинаковые" (так, что его можно выразить как абстрактный базовый класс/вектор функций)?

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

wieker, твой вариант предполагает, что все доступные модули создаются при запуске прораммы. Как мы узнаем, какие модули у нас есть, чтобы вызвать их конструкторы?

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

ты в тексте модуля поределяешь переменную, при определении переменной вызывается ее конструктор. - в Си++ ручками конструктор вызывать и не надо.

а сам конструктор уже даст знать основной программе через массив modules что он есть. че тут непонятного? ты Си++ знаешь? или я чего не понимаю?

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

tailgunner, собирать -- значит скомпилировать бинарник (exe или библиотеку) с заранее определённым набором модулей.

Модули могут быть разные. Например каждый модуль делает какую-то определённую обработку данных. В принципе, API вызова модуля можно сделать универсальным. Даже, наверное, придётся...

Базовый класс для модуля это понятно. Вопрос в том, как "запускалка модулей" у юзера узнает, с какими модулями она скомпилирована.

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

ну именно это я и написал в примере.

глобальная переменная для каждого модуля - конструктор которой сообщает программе о то что модуль собран.

ну или использовать какой-либо метаязык если это не устраиает - начиная от стандартного препроцессора Си++ и заканчивая всякими autogen и прочим. Вон в Qt не стесняются moc исползовать

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

> собирать -- значит скомпилировать бинарник (exe или библиотеку) с заранее определённым набором модулей.

Тогда условная компиляция

> Вопрос в том, как "запускалка модулей" у юзера узнает, с какими модулями она скомпилирована.

Конфигурационный файл определяет, с какими define'ами компилируется программа (-DHAVE_MODULE_FOO -DHAVE_MODULE_BAR). Код запускалки находится под #ifdef:

#ifdef HAVE_MODULE_FOO

init_foo(42, "dbzz");

#endif

Загляни в ядерный init/main.c, например.

P.S. а викер - он по молодости любит усложнять ;)

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

Да, в моём случае этих -DHAVE_MODULE_FOO будет несколько десятков... А ещё надо учесть, что модули могут зависеть друг от друга...

init_foo() это понятно. Однако, юзер будет составлять цепочку всего из нескольких модулей, запускаемых последовательно один за другим, хотя выбор у него должен быть из нескольких десятков. В связи с этим полную инициализацию модуля в int_foo() делать нехорошо, да и не возможно, так как нет нужной входной информации. Соответсвенно, этот init_foo() будет лишь что-то куда-то прописывать, чтобы потом можно было знать, что модуль есть и им можно воспользоваться. Так может эти действия как-то в компиль-тайм запихнуть? Понятное дело, что структура с информацией о модулях всё равно в рантайме создаваться будет, но сама информация уже может быть готова...

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

Может, тебе посмотреть на CML2 и язык конфигурации ядра?

> полную инициализацию модуля в int_foo() делать нехорошо, да и не возможно

И хорошо, и возможно. Просто вызывай init_bar без условной компиляции, и линковщик сам разрулит зависимости.

tailgunner ★★★★★
()

Ну в общем ты сам все уже придумал, только можно использовать не препроцессор а разделяемые библиотеки (*.so). Компилируешь модули как отдельные разделяемые библиотеки, кладешь в одну директорию, а основной модуль просматривая эту директорию вызывает функцию init_module() из каждой (man dlopen, dlsym, dlclose).

anonymous
()

Ну в общем ты сам все уже придумал, только можно использовать не препроцессор а разделяемые библиотеки (*.so). Компилируешь модули как отдельные разделяемые библиотеки, кладешь в одну директорию, а основной модуль просматривая эту директорию вызывает функцию init_module() из каждой (man dlopen, dlsym, dlclose).

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

Предупреждение: CML2, как говорится, "abandoned upstream" - то есть автор его забросил уже довольно давно.

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