![]() |
Здравствуйте, гость ( Вход | Регистрация )
![]() |
mva |
![]()
Сообщение
#1
|
Участник ![]() ![]() Группа: Участник Сообщений: 104 Регистрация: 15.3.2009 Из: Киров Пользователь №: 615 Спасибо сказали: 3 раз(а) Репутация: ![]() ![]() ![]() |
Добрый день!
Никак не могу найти в документации описание того, как правильно из плагина вызывать метод класса основного приложения. У меня выдается сообщение об ошибке "...: symbol lookup error: ... : undefined symbol: ... ". Может кто подскажет как это делается или где искать? |
|
|
![]() |
igor_bogomolov |
![]()
Сообщение
#2
|
Профессионал ![]() ![]() ![]() ![]() ![]() Группа: Сомодератор Сообщений: 1215 Регистрация: 22.3.2009 Из: Саратов Пользователь №: 630 Спасибо сказали: 235 раз(а) Репутация: ![]() ![]() ![]() |
Ну, видимо, у меня используется подобная архитектура.
Т.е. есть некий функционал который используется как в основном приложении так и в плагинах. Сначала эти файлы у меня участвовали в компиляции как основного приложения так и плагинов. Т.е. происходило некое дублирование. И никаких проблем с этим нет, пока нет статических полей, ну или просто каких то общи данных, разделяемых между приложением и плагинами. Сейчас общий код у меня вынесен в отдельную разделяемую библиотеку, которая уже и используется всеми кто в ней заинтересован. Это мне кажется оптимальным вариантом. В качестве еще одного варианта могу предложить GCC visibility (тык тык тык) |
|
|
Litkevich Yuriy |
![]()
Сообщение
#3
|
![]() разработчик РЭА ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Сомодератор Сообщений: 9669 Регистрация: 9.1.2008 Из: Тюмень Пользователь №: 64 Спасибо сказали: 807 раз(а) Репутация: ![]() ![]() ![]() |
если я правильно понимаю происходящее, то проблема в том, что некие классы в приложении и в библиотеке, должны взаимодействовать не напрямую, а через абстрактный интерфейсный класс (с истинно виртуальными методами).
На мой взгляд это единственный способ сказать линкеру, что реализации метода нет и не нужно её пытаться искать. |
|
|
SABROG |
![]()
Сообщение
#4
|
![]() Профессионал ![]() ![]() ![]() ![]() ![]() Группа: Участник Сообщений: 1207 Регистрация: 8.12.2008 Из: Russia, Moscow Пользователь №: 446 Спасибо сказали: 229 раз(а) Репутация: ![]() ![]() ![]() |
Никак не могу найти в документации описание того, как правильно из плагина вызывать метод класса основного приложения. У меня выдается сообщение об ошибке "...: symbol lookup error: ... : undefined symbol: ... ". Может кто подскажет как это делается или где искать? Вероятно можно передавать указатель на нужный объект через специальный метод, который объявить в плагине, типа setApplicationObject(QObject*). Приложение при подгрузке плагинов будет передавать в этот метод указатель на нужный объект. А там уже можно будет и через сигналы общаться. |
|
|
wiz29 |
![]()
Сообщение
#5
|
![]() Старейший участник ![]() ![]() ![]() ![]() Группа: Участник Сообщений: 600 Регистрация: 7.7.2010 Из: Санкт-Петербург Пользователь №: 1866 Спасибо сказали: 94 раз(а) Репутация: ![]() ![]() ![]() |
Думаю, правльно былобы иметь некий интерфейс, реализованый на уровне приложения, и передавть в плагин указатель на интерфейс.
Все остальные подходы имеют свои недостатки и усиливают бинарную связь между плагином и приложением. |
|
|
mva |
![]()
Сообщение
#6
|
Участник ![]() ![]() Группа: Участник Сообщений: 104 Регистрация: 15.3.2009 Из: Киров Пользователь №: 615 Спасибо сказали: 3 раз(а) Репутация: ![]() ![]() ![]() |
Думаю, правльно былобы иметь некий интерфейс, реализованый на уровне приложения, и передавть в плагин указатель на интерфейс. Все остальные подходы имеют свои недостатки и усиливают бинарную связь между плагином и приложением. Этот вариант мне показался самым простым. Если под интерфейсом понимается простой класс-прослойка, а не какой-либо специализированный класс Qt, то я вчера попробовал сделать такой интерфейс. Результат тот же. Точно также плагин не находит методы-члены этого класса. Вероятно можно передавать указатель на нужный объект через специальный метод, который объявить в плагине, типа setApplicationObject(QObject*). Приложение при подгрузке плагинов будет передавать в этот метод указатель на нужный объект. А там уже можно будет и через сигналы общаться. Да, у меня так и сделано. Проблема только в том, что через механизм сигналов-слотов нельзя вернуть данные. На мой взгляд это единственный способ сказать линкеру, что реализации метода нет и не нужно её пытаться искать. Сообщение об ошибке появляется не на этапе линковки, а во время выполнения программы в момент обращения к функции основного приложения в плагине. Ну, видимо, у меня используется подобная архитектура. Т.е. есть некий функционал который используется как в основном приложении так и в плагинах. Сначала эти файлы у меня участвовали в компиляции как основного приложения так и плагинов. Т.е. происходило некое дублирование. И никаких проблем с этим нет, пока нет статических полей, ну или просто каких то общи данных, разделяемых между приложением и плагинами. Сейчас общий код у меня вынесен в отдельную разделяемую библиотеку, которая уже и используется всеми кто в ней заинтересован. Это мне кажется оптимальным вариантом. В качестве еще одного варианта могу предложить GCC visibility (тык тык тык) Я так понял, что GCC visibility имеет смысл, если создается библиотека. Выделение искомого кода в библиотеку затруднительно по причине большой связности с остальным кодом. Это везде перед вызовом функции нужно вставлять код для поиска данной функции в библиотеке. Хотелось бы сделать по-проще. Пока думаю остановиться на таком варианте: после загрузки плагина "начинить" его необходимыми для его работы данными, чтобы он сам не обращался за ними в основную программу. Но вопрос вызова функций из основного приложения все же остается открытым. |
|
|
Litkevich Yuriy |
![]()
Сообщение
#7
|
![]() разработчик РЭА ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Сомодератор Сообщений: 9669 Регистрация: 9.1.2008 Из: Тюмень Пользователь №: 64 Спасибо сказали: 807 раз(а) Репутация: ![]() ![]() ![]() |
приведи код интерфейса и код использования в плагине. Как ты вызываешь метод?
|
|
|
SABROG |
![]()
Сообщение
#8
|
![]() Профессионал ![]() ![]() ![]() ![]() ![]() Группа: Участник Сообщений: 1207 Регистрация: 8.12.2008 Из: Russia, Moscow Пользователь №: 446 Спасибо сказали: 229 раз(а) Репутация: ![]() ![]() ![]() |
Но вопрос вызова функций из основного приложения все же остается открытым. Если ты можешь передавать указатель на QObject, то передавай указатель на "void *" и приводи его к нужному интерфейсу. Через механизм сигналов-слотов данные вернуть можно через схему: сигнал_запрос - слот - сигнал_ответ. Если нужно дождаться ответного сигнала, то можно QEventLoop использовать. |
|
|
igor_bogomolov |
![]()
Сообщение
#9
|
Профессионал ![]() ![]() ![]() ![]() ![]() Группа: Сомодератор Сообщений: 1215 Регистрация: 22.3.2009 Из: Саратов Пользователь №: 630 Спасибо сказали: 235 раз(а) Репутация: ![]() ![]() ![]() |
Написал тестовый пример имитирующий проблему (переделанный стандартный пример из поставки Qt). Сам пример, конечно, не самый элегантный, но все проблемы и возможные способы решения он показывает.
Сам пример в приложении. Предлагаю его в том виде, когда он даст ошибку на этапе исполнения, как раз то о чем говорит mva Я расширил стандартный пример неким классом SharedUtils который находится в файле shared_utils.* Этот код компилируется вместе с приложением. А теперь возникает ситуация, что этот функционал, который предоставляет SharedUtils, необходим не только приложению, но и плагину. Тот код, который я приложил, удачно скомпилируется (и приложение даже запустится), но при нажатии на кнопку произойдет ошибка, и в общем понятно почему. Я ранее еще предложил три пути решения этой проблемы 1. Включить shared_utils.* в компиляцию плагина. Модифицируем plugin pro И, ву а ля, все работает. Но это не хорошо. Т.о. мы просто продублировали функционал. Если у нас появятся статические данные, будут проблемы, т.к. статическая переменная в приложении и в плагине - это две совершенно разные переменные. 2. Выделить общий код в разделяемую библиотеку (.dll/.so). (У меня в проекте сделано именно так) 3. GCC visibility. Добавляем в файл проекта приложения следущую строку
И помечаем класс следующим образом Всё, этого вполне достаточно.
Прикрепленные файлы
|
|
|
mva |
![]()
Сообщение
#10
|
Участник ![]() ![]() Группа: Участник Сообщений: 104 Регистрация: 15.3.2009 Из: Киров Пользователь №: 615 Спасибо сказали: 3 раз(а) Репутация: ![]() ![]() ![]() |
Извиняюсь, не указал важную деталь и возможно ввел в заблуждение: ошибка происходит в слоте, который является элементом плагина. В остальной части плагина вызов функций основного приложения происходит корректно.
|
|
|
igor_bogomolov |
![]()
Сообщение
#11
|
Профессионал ![]() ![]() ![]() ![]() ![]() Группа: Сомодератор Сообщений: 1215 Регистрация: 22.3.2009 Из: Саратов Пользователь №: 630 Спасибо сказали: 235 раз(а) Репутация: ![]() ![]() ![]() |
Т.е. падение происходит когда приложение испускает сигнал?
Тогда такой вопрос, каким образам вы связываете сигнал приложения со слот плагина? P.S. Перечитал еще раз и запутался окончательно. Если бы вы приложили код было бы понятнее что у вас происходит. |
|
|
wiz29 |
![]()
Сообщение
#12
|
![]() Старейший участник ![]() ![]() ![]() ![]() Группа: Участник Сообщений: 600 Регистрация: 7.7.2010 Из: Санкт-Петербург Пользователь №: 1866 Спасибо сказали: 94 раз(а) Репутация: ![]() ![]() ![]() |
Извиняюсь, не указал важную деталь и возможно ввел в заблуждение: ошибка происходит в слоте, который является элементом плагина. В остальной части плагина вызов функций основного приложения происходит корректно. Покажите пожалуйста примерный вариант кода (где и как вызыватются нужные методы, с описанием сторон, под сторонами я понимаю плагин/приложение). не обязательно полный. |
|
|
mva |
![]()
Сообщение
#13
|
Участник ![]() ![]() Группа: Участник Сообщений: 104 Регистрация: 15.3.2009 Из: Киров Пользователь №: 615 Спасибо сказали: 3 раз(а) Репутация: ![]() ![]() ![]() |
Вот код плугина
searchparameters.h Раскрывающийся текст
searchparameters.cpp Раскрывающийся текст
Плагин SearchParameters "заряжается" примерно так: Раскрывающийся текст
QtDesigner принимает этот плагин. Написал тестовый пример имитирующий проблему (переделанный стандартный пример из поставки Qt). Сам пример, конечно, не самый элегантный, но все проблемы и возможные способы решения он показывает. Спасибо за пример. Обязательно его изучу. Т.е. падение происходит когда приложение испускает сигнал? Тогда такой вопрос, каким образам вы связываете сигнал приложения со слот плагина? Да, приложение падает, когда испускается сигнал, точнее когда начинает выполняться код соответствующего слота. Сигнал исходит от кнопки, которая является частью плагина и обрабатывается слотом в этом же плагине. |
|
|
igor_bogomolov |
![]()
Сообщение
#14
|
Профессионал ![]() ![]() ![]() ![]() ![]() Группа: Сомодератор Сообщений: 1215 Регистрация: 22.3.2009 Из: Саратов Пользователь №: 630 Спасибо сказали: 235 раз(а) Репутация: ![]() ![]() ![]() |
Видимо в файле проекта плагина отсутствуют следущие файлы
|
|
|
mva |
![]()
Сообщение
#15
|
Участник ![]() ![]() Группа: Участник Сообщений: 104 Регистрация: 15.3.2009 Из: Киров Пользователь №: 615 Спасибо сказали: 3 раз(а) Репутация: ![]() ![]() ![]() |
Все, проблему решил простейшим образом.
CODE void SearchParameters::dictionaryButtonPressed() { app->getDictionaries()->addDictionary(sender()->objectName(), 0); //здесь происходит сбой symbol lookup error .../libplugins.so: undefined symbol: _ZN12Dictionaries13addDictionaryE7QStringi Dictionary* dict = app->getDictionaries()->getDictionary(sender()->objectName()); if (dict != 0) { ... } ... } Всего-то что сделал - объявил функцию addDictionary(QString, int) в классе Dictionaries виртуальной. И все. Т.е. получается, что функции, вызываемые плагином из основного приложения должны быть виртуальными. Всем спасибо за помощь. |
|
|
![]() ![]() ![]() |
![]() |
|
Текстовая версия | Сейчас: 2.6.2025, 5:24 |