crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

mva
  опции профиля:
сообщение 17.9.2010, 22:03
Сообщение #1


Участник
**

Группа: Участник
Сообщений: 104
Регистрация: 15.3.2009
Из: Киров
Пользователь №: 615

Спасибо сказали: 3 раз(а)




Репутация:   0  


Добрый день!

Никак не могу найти в документации описание того, как правильно из плагина вызывать метод класса основного приложения. У меня выдается сообщение об ошибке "...: symbol lookup error: ... : undefined symbol: ... ". Может кто подскажет как это делается или где искать?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
2 страниц V   1 2 >  
Начать новую тему
Ответов (1 - 14)
igor_bogomolov
  опции профиля:
сообщение 18.9.2010, 0:33
Сообщение #2


Профессионал
*****

Группа: Сомодератор
Сообщений: 1215
Регистрация: 22.3.2009
Из: Саратов
Пользователь №: 630

Спасибо сказали: 235 раз(а)




Репутация:   29  


Ну, видимо, у меня используется подобная архитектура.
Т.е. есть некий функционал который используется как в основном приложении так и в плагинах. Сначала эти файлы у меня участвовали в компиляции как основного приложения так и плагинов. Т.е. происходило некое дублирование. И никаких проблем с этим нет, пока нет статических полей, ну или просто каких то общи данных, разделяемых между приложением и плагинами. Сейчас общий код у меня вынесен в отдельную разделяемую библиотеку, которая уже и используется всеми кто в ней заинтересован. Это мне кажется оптимальным вариантом.

В качестве еще одного варианта могу предложить GCC visibility (тык тык тык)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 18.9.2010, 8:44
Сообщение #3


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9669
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


если я правильно понимаю происходящее, то проблема в том, что некие классы в приложении и в библиотеке, должны взаимодействовать не напрямую, а через абстрактный интерфейсный класс (с истинно виртуальными методами).
На мой взгляд это единственный способ сказать линкеру, что реализации метода нет и не нужно её пытаться искать.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
SABROG
  опции профиля:
сообщение 20.9.2010, 11:05
Сообщение #4


Профессионал
*****

Группа: Участник
Сообщений: 1207
Регистрация: 8.12.2008
Из: Russia, Moscow
Пользователь №: 446

Спасибо сказали: 229 раз(а)




Репутация:   34  


Цитата(mva @ 17.9.2010, 23:03) *
Никак не могу найти в документации описание того, как правильно из плагина вызывать метод класса основного приложения. У меня выдается сообщение об ошибке "...: symbol lookup error: ... : undefined symbol: ... ". Может кто подскажет как это делается или где искать?


Вероятно можно передавать указатель на нужный объект через специальный метод, который объявить в плагине, типа setApplicationObject(QObject*). Приложение при подгрузке плагинов будет передавать в этот метод указатель на нужный объект. А там уже можно будет и через сигналы общаться.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
wiz29
  опции профиля:
сообщение 20.9.2010, 12:28
Сообщение #5


Старейший участник
****

Группа: Участник
Сообщений: 600
Регистрация: 7.7.2010
Из: Санкт-Петербург
Пользователь №: 1866

Спасибо сказали: 94 раз(а)




Репутация:   12  


Думаю, правльно былобы иметь некий интерфейс, реализованый на уровне приложения, и передавть в плагин указатель на интерфейс.
Все остальные подходы имеют свои недостатки и усиливают бинарную связь между плагином и приложением.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
mva
  опции профиля:
сообщение 21.9.2010, 8:42
Сообщение #6


Участник
**

Группа: Участник
Сообщений: 104
Регистрация: 15.3.2009
Из: Киров
Пользователь №: 615

Спасибо сказали: 3 раз(а)




Репутация:   0  


Цитата(wiz29 @ 20.9.2010, 13:28) *
Думаю, правльно былобы иметь некий интерфейс, реализованый на уровне приложения, и передавть в плагин указатель на интерфейс.
Все остальные подходы имеют свои недостатки и усиливают бинарную связь между плагином и приложением.


Этот вариант мне показался самым простым. Если под интерфейсом понимается простой класс-прослойка, а не какой-либо специализированный класс Qt, то я вчера попробовал сделать такой интерфейс. Результат тот же. Точно также плагин не находит методы-члены этого класса.


