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. pluginLoader.instance() returns nullptr if one class is present in qt_add_plugin()

pluginLoader.instance() returns nullptr if one class is present in qt_add_plugin()

Scheduled Pinned Locked Moved Solved General and Desktop
plugin
6 Posts 4 Posters 456 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.
  • O Offline
    O Offline
    odelaune
    wrote on 5 Jul 2023, 15:35 last edited by odelaune 7 May 2023, 15:39
    #1

    Hello,
    I discover the Qt plugin world and I am facing a weird issue.

    Here is the CMakeLists.txt of my plugin

    qt_add_plugin(MyPlugin
        SHARED
        CLASS_NAME WidgetPlugin
        MyPlugin.cpp MyPlugin.h
        classA.cpp classA.h
        classB.cpp classB.h
        classC.cpp classC.h
        ...
        classG.cpp classG.h
        classH.cpp classH.h
    )
    
    set_target_properties(MyPlugin PROPERTIES
        LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/plugins"
    )
    
    target_include_directories(MyPlugin PRIVATE
        ../dirWhereInterfaceIsDefined
    )
    
    target_link_libraries(MyPlugin PRIVATE
        Qt6::Core
        Qt6::Gui
        Qt6::Widgets
        Qt6::Network
        Qt6::Positioning
        Qt6::Svg
        Qt6::SvgWidgets
    )
    
    install(TARGETS MyPlugin
        RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}/plugins"
        LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/plugins"
    )
    

    Not here is the snippet I use to load the plugin

    bool MyApplication::loadPlugin()
    {
        QDir pluginsDir(QCoreApplication::applicationDirPath());
        pluginsDir.cdUp();
        QString dirName("plugins");
        bool ok = pluginsDir.cd(dirName);
        if(!ok)
            qDebug() << "The directory \"" << dirName << "\" does not exist!";
        const QStringList entries = pluginsDir.entryList(QDir::Files);
        for (const QString &fileName : entries) {
            QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName));
            qDebug() << "Loading" << fileName << "...";
            QObject *plugin = pluginLoader.instance();
            if (plugin) {
                populateTabs(plugin);
                return true;
            }
            qDebug() << "pluginLoader.instance() failed";
            pluginLoader.unload();
        }
    
        return false;
    }
    

    The class classH depends on all the other classes and is the main class of the plugins. The problem is that with CMakeLists.txt like this, the plugin QObject is always a nullptr.

    What I have done so far is to comment out all the lines in qt_add_plugin() one by one to see which class is broken. What I discovered is that the class classG is broken. If I comment the classG line and remove the classG dependency in classH, the plugin loader returns a non-zero object, which is perfect.

    The class classG depends on classA and classB, so it is not clear to me what could cause the plugin to be a nullptr when classG is present.

    This is a bit tricky for me because this classG works fine when I am not using it in a plugin system, i.e. it is used within a single application.

    Do you have any idea of what could cause this behaviour?

    S A 2 Replies Last reply 5 Jul 2023, 18:46
    0
    • O odelaune
      5 Jul 2023, 15:35

      Hello,
      I discover the Qt plugin world and I am facing a weird issue.

      Here is the CMakeLists.txt of my plugin

      qt_add_plugin(MyPlugin
          SHARED
          CLASS_NAME WidgetPlugin
          MyPlugin.cpp MyPlugin.h
          classA.cpp classA.h
          classB.cpp classB.h
          classC.cpp classC.h
          ...
          classG.cpp classG.h
          classH.cpp classH.h
      )
      
      set_target_properties(MyPlugin PROPERTIES
          LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/plugins"
      )
      
      target_include_directories(MyPlugin PRIVATE
          ../dirWhereInterfaceIsDefined
      )
      
      target_link_libraries(MyPlugin PRIVATE
          Qt6::Core
          Qt6::Gui
          Qt6::Widgets
          Qt6::Network
          Qt6::Positioning
          Qt6::Svg
          Qt6::SvgWidgets
      )
      
      install(TARGETS MyPlugin
          RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}/plugins"
          LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/plugins"
      )
      

      Not here is the snippet I use to load the plugin

      bool MyApplication::loadPlugin()
      {
          QDir pluginsDir(QCoreApplication::applicationDirPath());
          pluginsDir.cdUp();
          QString dirName("plugins");
          bool ok = pluginsDir.cd(dirName);
          if(!ok)
              qDebug() << "The directory \"" << dirName << "\" does not exist!";
          const QStringList entries = pluginsDir.entryList(QDir::Files);
          for (const QString &fileName : entries) {
              QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName));
              qDebug() << "Loading" << fileName << "...";
              QObject *plugin = pluginLoader.instance();
              if (plugin) {
                  populateTabs(plugin);
                  return true;
              }
              qDebug() << "pluginLoader.instance() failed";
              pluginLoader.unload();
          }
      
          return false;
      }
      

      The class classH depends on all the other classes and is the main class of the plugins. The problem is that with CMakeLists.txt like this, the plugin QObject is always a nullptr.

      What I have done so far is to comment out all the lines in qt_add_plugin() one by one to see which class is broken. What I discovered is that the class classG is broken. If I comment the classG line and remove the classG dependency in classH, the plugin loader returns a non-zero object, which is perfect.

      The class classG depends on classA and classB, so it is not clear to me what could cause the plugin to be a nullptr when classG is present.

      This is a bit tricky for me because this classG works fine when I am not using it in a plugin system, i.e. it is used within a single application.

      Do you have any idea of what could cause this behaviour?

      A Offline
      A Offline
      Axel Spoerl
      Moderators
      wrote on 5 Jul 2023, 21:01 last edited by
      #3

      @odelaune
      Changing the debug statement to

      qDebug() << __FUNCTION__ << fileName << pluginLoader.errorString();
      

      maybe sheds more light on the matter.

      Is plugin actually built? That can be ensured by adding
      find_package(MyPlugin) to the toplevel CMakeLists.txt.
      I assume that the libraries in the target_link_librariesstatement have all been found before. It wouldn't hurt adding a find_packagein the plugin's CMakeLists.txt as well.

      On a side note: The code for loading will iterate over all files found in the application directory. So the error output will be quite noisy. Might be worth considering a subdirectory for the plugin, or filtering the names for an expected plugin name convention.

      On a side-side note: Returning true after having found the first plugin will never allow having more than one plugin. I guess that's intentional.

      Software Engineer
      The Qt Company, Oslo

      1 Reply Last reply
      2
      • O odelaune
        5 Jul 2023, 15:35

        Hello,
        I discover the Qt plugin world and I am facing a weird issue.

        Here is the CMakeLists.txt of my plugin

        qt_add_plugin(MyPlugin
            SHARED
            CLASS_NAME WidgetPlugin
            MyPlugin.cpp MyPlugin.h
            classA.cpp classA.h
            classB.cpp classB.h
            classC.cpp classC.h
            ...
            classG.cpp classG.h
            classH.cpp classH.h
        )
        
        set_target_properties(MyPlugin PROPERTIES
            LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/plugins"
        )
        
        target_include_directories(MyPlugin PRIVATE
            ../dirWhereInterfaceIsDefined
        )
        
        target_link_libraries(MyPlugin PRIVATE
            Qt6::Core
            Qt6::Gui
            Qt6::Widgets
            Qt6::Network
            Qt6::Positioning
            Qt6::Svg
            Qt6::SvgWidgets
        )
        
        install(TARGETS MyPlugin
            RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}/plugins"
            LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/plugins"
        )
        

        Not here is the snippet I use to load the plugin

        bool MyApplication::loadPlugin()
        {
            QDir pluginsDir(QCoreApplication::applicationDirPath());
            pluginsDir.cdUp();
            QString dirName("plugins");
            bool ok = pluginsDir.cd(dirName);
            if(!ok)
                qDebug() << "The directory \"" << dirName << "\" does not exist!";
            const QStringList entries = pluginsDir.entryList(QDir::Files);
            for (const QString &fileName : entries) {
                QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName));
                qDebug() << "Loading" << fileName << "...";
                QObject *plugin = pluginLoader.instance();
                if (plugin) {
                    populateTabs(plugin);
                    return true;
                }
                qDebug() << "pluginLoader.instance() failed";
                pluginLoader.unload();
            }
        
            return false;
        }
        

        The class classH depends on all the other classes and is the main class of the plugins. The problem is that with CMakeLists.txt like this, the plugin QObject is always a nullptr.

        What I have done so far is to comment out all the lines in qt_add_plugin() one by one to see which class is broken. What I discovered is that the class classG is broken. If I comment the classG line and remove the classG dependency in classH, the plugin loader returns a non-zero object, which is perfect.

        The class classG depends on classA and classB, so it is not clear to me what could cause the plugin to be a nullptr when classG is present.

        This is a bit tricky for me because this classG works fine when I am not using it in a plugin system, i.e. it is used within a single application.

        Do you have any idea of what could cause this behaviour?

        S Offline
        S Offline
        SGaist
        Lifetime Qt Champion
        wrote on 5 Jul 2023, 18:46 last edited by
        #2

        Hi,

        Does that class use symbols from some external library ?

        Interested in AI ? www.idiap.ch
        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

        1 Reply Last reply
        1
        • O odelaune
          5 Jul 2023, 15:35

          Hello,
          I discover the Qt plugin world and I am facing a weird issue.

          Here is the CMakeLists.txt of my plugin

          qt_add_plugin(MyPlugin
              SHARED
              CLASS_NAME WidgetPlugin
              MyPlugin.cpp MyPlugin.h
              classA.cpp classA.h
              classB.cpp classB.h
              classC.cpp classC.h
              ...
              classG.cpp classG.h
              classH.cpp classH.h
          )
          
          set_target_properties(MyPlugin PROPERTIES
              LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/plugins"
          )
          
          target_include_directories(MyPlugin PRIVATE
              ../dirWhereInterfaceIsDefined
          )
          
          target_link_libraries(MyPlugin PRIVATE
              Qt6::Core
              Qt6::Gui
              Qt6::Widgets
              Qt6::Network
              Qt6::Positioning
              Qt6::Svg
              Qt6::SvgWidgets
          )
          
          install(TARGETS MyPlugin
              RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}/plugins"
              LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/plugins"
          )
          

          Not here is the snippet I use to load the plugin

          bool MyApplication::loadPlugin()
          {
              QDir pluginsDir(QCoreApplication::applicationDirPath());
              pluginsDir.cdUp();
              QString dirName("plugins");
              bool ok = pluginsDir.cd(dirName);
              if(!ok)
                  qDebug() << "The directory \"" << dirName << "\" does not exist!";
              const QStringList entries = pluginsDir.entryList(QDir::Files);
              for (const QString &fileName : entries) {
                  QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName));
                  qDebug() << "Loading" << fileName << "...";
                  QObject *plugin = pluginLoader.instance();
                  if (plugin) {
                      populateTabs(plugin);
                      return true;
                  }
                  qDebug() << "pluginLoader.instance() failed";
                  pluginLoader.unload();
              }
          
              return false;
          }
          

          The class classH depends on all the other classes and is the main class of the plugins. The problem is that with CMakeLists.txt like this, the plugin QObject is always a nullptr.

          What I have done so far is to comment out all the lines in qt_add_plugin() one by one to see which class is broken. What I discovered is that the class classG is broken. If I comment the classG line and remove the classG dependency in classH, the plugin loader returns a non-zero object, which is perfect.

          The class classG depends on classA and classB, so it is not clear to me what could cause the plugin to be a nullptr when classG is present.

          This is a bit tricky for me because this classG works fine when I am not using it in a plugin system, i.e. it is used within a single application.

          Do you have any idea of what could cause this behaviour?

          A Offline
          A Offline
          Axel Spoerl
          Moderators
          wrote on 5 Jul 2023, 21:01 last edited by
          #3

          @odelaune
          Changing the debug statement to

          qDebug() << __FUNCTION__ << fileName << pluginLoader.errorString();
          

          maybe sheds more light on the matter.

          Is plugin actually built? That can be ensured by adding
          find_package(MyPlugin) to the toplevel CMakeLists.txt.
          I assume that the libraries in the target_link_librariesstatement have all been found before. It wouldn't hurt adding a find_packagein the plugin's CMakeLists.txt as well.

          On a side note: The code for loading will iterate over all files found in the application directory. So the error output will be quite noisy. Might be worth considering a subdirectory for the plugin, or filtering the names for an expected plugin name convention.

          On a side-side note: Returning true after having found the first plugin will never allow having more than one plugin. I guess that's intentional.

          Software Engineer
          The Qt Company, Oslo

          1 Reply Last reply
          2
          • R Offline
            R Offline
            ryder_z
            wrote on 6 Jul 2023, 06:41 last edited by
            #4

            Generally, it is the code problem inside the plug-in, such as the parameter of the function does not match; For details, print the errstring of the qpluginloader to know the specific problem.

            O 1 Reply Last reply 6 Jul 2023, 07:14
            0
            • R ryder_z
              6 Jul 2023, 06:41

              Generally, it is the code problem inside the plug-in, such as the parameter of the function does not match; For details, print the errstring of the qpluginloader to know the specific problem.

              O Offline
              O Offline
              odelaune
              wrote on 6 Jul 2023, 07:14 last edited by
              #5

              Thank you very much. Using pluginLoader.errorString() helped me to find the problem (a global variable was missing in classG, adding it makes the plugin load correctly).

              I am discovering the plugin world so I was not aware about errorString(). Thanks for all your tips.

              A 1 Reply Last reply 6 Jul 2023, 07:55
              1
              • O odelaune has marked this topic as solved on 6 Jul 2023, 07:14
              • O odelaune
                6 Jul 2023, 07:14

                Thank you very much. Using pluginLoader.errorString() helped me to find the problem (a global variable was missing in classG, adding it makes the plugin load correctly).

                I am discovering the plugin world so I was not aware about errorString(). Thanks for all your tips.

                A Offline
                A Offline
                Axel Spoerl
                Moderators
                wrote on 6 Jul 2023, 07:55 last edited by
                #6

                @odelaune Thanks, pls mark the thread solved!

                Software Engineer
                The Qt Company, Oslo

                1 Reply Last reply
                0

                1/6

                5 Jul 2023, 15:35

                • Login

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