This forum has been archived. All content is frozen. Please use KDE Discuss instead.

Virtual functions causing link errors

Tags: None
(comma "," separated)
patrikgwet
Registered Member
Posts
5
Karma
0
I am struggling with an issue while I am using external .h files in my project.
I am using Qt5 with MSVC2012. In my main file, I am including a header file from a KDE application. I put some INCLUDEPATH in the .pro file to link correctly.
The piece of code I am in trouble with is the following:
Code: Select all
main.cpp
...
#include <Doc.h>

int main(int argc, char *argv[])
...

The Doc.h belongs to the KDE application source code. Including that file includes many other files in several directories in the KDE application source code.
Currently, the KUndo2Stack.h and the KUndo2Stack.cpp files are the files I am struggling with since three days now.
When I run QMake and compile, I get a link 2001 errors due to unresolved externals with virtual functions in the KUndo2QStack class defined and implemented in those files. Here is an extract:
Code: Select all
#ifndef QT_NO_UNDOSTACK

class KUNDO2_EXPORT KUndo2QStack : public QObject
{
    Q_OBJECT
//    Q_DECLARE_PRIVATE(KUndo2QStack)
    Q_PROPERTY(bool active READ isActive WRITE setActive)
    Q_PROPERTY(int undoLimit READ undoLimit WRITE setUndoLimit)

public:
    explicit KUndo2QStack(QObject *parent = 0);
    virtual ~KUndo2QStack();
    void clear();

    void push(KUndo2Command *cmd);

    bool canUndo() const;
    bool canRedo() const;
    QString undoText() const;
    QString redoText() const;

    int count() const;
    int index() const;
    QString actionText(int idx) const;
    QString text(int idx) const;

#ifndef QT_NO_ACTION
    QAction *createUndoAction(QObject *parent) const;
    QAction *createRedoAction(QObject *parent) const;
#endif // QT_NO_ACTION

    bool isActive() const;
    bool isClean() const;
    int cleanIndex() const;

    void beginMacro(const QString &text);
    void endMacro();

    void setUndoLimit(int limit);
    int undoLimit() const;

    const KUndo2Command *command(int index) const;

public Q_SLOTS:
    void setClean();
    virtual void setIndex(int idx);
    virtual void undo();
    virtual void redo();
    void setActive(bool active = true);

Q_SIGNALS:
    void indexChanged(int idx);
    void cleanChanged(bool clean);
    void canUndoChanged(bool canUndo);
    void canRedoChanged(bool canRedo);
    void undoTextChanged(const QString &undoActionText);
    void redoTextChanged(const QString &redoActionText);

private:
    // from QUndoStackPrivate
    QList<KUndo2Command*> m_command_list;
    QList<KUndo2Command*> m_macro_stack;
    int m_index;
    int m_clean_index;
    KUndo2Group *m_group;
    int m_undo_limit;

    // also from QUndoStackPrivate
    void setIndex(int idx, bool clean);
    bool checkUndoLimit();

    Q_DISABLE_COPY(KUndo2QStack)
    friend class KUndo2Group;
};

class KUNDO2_EXPORT KUndo2Stack : public KUndo2QStack
{
public:
    explicit KUndo2Stack(QObject *parent = 0);

    // functions from KUndoStack
    QAction* createRedoAction(KActionCollection* actionCollection, const QString& actionName = QString());
    QAction* createUndoAction(KActionCollection* actionCollection, const QString& actionName = QString());
};

#endif // QT_NO_UNDOSTACK

Note that the unresolved links occur only for virtual functions. Those functions are implemented as it follows:
Code: Select all
KUndo2QStack::~KUndo2QStack()
{
#ifndef QT_NO_UNDOGROUP
    if (m_group != 0)
        m_group->removeStack(this);
#endif
    clear();
}

void KUndo2QStack::undo()
{
    if (m_index == 0)
        return;

    if (!m_macro_stack.isEmpty()) {
        qWarning("KUndo2QStack::undo(): cannot undo in the middle of a macro");
        return;
    }

    int idx = m_index - 1;
    m_command_list.at(idx)->undo();
    setIndex(idx, false);
}

void KUndo2QStack::redo()
{
    if (m_index == m_command_list.size())
        return;

    if (!m_macro_stack.isEmpty()) {
        qWarning("KUndo2QStack::redo(): cannot redo in the middle of a macro");
        return;
    }

    m_command_list.at(m_index)->redo();
    setIndex(m_index + 1, false);
}

