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

Linker error 2001: mainwindow.obj:-1: error: LNK2001: unresolved external symbol "public: static struct QMetaObject



  • Hi,

    I guess this has been asked about a thousand times, but for the love of god, I don't understand why I am getting this linker error. So please bear with me:
    I have a project where I create a library which contains 2 ActiveX controls that are going to be used in an industrial HMI. In order to test the controls I have a test application (which is part of the same Qt project) where I dynamically link against the ActiveX control library - I do not embedd an ActiveX client in the test application though.
    For creating the library I think I followed the Qt documentation guide lines.

    Project file:

    TEMPLATE =  subdirs
    
    SUBDIRS =   ActiveX_Control TestApp \
    

    The library project file:

    win32 {
     build_pass:CONFIG(debug, debug|release) {
        TARGET = StaubliControlsd
     } else {
        TARGET = StaubliControls
      }
    }
    
    DESTDIR=../bin
    TEMPLATE = lib
    SOURCES +=  robotComm/cs8robotcomm.cpp \
        main.cpp \
        TrayView/cs8trayview.cpp \
        TrayView/cs8trayspot.cpp \
        TrayView/cs8graphicsitemtray.cpp \
        TrayView/cs8graphicsitempartlist.cpp \
        TrayView/cs8graphicsitempart.cpp \
        CleaningTrajectoryView/parser.cpp \
        CleaningTrajectoryView/cs8cleaningtrajectorywidget.cpp \
        CleaningTrajectoryView/cs8cleaningview.cpp \
        CleaningTrajectoryView/codeeditor.cpp \
        CleaningTrajectoryView/highlighter.cpp \
        TrayView/dialogpartmodifier.cpp
    
    HEADERS +=   robotComm/cs8robotcomm.h \
        TrayView/cs8trayview.h \
        TrayView/cs8trayspot.h \
        TrayView/cs8graphicsitemtray.h \
        TrayView/cs8graphicsitempartlist.h \
        TrayView/cs8graphicsitempart.h \
        CleaningTrajectoryView/parser.h \
        CleaningTrajectoryView/cs8cleaningtrajectorywidget.h \
        CleaningTrajectoryView/cs8cleaningview.h \
        CleaningTrajectoryView/codeeditor.h \
        CleaningTrajectoryView/highlighter.h \
        TrayView/dialogpartmodifier.h
    
    
    
    CONFIG += qt warn_all
    CONFIG += dll
    
    DEFINES += CLEANINGTRAJECTORYVIEW_EXPORTS
    DEFINES += PALETTEVIEW_EXPORTS
    DEFINES += USE_SQLITE
    
    VERSION = 2.0
    
    QT += network widgets
    QT += axserver sql
    
    RC_FILE	 = qaxserver.rc
    DEF_FILE = qaxserver.def
    
    FORMS += \
        CleaningTrajectoryView/cs8cleaningtrajectorywidget.ui \
        CleaningTrajectoryView/cs8cleaningview.ui \
        TrayView/dialogpartmodifier.ui
    
    QTPLUGIN += qsqlite
    
    
    RESOURCES += \
        ../res/ActiveX_Control.qrc
    

    And the test application project file:

    
    TARGET = ActiveX_Test
    TEMPLATE = app
    DESTDIR=../bin
    
    
    SOURCES += main.cpp \
               mainwindow.cpp
    
    HEADERS += mainwindow.h
    
    FORMS += mainwindow.ui
    
    QT += network widgets
    
    CONFIG += qt warn_all
    
    
    
    win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../bin/ -lStaubliControls2
    else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../bin/ -lStaubliControlsd2
    
    INCLUDEPATH += $$PWD/../ActiveX_Control/CleaningTrajectoryView
    DEPENDPATH += $$PWD/../ActiveX_Control/CleaningTrajectoryView
    
    INCLUDEPATH += $$PWD/../ActiveX_Control/TrayView
    DEPENDPATH += $$PWD/../ActiveX_Control/TrayView
    

    The h file of one of the controls looks like this:

    #ifndef CS8PALETTEVIEW_H
    #define CS8PALETTEVIEW_H
    
    #include "../robotComm/cs8robotcomm.h"
    #include "cs8graphicsitemtray.h"
    #include "dialogpartmodifier.h"
    
    #include <QGraphicsView>
    
    // The following ifdef block is the standard way of creating macros which make exporting
    // from a DLL simpler. All files within this DLL are compiled with the PALETTEVIEW_EXPORTS
    // symbol defined on the command line. this symbol should not be defined on any project
    // that uses this DLL. This way any other project whose source files include this file see
    // PALETTEVIEW_API functions as being imported from a DLL, whereas this DLL sees symbols
    // defined with this macro as being exported.
    #ifdef PALETTEVIEW_EXPORTS
    #include <QAxBindable>
    #define PALETTEVIEW_API Q_DECL_EXPORT
    #else
    #define PALETTEVIEW_API Q_DECL_IMPORT
    #endif
    
    
    class cs8TrayView : public QWidget
    #ifdef PALETTEVIEW_EXPORTS
        ,
                        public QAxBindable
    #endif
    {
      Q_OBJECT
      Q_CLASSINFO("ClassID", "{14941F51-AD85-46CE-ABAF-472F5198353A}")
      Q_CLASSINFO("InterfaceID", "{E12482E3-C3C8-443E-8001-AFEBE58D5A1A}")
      Q_CLASSINFO("EventsID", "{C0B3A05B-7BD9-4C6B-8C3A-4833B8D30913}")
      Q_CLASSINFO("Insertable", "yes")
      Q_CLASSINFO("ToSuperClass", "cs8TrayView")
    
      
      Q_PROPERTY(double partWidth READ partWidth WRITE setPartWidth)
    
      Q_PROPERTY(double partDepth READ partDepth WRITE setPartDepth)
      [..]
    public:
     
      PALETTEVIEW_API cs8TrayView(QWidget *parent = nullptr);
      PALETTEVIEW_API ~cs8TrayView() override;
    
      PALETTEVIEW_API QMap<uint, cs8PartCoordinates> partCoordinates() const;
      PALETTEVIEW_API cs8TrayTypes paletteTypes() const;
      PALETTEVIEW_API double partCount(bool withDisabledParts = true);
      PALETTEVIEW_API QString deactivatedPositions() const;
    
      
      PALETTEVIEW_API void getDeactivatedPositions(QString &value);
    
      PALETTEVIEW_API bool updateTrayProperty() const;
    
      
      PALETTEVIEW_API void setHost(QString host);
      PALETTEVIEW_API QString host() const;
      PALETTEVIEW_API QString errorString() const;
    
     
      PALETTEVIEW_API void getErrorString(QString &value);
    
      PALETTEVIEW_API void mirrorView(bool mirror);
      PALETTEVIEW_API int currentSelectedPart() const;
      PALETTEVIEW_API void setCurrentSelectedPart(int currentSelectedPart);
      PALETTEVIEW_API int modifyCurrentSelectedPart(int delta);
      PALETTEVIEW_API void enableCurrentPart(bool enable);
      PALETTEVIEW_API bool currentPartEnabled() const;
    
      PALETTEVIEW_API double getMaxTotalWeight() const;
    
      PALETTEVIEW_API double getActualWeight() const;
    
    [..]
    

    I was able to compile the project without problems and test the library in my test application. Since a while back now the linker complains about unresolved external symbols when I tryto compile the test application:

    link /NOLOGO /DYNAMICBASE /NXCOMPAT /DEBUG /SUBSYSTEM:WINDOWS "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" /MANIFEST:embed /OUT:..\bin\ActiveX_Test.exe @C:\Users\vdg.HSH\AppData\Local\Temp\ActiveX_Test.exe.7868.156.jom
    mainwindow.obj : error LNK2001: unresolved external symbol "public: static struct QMetaObject const cs8TrayView::staticMetaObject" (?staticMetaObject@cs8TrayView@@2UQMetaObject@@B)
    ..\bin\ActiveX_Test.exe : fatal error LNK1120: 1 unresolved externals
    

    I seem to be having a brain malfunction now, since I can't figure out why the linker process fails now. I tried to clean and rebuild the project multiple times, to no avail.

    Any help would be very much appreciated.

    Volker


  • Qt Champions 2017

    Export the whole class, not only single members:

    class PALETTEVIEW_API cs8TrayView : public QWidget // ...
    

    this would imply also to remove PALETTEVIEW_API that are in front of the functions, as they're redundant. The Q_OBJECT macro generates some metadata (and few methods) that need to be accessible to the user binary, and since you haven't exported the whole class that data is private, thus you get the linker error.



  • Hi @kshegunov,

    indeed that did the trick. Then I just wonder why I could compile the project before where I exported only individual items of the class....


  • Qt Champions 2017

    @volkerd said in Linker error 2001: mainwindow.obj:-1: error: LNK2001: unresolved external symbol "public: static struct QMetaObject:

    Then I just wonder why I could compile the project before where I exported only individual items of the class

    Probably you didn't reference anything related to the QMetaObject member (e.g. qobject_cast) in the user code, so it never was an issue until then.



  • @kshegunov said in Linker error 2001: mainwindow.obj:-1: error: LNK2001: unresolved external symbol "public: static struct QMetaObject:

    @volkerd said in Linker error 2001: mainwindow.obj:-1: error: LNK2001: unresolved external symbol "public: static struct QMetaObject:

    Then I just wonder why I could compile the project before where I exported only individual items of the class

    Probably you didn't reference anything related to the QMetaObject member (e.g. qobject_cast) in the user code, so it never was an issue until then.

    Yep, that might explain it.


Log in to reply