Цитата(SABROG @ 20.9.2010, 12:05) *
Вероятно можно передавать указатель на нужный объект через специальный метод, который объявить в плагине, типа setApplicationObject(QObject*). Приложение при подгрузке плагинов будет передавать в этот метод указатель на нужный объект. А там уже можно будет и через сигналы общаться.


Да, у меня так и сделано. Проблема только в том, что через механизм сигналов-слотов нельзя вернуть данные.

Цитата(Litkevich Yuriy @ 18.9.2010, 9:44) *
На мой взгляд это единственный способ сказать линкеру, что реализации метода нет и не нужно её пытаться искать.


Сообщение об ошибке появляется не на этапе линковки, а во время выполнения программы в момент обращения к функции основного приложения в плагине.

Цитата(igor_bogomolov @ 18.9.2010, 1:33) *
Ну, видимо, у меня используется подобная архитектура.
Т.е. есть некий функционал который используется как в основном приложении так и в плагинах. Сначала эти файлы у меня участвовали в компиляции как основного приложения так и плагинов. Т.е. происходило некое дублирование. И никаких проблем с этим нет, пока нет статических полей, ну или просто каких то общи данных, разделяемых между приложением и плагинами. Сейчас общий код у меня вынесен в отдельную разделяемую библиотеку, которая уже и используется всеми кто в ней заинтересован. Это мне кажется оптимальным вариантом.

В качестве еще одного варианта могу предложить GCC visibility (тык тык тык)


Я так понял, что GCC visibility имеет смысл, если создается библиотека. Выделение искомого кода в библиотеку затруднительно по причине большой связности с остальным кодом. Это везде перед вызовом функции нужно вставлять код для поиска данной функции в библиотеке. Хотелось бы сделать по-проще.

Пока думаю остановиться на таком варианте: после загрузки плагина "начинить" его необходимыми для его работы данными, чтобы он сам не обращался за ними в основную программу. Но вопрос вызова функций из основного приложения все же остается открытым.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 21.9.2010, 9:33
Сообщение #7


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9669
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


приведи код интерфейса и код использования в плагине. Как ты вызываешь метод?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
SABROG
  опции профиля:
сообщение 21.9.2010, 11:15
Сообщение #8


Профессионал
*****

Группа: Участник
Сообщений: 1207
Регистрация: 8.12.2008
Из: Russia, Moscow
Пользователь №: 446

Спасибо сказали: 229 раз(а)




Репутация:   34  


Цитата(mva @ 21.9.2010, 9:42) *
Но вопрос вызова функций из основного приложения все же остается открытым.

Если ты можешь передавать указатель на QObject, то передавай указатель на "void *" и приводи его к нужному интерфейсу.

Через механизм сигналов-слотов данные вернуть можно через схему: сигнал_запрос - слот - сигнал_ответ. Если нужно дождаться ответного сигнала, то можно QEventLoop использовать.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
igor_bogomolov
  опции профиля:
сообщение 21.9.2010, 11:26
Сообщение #9


Профессионал
*****

Группа: Сомодератор
Сообщений: 1215
Регистрация: 22.3.2009
Из: Саратов
Пользователь №: 630

Спасибо сказали: 235 раз(а)




Репутация:   29  


Написал тестовый пример имитирующий проблему (переделанный стандартный пример из поставки Qt). Сам пример, конечно, не самый элегантный, но все проблемы и возможные способы решения он показывает.

Сам пример в приложении. Предлагаю его в том виде, когда он даст ошибку на этапе исполнения, как раз то о чем говорит mva

Я расширил стандартный пример неким классом SharedUtils который находится в файле shared_utils.* Этот код компилируется вместе с приложением.
А теперь возникает ситуация, что этот функционал, который предоставляет SharedUtils, необходим не только приложению, но и плагину. Тот код, который я приложил, удачно скомпилируется (и приложение даже запустится), но при нажатии на кнопку произойдет ошибка, и в общем понятно почему.

Я ранее еще предложил три пути решения этой проблемы
1. Включить shared_utils.* в компиляцию плагина. Модифицируем plugin pro
HEADERS         = echoplugin.h \
                  ../echowindow/shared_utils.h
SOURCES         = echoplugin.cpp \
                  ../echowindow/shared_utils.cpp
И, ву а ля, все работает. Но это не хорошо. Т.о. мы просто продублировали функционал. Если у нас появятся статические данные, будут проблемы, т.к. статическая переменная в приложении и в плагине - это две совершенно разные переменные.