void KUndo2QStack::setIndex(int idx)
{
    if (!m_macro_stack.isEmpty()) {
        qWarning("KUndo2QStack::setIndex(): cannot set index in the middle of a macro");
        return;
    }

    if (idx < 0)
        idx = 0;
    else if (idx > m_command_list.size())
        idx = m_command_list.size();

    int i = m_index;
    while (i < idx)
        m_command_list.at(i++)->redo();
    while (i > idx)
        m_command_list.at(--i)->undo();

    setIndex(idx, false);
}

I have turned this question upside down looking for answers on the web and the only time I got something was when I deleted the word virtual off all the related functions. It cancelled the errors but I got an unresolved link2019 error with the destructor of the class KUndo2Stack (see the code above). The destructor I am talking about is the default one, you won't see any definition or implementation of it.
The exact error messages are:
Code: Select all
main.obj:-1: error: LNK2001: unresolved external symbol "public: virtual struct QMetaObject const * __cdecl KUndo2QStack::metaObject(void)const " (?metaObject@KUndo2QStack@@UEBAPEBUQMetaObject@@XZ)

main.obj:-1: error: LNK2001: unresolved external symbol "public: virtual void * __cdecl KUndo2QStack::qt_metacast(char const *)" (?qt_metacast@KUndo2QStack@@UEAAPEAXPEBD@Z)

main.obj:-1: error: LNK2001: unresolved external symbol "public: virtual int __cdecl KUndo2QStack::qt_metacall(enum QMetaObject::Call,int,void * *)" (?qt_metacall@KUndo2QStack@@UEAAHW4Call@QMetaObject@@HPEAPEAX@Z)

main.obj:-1: error: LNK2001: unresolved external symbol "public: virtual void __cdecl KUndo2QStack::setIndex(int)" (?setIndex@KUndo2QStack@@UEAAXH@Z)

main.obj:-1: error: LNK2001: unresolved external symbol "public: virtual void __cdecl KUndo2QStack::undo(void)" (?undo@KUndo2QStack@@UEAAXXZ)

main.obj:-1: error: LNK2001: unresolved external symbol "public: virtual void __cdecl KUndo2QStack::redo(void)" (?redo@KUndo2QStack@@UEAAXXZ)

main.obj:-1: error: LNK2019: unresolved external symbol "__declspec(dllimport) public: virtual __cdecl KUndo2Stack::~KUndo2Stack(void)" (__imp_??1KUndo2Stack@@UEAA@XZ) referenced in function "public: virtual void * __cdecl KUndo2Stack::`scalar deleting destructor'(unsigned int)" (??_GKUndo2Stack@@UEAAPEAXI@Z)

debug\whitehall_0_2.exe:-1: error: LNK1120: 7 unresolved externals

I need some help to understand what is really going on and how to fix it.
Thanks!
User avatar
google01103
Manager
Posts
6668
Karma
25
moved to KDE Development -> Helping Hands


OpenSuse Leap 42.1 x64, Plasma 5.x

User avatar
bcooksley
Administrator
Posts
19765
Karma
87
OS
You might want to post this on kde-devel@kde.org or calligra-devel@kde.org, as someone there is more likely to have an answer to this problem.
I suspect the implementation of KUndo2QStack is not being compiled into your library/binary.


KDE Sysadmin
[img]content/bcooksley_sig.png[/img]
patrikgwet
Registered Member
Posts
5
Karma
0
Hi,

I have already sent, 2 days ago, an email to calligra-devel@kde.org but my message was held waiting for a moderator approval (saying because I am not a member, what I don't really understand).

In fact, I am using .h and .cpp source code files of Calligra directly. Not .h and .lib files instead. Is there a problem with that? Because the other headers I included before the <Doc.h> compiled without any issues.

Thanks!
User avatar
bcooksley
Administrator
Posts
19765
Karma
87
OS
As long as you include all the necessary headers, and compile the *.cpp files into your project then it should work. You might need to modify the headers though to remove the exports - it is probably them causing the issue here.

In regards to the mailing list - this is because you have not subscribed to it. It is fairly standard practice to not let non-subscribers post due to spam.


KDE Sysadmin
[img]content/bcooksley_sig.png[/img]


Bookmarks



Who is online

Registered users: Bing [Bot], Google [Bot], Sogou [Bot]