Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. [SOLVED] How can a plugin that is dynamically loadded access main application objects and data?
QtWS25 Last Chance

[SOLVED] How can a plugin that is dynamically loadded access main application objects and data?

Scheduled Pinned Locked Moved General and Desktop
9 Posts 2 Posters 4.0k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • CKurduC Offline
    CKurduC Offline
    CKurdu
    wrote on last edited by
    #1

    Hi there

    I have an application that loads plugins in run time. I want to write a singleton pattern (and also later Factory pattern) and able to access from loadded plugins. I added header files for singleton class to plugin project. But when I try load plugins in main application, I get undefined symbol error and library can't be loadded. If I add implementation file(singleton.cpp) to plugin , loadded plugin use own singleton code not the main application. I prepared simple program to explain my problem. You can see the codes under.

    loadplugin main program Project File
    @
    QT += core

    QT -= gui

    TARGET = loadplugin
    CONFIG += console
    CONFIG -= app_bundle

    TEMPLATE = app

    SOURCES += main.cpp
    singleton.cpp

    HEADERS +=
    moduleinterface.h
    singleton.h
    @

    Main Application Singleton header
    @
    #ifndef SINGLETON_H
    #define SINGLETON_H
    class Singleton
    {
    static Singleton* sInstance;
    public:
    int property;
    Singleton(){property=1; Singleton::sInstance=0;}
    static Singleton& instance();
    ~Singleton();
    };

    #endif // SINGLETON_H

    @

    Main application singleton implementation file
    @
    #include "singleton.h"
    Singleton* Singleton::sInstance=0;

    Singleton::~Singleton()
    {

    }
    Singleton& Singleton::instance()
    {
    if(sInstance == 0)
    {
    sInstance = new Singleton();
    }
    return *(sInstance);
    }

    @

    Main application main.cpp file
    @
    #include <QCoreApplication>
    #include <QPluginLoader>
    #include <QDebug>
    #include <moduleinterface.h>
    #include <singleton.h>

    int main(int argc, char *argv[])
    {
    QCoreApplication a(argc, argv);

    QString moduleName = "testplugin";
    QString functionName = "command";
    Singleton::instance().property=3;
                const QString *libPath = new QString("/home/ckurdu/Documents/my_works/C++/qt/qtbin/qtcms_modules/"+moduleName+"/libqt"+moduleName+".so");
                QPluginLoader pluginLoader(*libPath);
                pluginLoader.load();
                if(pluginLoader.isLoaded())
                {
                QObject *plugin = pluginLoader.instance();
                    if(plugin)
                    {
                       ModuleInterface *moduleInt = qobject_cast<ModuleInterface *>(plugin);
                        if(moduleInt)
                        {
                           qDebug()<<"Module loaded"<<endl;
                           qDebug()<<moduleInt->execute(functionName);
                        }else{
                            qDebug()<<"Module not converted"<<endl;
                        }
                    }else{
                        qDebug()<<"Module couldn't resolve"<<endl;
                    }
    
                }else{
                    if(!QLibrary::isLibrary(*libPath))
                    {
                       qDebug()<<"File is not a type of library" <<endl;
                    }
                    qDebug()<<"Module not loaded"<<endl;
                    qDebug()<<pluginLoader.errorString()<<endl;
                }
    
    return a.exec&#40;&#41;;
    

    }

    @

    moduleinterface.h file for plugin creation.
    @
    #ifndef MODULEINTERFACE_H
    #define MODULEINTERFACE_H
    #include <QString>
    #include <QObject>
    class ModuleInterface
    {
    public:
    virtual ~ModuleInterface() {}
    virtual QString display(QString) = 0;
    virtual QString execute(QString) = 0;
    };

    QT_BEGIN_NAMESPACE

    #define ModuleInterface_iid "proje.tc.ModuleInterface"

    Q_DECLARE_INTERFACE(ModuleInterface, ModuleInterface_iid)

    QT_END_NAMESPACE

    #endif // MODULEINTERFACE_H

    @
    *
    Example plugin TestPlugin pro file.
    *
    @
    QT -= gui
    CONFIG += plugin

    TARGET = TestPlugin
    TEMPLATE = lib

    DEFINES += TESTPLUGIN_LIBRARY

    SOURCES += testplugin.cpp
    ../../loadplugintest/loadplugin/singleton.cpp

    HEADERS += testplugin.h
    testplugin_global.h
    ../../loadplugintest/loadplugin/moduleinterface.h
    ../../loadplugintest/loadplugin/singleton.h

    TARGET = $$qtLibraryTarget(qttestplugin)
    DESTDIR = /home/ckurdu/Documents/my_works/C++/qt/qtbin/qtcms_modules/testplugin/

    @

    plugin header file

    @
    #ifndef TESTPLUGIN_H
    #define TESTPLUGIN_H

    #include <QObject>
    #include <QtPlugin>
    #include <QString>
    #include "../../loadplugintest/loadplugin/moduleinterface.h"
    #include "../../loadplugintest/loadplugin/singleton.h"

    class TestPlugin : public QObject, ModuleInterface
    {
    Q_OBJECT
    Q_PLUGIN_METADATA(IID "proje.tc.ModuleInterface")
    Q_INTERFACES(ModuleInterface)
    int yesno=false;
    public:
    QString display(QString command);
    QString execute(QString command);
    TestPlugin(QObject *parent=NULL);
    };

    #endif // TESTPLUGIN_H

    @

    TestPlugin implementation
    @
    #include "testplugin.h"
    #include <QDebug>

    TestPlugin::TestPlugin(QObject* parent):QObject(parent)
    {
    }

    QString TestPlugin::display(QString command)
    {
    return command;
    }

    QString TestPlugin::execute(QString command)
    {
    qDebug()<<Singleton::instance().property<<endl;
    return command;
    }

    @

    If I add singleton.cpp file to my simple test plugin I get singleton::property value as 1. If singleton code of main program runs, singleton::property value must be 3.

    Sorry for my english.

    You reap what you sow it

    1 Reply Last reply
    0
    • C Offline
      C Offline
      ckakman
      wrote on last edited by
      #2

      Hi,

      You may consider defining an interface, e.g. AbstractSingleton, for the singleton and derive your Sİngleton class from this interface. You can add a setter function to your plugin interface that takes a pointer or reference to an AbstractSingleton, e.g
      @void setSingleton(AbstractSingleton *singleton)@

      1 Reply Last reply
      0
      • CKurduC Offline
        CKurduC Offline
        CKurdu
        wrote on last edited by
        #3

        Hi ckakman

        I tried with abstract class. I get error message when Main application loads the library. "undefined symbol". If I remove the line "this->singleton = singleton" in setSingleton method of plugin, Program loads plugin (library) successfully. But of course it is not a solution.

        You reap what you sow it

        1 Reply Last reply
        0
        • C Offline
          C Offline
          ckakman
          wrote on last edited by
          #4

          Hi again,

          Unfortunately I couldn't understand where and how the error occurs. Pure abstract classes completely decouple declarations and implementations therefore I wouldn't expect much issues. Moreover an error like "undefined symbol" smells like a missing header include somewhere.

          Could you please post here the following listings?

          • definition of the singleton interface class
          • new definition of the Singleton class
          • new definition of the plugin interface
          • implementation of the setSingleton() member of the concrete plugin class implementing the plugin interface
          • the code segment where you call the setSingleton() on the plugin
          1 Reply Last reply
          0
          • CKurduC Offline
            CKurduC Offline
            CKurdu
            wrote on last edited by
            #5

            bq. definition of the singleton interface class
            @
            #ifndef SINGLETONINTERFACE
            #define SINGLETONINTERFACE
            class SingletonInterface
            {
            public:
            static int property;
            virtual int getProperty() = 0;
            virtual void setProperty(int value) = 0;
            static SingletonInterface& instance();
            };
            #endif // SINGLETONINTERFACE
            @

            bq. new definition of the Singleton class

            @#ifndef SINGLETON_H
            #define SINGLETON_H
            #include "singletoninterface.h"
            class Singleton:public SingletonInterface
            {
            static Singleton* sInstance;
            public:
            int property;
            Singleton(){property=1; Singleton::sInstance=0;}
            static SingletonInterface& instance();
            int getProperty(){ return this->property;}
            void setProperty(int value){this->property = value;}
            ~Singleton();
            };

            #endif // SINGLETON_H@

            bq. new definition of the plugin interface

            @#ifndef MODULEINTERFACE_H
            #define MODULEINTERFACE_H
            #include <QString>
            #include <QObject>
            #include "/home/ckurdu/Documents/my_works/C++/qt/tests/loadplugintest/loadplugin/singletoninterface.h"
            class ModuleInterface
            {
            public:
            virtual ~ModuleInterface() {}
            virtual QString display(QString) = 0;
            virtual QString execute(QString) = 0;
            virtual void setSingleton(SingletonInterface *ptr) =0;
            };

            QT_BEGIN_NAMESPACE

            #define ModuleInterface_iid "proje.tc.ModuleInterface"

            Q_DECLARE_INTERFACE(ModuleInterface, ModuleInterface_iid)

            QT_END_NAMESPACE

            #endif // MODULEINTERFACE_H@

            bq. implementation of the setSingleton() member of the concrete plugin class implementing the plugin interface

            @#include "testplugin.h"
            #include <QDebug>

            TestPlugin::TestPlugin(QObject* parent):QObject(parent)
            {
            }

            QString TestPlugin::display(QString command)
            {
            return command;
            }

            QString TestPlugin::execute(QString command)
            {
            qDebug()<<this->psing->instance().property<<endl;
            return command;
            }

            void TestPlugin::setSingleton(SingletonInterface *ptr)
            {
            this->psing = ptr;
            }@

            @the code segment where you call the setSingleton() on the plugin@

            @#include <QCoreApplication>
            #include <QPluginLoader>
            #include <QDebug>
            #include <moduleinterface.h>
            #include <singleton.h>

            int main(int argc, char *argv[])
            {
            QCoreApplication a(argc, argv);

            QString moduleName = "testplugin";
            QString functionName = "command";
            Singleton &singleton = dynamic_cast<Singleton&>(Singleton::instance());
                      singleton.property=3;
            
                        const QString *libPath = new QString("/home/ckurdu/Documents/my_works/C++/qt/qtbin/qtcms_modules/"+moduleName+"/libqt"+moduleName+".so");
                        QPluginLoader pluginLoader(*libPath);
                        pluginLoader.load();
                        if(pluginLoader.isLoaded())
                        {
                        QObject *plugin = pluginLoader.instance();
                            if(plugin)
                            {
                               ModuleInterface *moduleInt = qobject_cast<ModuleInterface *>(plugin);
                                if(moduleInt)
                                {
                                   qDebug()<<"Module loaded"<<endl;
                                   moduleInt->setSingleton(&singleton);
                                   qDebug()<<moduleInt->execute(functionName);
                                }else{
                                    qDebug()<<"Module not converted"<<endl;
                                }
                            }else{
                                qDebug()<<"Module couldn't resolve"<<endl;
                            }
            
                        }else{
                            if(!QLibrary::isLibrary(*libPath))
                            {
                               qDebug()<<"File is not a type of library" <<endl;
                            }
                            qDebug()<<"Module not loaded"<<endl;
                            qDebug()<<pluginLoader.errorString()<<endl;
                        }
            
            return a.exec&#40;&#41;;
            

            }@

            setSingleton is called on Line 28 . But program never reachs this line.

            Error Message
            "Cannot load library /home..../libqttestplugin.so : undefined symbol: _Zn18SingletonInterface8propertyE"

            I also solved the problem with different way.
            I created a plugin that have singleton and factory methods. I load this plugin from main and testplugin. It works. I don't understand how but
            library have same data between main and loadded testplugin.

            You reap what you sow it

            1 Reply Last reply
            0
            • C Offline
              C Offline
              ckakman
              wrote on last edited by
              #6

              Hi,

              The point of using an interface is that you don't need to link to a concrete implementation. You should not add a non-virtual method to an interface. Also you shouldn't have a, static or not, a data member in an interface.

              You are calling the static instance() member on the SingletonInterface pointer you've passed to the plugin. This is the problem. You shouldn't do that. Just call the non-static virtual members via the pointer.

              To make it clearer, look at this line of code in the TestPlugin
              @qDebug()<<this->psing->instance().property<<endl;@

              Here you are trying to access a concrete member. Of course the runtime will complain because it needs to read the "property" directly. You should have used the virtual getProperty() accessor:
              @qDebug()<<this->psing->getProperty()<<endl;@

              Put the static instance() member and the static property data member into Singleton. This way, you won't need to dynamic_cast and your plugin won't need a concrete SingletonInterface implementation.

              1 Reply Last reply
              0
              • CKurduC Offline
                CKurduC Offline
                CKurdu
                wrote on last edited by
                #7

                It worked perfectly. Thank you. Which method do you suggest?

                1 . Making a library for factory methods and load this librarry into main application and for each plugins.

                1. Your solution.

                You reap what you sow it

                1 Reply Last reply
                0
                • C Offline
                  C Offline
                  ckakman
                  wrote on last edited by
                  #8

                  [quote author="CKurdu" date="1420317414"]It worked perfectly. Thank you. Which method do you suggest?

                  1 . Making a library for factory methods and load this librarry into main application and for each plugins.

                  1. Your solution.

                  [/quote]

                  I would suggest my solution. Not because it is my solution :), but because you'd need to take care of one library less.

                  Kolay gelsin.

                  1 Reply Last reply
                  0
                  • CKurduC Offline
                    CKurduC Offline
                    CKurdu
                    wrote on last edited by
                    #9

                    Sağolasın :)

                    You reap what you sow it

                    1 Reply Last reply
                    0

                    • Login

                    • Login or register to search.
                    • First post
                      Last post
                    0
                    • Categories
                    • Recent
                    • Tags
                    • Popular
                    • Users
                    • Groups
                    • Search
                    • Get Qt Extensions
                    • Unsolved