2. Выделить общий код в разделяемую библиотеку (.dll/.so). (У меня в проекте сделано именно так)

3. GCC visibility. Добавляем в файл проекта приложения следущую строку
QMAKE_LFLAGS += -Wl,-export-dynamic -fvisibility=hidden


И помечаем класс следующим образом
class __attribute__ ((visibility ("default"))) SharedUtils
{
    ....
}
Всё, этого вполне достаточно.
Прикрепленные файлы
Прикрепленный файл  echoplugin.zip ( 5.11 килобайт ) Кол-во скачиваний: 145
 
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
mva
  опции профиля:
сообщение 21.9.2010, 11:49
Сообщение #10


Участник
**

Группа: Участник
Сообщений: 104
Регистрация: 15.3.2009
Из: Киров
Пользователь №: 615

Спасибо сказали: 3 раз(а)




Репутация:   0  


Извиняюсь, не указал важную деталь и возможно ввел в заблуждение: ошибка происходит в слоте, который является элементом плагина. В остальной части плагина вызов функций основного приложения происходит корректно.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
igor_bogomolov
  опции профиля:
сообщение 21.9.2010, 12:06
Сообщение #11


Профессионал
*****

Группа: Сомодератор
Сообщений: 1215
Регистрация: 22.3.2009
Из: Саратов
Пользователь №: 630

Спасибо сказали: 235 раз(а)




Репутация:   29  


Т.е. падение происходит когда приложение испускает сигнал?
Тогда такой вопрос, каким образам вы связываете сигнал приложения со слот плагина?

P.S. Перечитал еще раз и запутался окончательно. Если бы вы приложили код было бы понятнее что у вас происходит.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
wiz29
  опции профиля:
сообщение 21.9.2010, 12:09
Сообщение #12


Старейший участник
****

Группа: Участник
Сообщений: 600
Регистрация: 7.7.2010
Из: Санкт-Петербург
Пользователь №: 1866

Спасибо сказали: 94 раз(а)




Репутация:   12  


Цитата(mva @ 21.9.2010, 12:49) *
Извиняюсь, не указал важную деталь и возможно ввел в заблуждение: ошибка происходит в слоте, который является элементом плагина. В остальной части плагина вызов функций основного приложения происходит корректно.

Покажите пожалуйста примерный вариант кода (где и как вызыватются нужные методы, с описанием сторон, под сторонами я понимаю плагин/приложение). не обязательно полный.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
mva
  опции профиля:
сообщение 21.9.2010, 23:02
Сообщение #13


Участник
**

Группа: Участник
Сообщений: 104
Регистрация: 15.3.2009
Из: Киров
Пользователь №: 615

Спасибо сказали: 3 раз(а)




Репутация:   0  


Вот код плугина

searchparameters.h
Раскрывающийся текст
#include <QtGui>
#include <QFrame>
#include <QVBoxLayout>
#include <QString>
#include <QStringList>
#include <QWidget>
#include <QObject>
#include "mycombobox.h"
#include "formgridsearch.h"
#include "guifactory.h"
#include "../app.h"

class App;
class FormGridSearch;
struct sParam;

class SearchParameters : public QFrame {
    Q_OBJECT

public:
    SearchParameters(QWidget* parentWidget = 0);
    void setApp(App* a) { app = a; }
    void setFieldsList(QStringList);
    void setFormGrid(FormGridSearch* par) { parentForm = par; }
    void setProgramIdFieldName(QString s) { programIdFieldName = s; }
    void setProgramNameFieldName(QString s) { programNameFieldName = s; }

signals:
    void requery();

public slots:
    void dictionaryButtonPressed();

private:
    App* app;
    QString programIdFieldName;
    QString programNameFieldName;

    QGridLayout* gridLayout;
    QStringList parameters;
    FormGridSearch* parentForm;
    void addString(QString, int);
};


searchparameters.cpp
Раскрывающийся текст
#include <QString>
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QDebug>
#include <QSizePolicy>
#include <QFrame>
#include <QLayout>
#include <QKeyEvent>
#include "searchparameters.h"
#include "../dictionary.h"
#include "../dictionaries.h"
#include "formgrid.h"
#include "formgridsearch.h"
#include "../essence.h"


SearchParameters::SearchParameters(QWidget* parentWidget): QFrame(parentWidget) {
    gridLayout = 0;
}

