Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Using Qt lib macros with static libs and apps



  • Hi, I've run into a situation that I'm not quite sure how to resolve. Here is the scenario:

    I have a static lib, let's call it glib.
    In glib I have 2 files called app.hpp and app.cpp.
    Inside of these files are subclasses of QApplication and QCoreApplication.
    I want to be able to use the subclasses of QCoreApplication inside of apps that do not have the Qt GUI framework ( QT -= gui), i.e command line apps.

    I now have a cmd line app called capp.
    Inside of capp, I want to use my custom subclasses of QCoreApplication.
    So I #include <app.hpp> and add the necessary lib to my cmd line app's project file.

    However, because this is a cmd line app ( QT -= gui), it of course complains that <QApplication> does not exist.
    So in an attempt to resolve this, I wrapped all of the "GUI" related code in app.hpp and app.cpp with a QT_GUI_LIB macro ifdef.

    Keep in mind that app.hpp and app.cpp is compiled as a static lib. That means that the generated static lib still contains all the symbols for the subclasses of both QApplication and QCoreApplication, since the lib itself is compiled with QT += gui widgets

    I can of course split up the GUI and non-gui code into 2 separate files, but wanted to know if my current approach should work and if I'm just doing something incorrectly.

    Thanks for any help


  • Lifetime Qt Champion

    Hi,

    Can you show your header content ?

    Note that it's indeed better to have these two classes in separate headers. That will makes things way clearer when using your library.



  • So the static lib builds perfectly fine. I've also tried using the QT_GUI_LIB macro instead but same result. I get these compile errors when trying to use the static lib in a non-gui app. Perhaps the easiest solution is to just spit up the GUI and non-GUI code into separate files.

    This is what my app's project file looks like:

    
    LIBS_DEPTH = ../..
    LIB_DEPENDENCIES = \
       momalib \
       gedilib \
       gselib \
       tools \
       gse_streams
    include(../../custom.pri)
    
    # Input
    HEADERS += mainclass.hpp
    SOURCES += main.cpp mainclass.cpp
    
    CONFIG += qt console
    CONFIG -= app_bundle
    QT -= gui
    QT += network
    

    Generated compile error:

    Undefined symbols for architecture x86_64:
      "QApplication::qt_metacall(QMetaObject::Call, int, void**)", referenced from:
          vtable for ExceptionSafeApplication in libgselib.a(apputil.o)
          NasaApp::qt_metacall(QMetaObject::Call, int, void**) in libgselib.a(moc_apputil.o)
      "QApplication::qt_metacast(char const*)", referenced from:
          vtable for ExceptionSafeApplication in libgselib.a(apputil.o)
          NasaApp::qt_metacast(char const*) in libgselib.a(moc_apputil.o)
      "QApplication::compressEvent(QEvent*, QObject*, QPostEventList*)", referenced from:
          vtable for ExceptionSafeApplication in libgselib.a(apputil.o)
          vtable for NasaApp in libgselib.a(moc_apputil.o)
      "QApplication::staticMetaObject", referenced from:
          NasaApp::staticMetaObject in libgselib.a(moc_apputil.o)
      "QApplication::event(QEvent*)", referenced from:
          vtable for ExceptionSafeApplication in libgselib.a(apputil.o)
          vtable for NasaApp in libgselib.a(moc_apputil.o)
      "QApplication::notify(QObject*, QEvent*)", referenced from:
          ExceptionSafeApplication::notify(QObject*, QEvent*) in libgselib.a(apputil.o)
          vtable for NasaApp in libgselib.a(moc_apputil.o)
      "QApplication::QApplication(int&, char**, int)", referenced from:
          NasaApp::NasaApp(int&, char**, int, int, int, QString) in libgselib.a(apputil.o)
          ExceptionSafeApplication::ExceptionSafeApplication(int&, char**) in libgselib.a(apputil.o)
      "QApplication::~QApplication()", referenced from:
          NasaApp::NasaApp(int&, char**, int, int, int, QString) in libgselib.a(apputil.o)
          ExceptionSafeApplication::~ExceptionSafeApplication() in libgselib.a(apputil.o)
          NasaApp::~NasaApp() in libgselib.a(moc_apputil.o)
      "QApplication::metaObject() const", referenced from:
          vtable for ExceptionSafeApplication in libgselib.a(apputil.o)
      "typeinfo for QApplication", referenced from:
          typeinfo for ExceptionSafeApplication in libgselib.a(apputil.o)
          typeinfo for NasaApp in libgselib.a(moc_apputil.o)
    ld: symbol(s) not found for architecture x86_64
    clang: error: linker command failed with exit code 1 (use -v to see invocation)
    

    And the static lib's header file:

    /**
     * @file
     */
    
    #ifndef APPUTIL_HPP
    #define APPUTIL_HPP
    
    #include <logger/logger.hpp>
    #include <util/pluginmanager.hpp>
    
    #ifdef QT_WIDGETS_LIB
    #include <QApplication>
    #else
    #include <QCoreApplication>
    #endif
    #include <QPointer>
    
    
    bool disableAppNap(const QString &appDomainName);
    
    
    /*******************************************************************************
     * Almost all projects should use one of the below app subclasses. They enforce
     * routine initialization and conventions.
     ******************************************************************************/
    
    /**
     * Use for non-GUI apps.
     */
    class NasaCoreApp : public QCoreApplication
    {
       Q_OBJECT
    public:
       explicit NasaCoreApp(int & ac,
                            char **av,
                            int majorVer,
                            int minorVer,
                            int patchVer,
                            QString svnRevision);
    
       void initializeLogger(bool stdErrEnabled = false);
    
    private:
       Q_DISABLE_COPY(NasaCoreApp)
    };
    
    
    #ifdef QT_WIDGETS_LIB
    
    
    
    /**
     * Use for GUI apps.
     */
    class NasaApp : public QApplication
    {
       Q_OBJECT
    public:
       explicit NasaApp(int & ac,
                        char **av,
                        int majorVer,
                        int minorVer,
                        int patchVer,
                        QString svnRevision);
    
       void initializeLogger(bool stdErrEnabled = false);
       void initializeConfig699(const QString & group = "");
    
       void loadPlugins(const QStringList & pluginPaths = QStringList());
       PluginManager *pluginManager() { return pluginManager_; }
    
    private:
       Q_DISABLE_COPY(NasaApp)
    
       QPointer<PluginManager> pluginManager_;
    };
    
    
    /**
     * Provides a QApplication that catches any exceptions that are thrown during
     * handling of any events. The intention is to prevent the application from
     * crashing due to an exception.
     */
    class ExceptionSafeApplication : public QApplication
    {
    public:
       explicit ExceptionSafeApplication(int & ac, char **av);
    
       virtual bool notify (QObject *r, QEvent *e );
    
    private:
       Q_DISABLE_COPY(ExceptionSafeApplication)
    };
    
    #endif // QT_WIDGETS_LIB
    
    #endif // APPUTIL_HPP
    

  • Qt Champions 2019

    Wouldn't it be easier to simply create two separate classes/libraries instead?



  • @Christian-Ehrlicher

    Yes and that's what I've already done. I was really more curious if my original approach should have worked, but apparently there's holes in my understanding of how header and lib files interact.


  • Qt Champions 2019

    You have to make sure QT_WIDGETS_LIB is (not) defined when using the header. So I assume QT_WIDGETS_LIB was defined when you wanted to use it in non-gui mode.



  • @Christian-Ehrlicher Well I've explicitly added "QT -= gui widgets" to my non-gui app's project file but it still complains about missing symbols. Is that not enough?


  • Qt Champions 2019

    @Christian-Ehrlicher said in Using Qt lib macros with static libs and apps:

    QT_WIDGETS_LIB

    I would check it with a short '#error QT_WIDGETS_LIB defined' within the #ifdef QT_WIDGETS_LIB branch while compiling to non-gui app just to be sure :)


Log in to reply