|
|
|
Теория плагинов30.04.2010, 17:02. Показов 34287. Ответов 40
Метки нет (Все метки)
Всем привет.
Для одной моей проги, нужно реализовать поддержку плагинов. Плагины предполагаются простенькие, написанные на Си. То, что плагин, это просто .so файл - понятно. То, что прога может дергать из .so файла функции - тоже понятно. 1. Непонятно то, как сам плагин сможет дергать функции из программы? 2. Программа написана на С++, но плагины предполагаю писать на Си, во избежания бинарной несовместимости. В этом случае, какие сложности могут возникнуть? 3. Еще непонятно, каким образом "разделять" плагины, ведь их может быть несколько? 4. И еще непонятно, каким образом программе "сообщить" какие функции дергать из конкретного плагина? 5. И еще непонятно, каким образом плагин, сможет дергать функции из другого плагина? Нужна теоретическая подкова ![]() Благодарен всем откликнувшимся.
0
|
|
| 30.04.2010, 17:02 | |
|
Ответы с готовыми решениями:
40
Написание плагинов для notepad++ Система плагинов Взаимодействие плагинов |
|
22 / 22 / 2
Регистрация: 06.12.2010
Сообщений: 125
|
||||||||||||||||||||||||||
| 12.03.2011, 19:48 | ||||||||||||||||||||||||||
|
эхх... чем пояснять и доказывать, вот вам пример:
Я тут обнаружила потребность народа в некотором примере насчёт использования динамических библиотек. Вот, вытащила из своего проекта куски, относящиеся к загрузке и вызовам. Смысл примера такой: есть приложение, которое грузит (динамически) библиотеки с некоторым интерфейсом (IInterface). Все загружаемые библиотеки наследуют некоторое дефолтное поведение от базового класса (Base). Если библиотека не реализует какой-то метод интерфейса, то будет вызван базовый метод. Это чтобы не переписывать в каждой библиотеке одни и те же действия. Пример загружаемой библиотеки - Derived. Я привела флаги компиляции и сборки для разных систем (я собираю под линюксом с gcc и icc и под вендой с mingw). Вроде ничего не забыла, но возможно, что некоторые флаги не нужны для данного примера (я их поместила в квадратные скобки [...]). Просто у меня проект большой и там много чего ещё кроме этого, поэтому там могли оказаться не относящиеся к данной подзадаче параметры. Да, стандартные флаги для библиотек типа -ldl я сюда не выписывала. Выписаны только специфические параметры. Какие плюсы? Собственно, независимость библиотек от основного кода. Для добавления функционала достаточно перекомпилять загружаемые модули. Базовый функционал класса Base можно менять, не пересобирая библиотеки, которые его используют. Надеюсь, что в принципе понятно. Общий файл интерфейса Interface.h
gcc,icc: CXXFLAGS: -fPIC LDFLAGS: -nodefaultlibs -shared mingw: для венды установить дефайн__DLL (для экспорта) CXXFLAGS: LDFLAGS: -enable-auto-import [-enable-runtime-pseudo-reloc] -Wl,--kill-at Заголовок базового класса Base.h
Инструкции по сборке библиотеки Derived: gcc,icc: CXXFLAGS: -fPIC [-enable-runtime-pseudo-reloc] LDFLAGS: -nodefaultlibs -shared -lBase mingw: для венды установить дефайн __DLL (для экспорта) CXXFLAGS: LDFLAGS: -enable-auto-import [-Wl,--allow-multiple-definition] Заголовок файла основной динамически загружаемой библиотеки Derived.h
gcc,icc: CXXFLAGS: -fPIC LDFLAGS: mingw: CXXFLAGS: LDFLAGS: -enable-auto-import [-enable-runtime-pseudo-reloc] [-Wl,--allow-multiple-definition] -Wl,--kill-at Пример загрузки/выгрузки библиотеки Derived и использования класса (вызов метода init):
меня давно просили и вот количество просьб превысило порог моей лени и я написала своеобразный "отчёт о проделанной работе". перекопав море документации и наступив на кучу граблей, я всё-таки решила свою задачу. не знаю, подойдёт-не подойдёт, но мне кажется, что эти именно то самое, о чём спрашивал niXman или, во всяком случае, очень близкая к этому задача. да, кстати: в С++ классы экспортировать можно. только есть некоторые ограничения. но их можно аккуратненько обойти а внутри одного комплятора (это уже совсем шёпотом) можно даже экспортировать классы без фабрики! просто надо маленько ассемблера добавить и знать чуть-чуть реализацию виртуальных таблиц - и дело в кармане. если очень нужно - могу найти статью, как это делается под вендой. но мне это было не нужно, так как у меня задача как раз - наибольшая переносимость по платформам и компиляторам.
1
|
||||||||||||||||||||||||||
|
|
|
| 13.03.2011, 02:16 [ТС] | |
|
Evg, давайте пойдем с другой стороны.
в моей реализации, что конкретно вы считаете неправильным? и почему? Iron Bug, посмотрел вашу статью. но возник всего один вопрос: что в вашем примере, радикально отличается от моего варианта?! единственное это то, что ваш вариант менее функционален, и сильно хуже спроектирован. или я что-то пропустил? ... подскажите.
0
|
|
|
|
||||||||
| 13.03.2011, 10:24 | ||||||||
0
|
||||||||
|
22 / 22 / 2
Регистрация: 06.12.2010
Сообщений: 125
|
|||
| 13.03.2011, 11:49 | |||
|
Добавлено через 10 минут
0
|
|||
|
|
|
| 13.03.2011, 12:02 | |
|
Iron Bug,
1. Твой код - это обычная реализация виртуального наследования, вынесенного в динамическую библиотеку. 2. В твоём коде нет экспорта типов, потому что на Си++ это невозможно. Ты путаешь понятие экспорта типа и экспорта данных или функций. И твой размышления по части манглирования подтверждают это. 3. Твой код работает только под виндами и линуксом, а потому назвать его кроссплатформенным - несколько оптимистично. Тем более, что даже на две платформы с идеологической точки зрения разведено неправильно. Так же мне с ходу непонятно наличие специфических флагов типа -enable-runtime-pseudo-reloc или -Wl,--allow-multiple-definition, но я под виндой практически не работаю Мне не хотелось бы заниматься подробным обсуждением твоего кода, потому что в данной теме речь идёт совсем о другом. Но твой код, применительно к данной теме - это пример правильной реализации того, как должен выглядеть плагин. Потому что код плагина не выходит за рамки базового интерфейса, предоставленного для работы с плагином. Чего нет в варианте от niXman'а
0
|
|
|
22 / 22 / 2
Регистрация: 06.12.2010
Сообщений: 125
|
||
| 13.03.2011, 12:12 | ||
|
P.S. но в моей реализации там есть "фабрики" - функции для создания и уничтожения представителя класса, реализованные внутри библиотеки. это требуется для совместимости библиотек, собранных разными компиляторами. ибо там выделение памяти разное и прочие различия имеются. сами "фабрики" имеют фиксированные имена и также цепляются через dlsym.
Добавлено через 4 минуты а по части манглирования внутри совместимых на уровне кода (фактически, скомпиленных одним компилятором) библиотек возможна подгрузка куска памяти и инициализация указателей через ассемблер. это и будет чистым "импортом класса". но этот вариант мне не подходит. что касается кроссплатформенности, то мне нужны только линь и венда. по сути, линь - это моя инициатива. а так, всё написано через буст и исключительно стандартные библиотеки. так что если потребуется реализация для мака или ещё чего-то - это будет требовать минимума изменений в коде. софтина сложная и совсем без ifdef'ов тут не обойтись, увы.
0
|
||
|
|
||||
| 13.03.2011, 12:21 | ||||
|
0
|
||||
|
22 / 22 / 2
Регистрация: 06.12.2010
Сообщений: 125
|
||
| 13.03.2011, 12:37 | ||
|
http://www.codeproject.com/KB/... ingLL.aspx это реализация для венды, но под линём тоже можно найти аналогичное решение. ведь загрузчик в этой инфе лазит и её инициализирует. значит, и мы можем это сделать. просто это геморно, архитектурно-зависимо и для моей задачи не подходит. но это работает. если очень усираться, то можно написать такие "загрузчики" для всех систем и архитектур. только нафига оно надо... а про методы именно так и есть. мы должны знать имя. на самом деле, мы можем выкопать его из виртуальной таблицы. но тут включается семантика. ну вот мы выкопали имя, деманглировали (если и это не лень), выковыряли из мангла типы переменных и их количество... а дальше-то что? как это использовать? мы ничего не знаем о семантике метода и его назначении. вот и приплыли.
0
|
||
|
|
||
| 13.03.2011, 17:12 [ТС] | ||
|
вот ты, для того чтоб выделить память, почему используешь функцию malloc() ? вот и мне, для того чтоб использовать функционал предоставляемый плагином реализующим type1, нужно знать интерфейс к type1.
0
|
||
|
|
|||
| 13.03.2011, 17:42 | |||
|
Добавлено через 44 секунды
0
|
|||
|
|
||
| 13.03.2011, 18:03 [ТС] | ||
|
т.е. я работаю на основе информации известной из интерфейса. а из интерфейса я знаю, что у некоторого типа есть некоторые методы. так же знаю, что поведение методов определено не интерфейсом, а его реализацией в плагине. Добавлено через 2 минуты Evg, по моему, мы говорим о разном...
0
|
||
|
|
|||
| 13.03.2011, 18:04 | |||
|
Добавлено через 45 секунд
0
|
|||
|
|
||
| 13.03.2011, 18:08 [ТС] | ||
|
name() description() version() и наследование от этого типа, обязывает реализатора плагина, переопределить эти методы, дабы они возвращали информацию о реализуемом плагине. Добавлено через 1 минуту к примеру, я выкину тип plugin_object, и изменю функцию instance() так, чтоб она возвращала указатель на void. это будет то, о чем говоришь ты?
0
|
||
|
|
|||
| 13.03.2011, 18:18 | |||
|
Iron Bug приводила ссылку со своей реализацией. Вот там всё было правильно: из главной программы не было никаких обращений, выходящих за рамки интерфейса. Вот возьми, к примеру, фотошоп. У него куча всяких фильтров (которые выполняют преобразование изображения). Все они реализованы в виде плагинов и могут добавляться к программе (в том числе и от сторонних разработчиков). Интерфейс плагина, в самом примитивном случае состоит из следующего: - создать экземпляр класса "плагин". Реально создастся экземпляр пронаследованного класса, но он будет отдан программе в виде указателя на базовый класс - выполнить преобразование картинки: в некий метод, определённый в базовом классе, отдаётся картинка на вход и принимается картинка на выходе. Главная программа никоим образом не знает о том, через какой класс всё это реализовано внутри плагина. Знает лишь то, что этот класс является производным классом от базового класса плагина. И главная программа пользуется лишь тем интерфейсом, который описан в базовом классе. Никаких Set и get, который в базовом классе нет
0
|
|||
|
|
|||
| 13.03.2011, 18:36 [ТС] | |||
|
я хочу чтоб плагин type1.so экспортировал функционал согласно интерфейсу type1. поэтому, я получив от плагина инстанс, кастую его к типу type1*, и работаю с указателем на type1. одновременно, я хочу юзать плагин type2.so. так же, получаю инстанс, и кастую его к типу type2*, и работаю с указателем на type2. все. невижу противоречий и нелогичности.
0
|
|||
|
|
|||
| 13.03.2011, 18:47 | |||
|
Я могу реализовать динамическую библиотеку, экспортировать в ней функцию trampampam, в которую передаются два int'а, а она будет возвращать их сумму. Далее могу для вычисления суммы двух чисел подключать эту библиотеку через dlopen и работать через ней. Могу назвать эту библиотеку "плагином". И всё будет работать. За исключением того, что это НЕ будет являться плагином
0
|
|||
|
|
|||
| 13.03.2011, 19:00 [ТС] | |||
|
но мне нужна возможность использовать несколько типов интерфейсов обязывая себя знать, какой плагин, какой интерфейс реализует. детали же реализация плагина мне не известны. это мне и требуется.
0
|
|||
| 13.03.2011, 19:00 | |
|
Как видео с камеры отобразить в браузере без использования сторонних плагинов? Реализовать систему плагинов (модулей), каждый из которых должен работать в отдельном потоке Взаимодействие плагинов с ядром Установка плагинов cppunit + ecut в Eclipse Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
|
|||
|
[golang] Конкурентный fetcher с ограничением максимального количества одновременных HTTP запросов.
alhaos 10.06.2026
Задача
Реализовать конкурентный fetcher с ограничением максимального количества одновременных HTTP запросов.
Сигнатура
func Fetch(urls string, maxConcurrent int) Result
Пример
urls :=. . .
|
[golang] Состояние гонки (race condition)
alhaos 10.06.2026
Состояние гонки (race condition)
Состояние гонки (Race Condition) — это ошибка, возникающая при одновременном доступе нескольких горутин к одним и тем же данным без должной синхронизации. При этом. . .
|
Взрослые отношения, и почему они не получаются
kumehtar 09.06.2026
Когда в детстве ребёнок не получает от родителей чего-то важного, он лишается не просто приятных переживаний, а основы для формирования определённых внутренних качеств и навыков. Если ребёнок не. . .
|
[golang] Worker Pool
alhaos 09.06.2026
Worker Pool
Worker Pool — паттерн конкурентной обработки задач в Go.
Суть: фиксированное количество горутин-воркеров читают задачи из общего канала
и пишут результаты в общий канал результатов. . . .
|
|
[golang] Pipeline
alhaos 08.06.2026
Pipeline
Pipeline — паттерн конкурентной обработки данных в Go.
Суть: данные проходят через цепочку независимых стадий, каждая из которых работает в своей горутине и общается с соседями через. . .
|
Свет внутри себя
kumehtar 07.06.2026
Пусть это будет здесь
lIs4oanZS9Y
|
Программа для com-порта
Uhbif79 05.06.2026
Всем привет, давно хотел изучить Qt, начинал, бросал, потом снова начинал. И сейчас вот смог написать свою первую программу.
До этого имел опыт программирования микроконтроллеров, писал прошивки на. . .
|
Транскрипция 55-минутного видео через Whisper: WhisperDesktop облажался, спас Google Colab[
anaschu 01.06.2026
Понадобилось получить текст из свежезагруженного видео на YouTube. Казалось бы, задача на пять минут. Заняла полтора часа. Делюсь опытом — может кому пригодится последовательность решений.
. . .
|