void SearchParameters::setFieldsList(QStringList fldList) {
    ...
    gridLayout = new QGridLayout(this);
    int strNum = 0;
    for (int i = 0; i < fldList.count(); i++) {
        QString field = fldList.at(i);
        if (...)
            addString(field, strNum++); 
    }
    setLayout(gridLayout);
    ...
}

void SearchParameters::addString(QString name, int strNum) {
    ...
    MyComboBox* comboBox = new MyComboBox();
    ...
    connect (comboBox, SIGNAL(enterPressed(QWidget*)), this, SLOT(comboBoxEnterPressed(QWidget*)));
    ...
    gridLayout->addWidget(comboBox, strNum, 1, 1, 1);
    if (...) {
        ...
        QPushButton* button = new QPushButton("...");
        button->setObjectName(name);
        ...
        gridLayout->addWidget(button, strNum, 2, 1, 1);
        connect (button, SIGNAL(clicked()), this, SLOT(dictionaryButtonPressed()));
        labelName = app->getDictionaries()->getDictionaryProperty(name, "имя_в_форме").toString();   [b][size=3]// здесь вызов функции из основного приложения происходит нормально[/size][/b]
        ...
    }
    else {
        labelName = app->getDictionaries()->getDictionaryProperty(parentForm->getParent()->getTableName(), "имя_в_форме").toString();    [b][size=3]// здесь тоже нормально[/size][/b]
        ...
    }
    ...
    QLabel* label = new QLabel(labelName + ":");
    gridLayout->addWidget(label, strNum, 0, 1, 1, Qt::AlignRight);
}

void SearchParameters::dictionaryButtonPressed() {
    app->getDictionaries()->addDictionary(sender()->objectName(), 0);            [b][size=3]//здесь происходит сбой[/size][/b] symbol lookup error .../libplugins.so: undefined symbol: _ZN12Dictionaries13addDictionaryE7QStringi
    Dictionary* dict = app->getDictionaries()->getDictionary(sender()->objectName());
    if (dict != 0) {
        ...
    }
    ...
}


Плагин SearchParameters "заряжается" примерно так:
Раскрывающийся текст
        extern App* app;
        ...
        QPointer<SearchParameters> parameters;
        ...
        parameters = (SearchParameters*)formWidget->findChild<QFrame*>("searchParameters");
        if (parameters) {
            parameters->setApp(app);
            parameters->setParent(formWidget);
            parameters->setFormGrid(this);
            parameters->setProgramIdFieldName(programIdFieldName);
            parameters->setProgramNameFieldName(programNameFieldName);
            parameters->setFieldsList(parent->getFieldsList());
            connect(parameters, SIGNAL(requery()), this, SLOT(cmdRequery()));
        }


QtDesigner принимает этот плагин.


Цитата(igor_bogomolov @ 21.9.2010, 12:26) *
Написал тестовый пример имитирующий проблему (переделанный стандартный пример из поставки Qt). Сам пример, конечно, не самый элегантный, но все проблемы и возможные способы решения он показывает.


Спасибо за пример. Обязательно его изучу.

Цитата(igor_bogomolov @ 21.9.2010, 13:06) *
Т.е. падение происходит когда приложение испускает сигнал?
Тогда такой вопрос, каким образам вы связываете сигнал приложения со слот плагина?


Да, приложение падает, когда испускается сигнал, точнее когда начинает выполняться код соответствующего слота. Сигнал исходит от кнопки, которая является частью плагина и обрабатывается слотом в этом же плагине.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
igor_bogomolov
  опции профиля:
сообщение 22.9.2010, 2:25
Сообщение #14


Профессионал
*****

Группа: Сомодератор
Сообщений: 1215
Регистрация: 22.3.2009
Из: Саратов
Пользователь №: 630

Спасибо сказали: 235 раз(а)




Репутация:   29  


Видимо в файле проекта плагина отсутствуют следущие файлы
HEADERS += ../dictionary.h \
           ../dictionaries.h
SOURCES += ../dictionary.cpp \
           ../dictionaries.cpp
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
mva
  опции профиля:
сообщение 22.9.2010, 9:50
Сообщение #15


Участник
**

Группа: Участник
Сообщений: 104
Регистрация: 15.3.2009
Из: Киров
Пользователь №: 615

Спасибо сказали: 3 раз(а)




Репутация:   0  


Все, проблему решил простейшим образом.

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 страниц V   1 2 >
Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0


RSS Рейтинг@Mail.ru Текстовая версия Сейчас: 2.6.2025, 5:24