[Solved] Getting Started code won't build on VS 2010



  • Hello everyone,
    I got Qt installed fine, and I'm using Visual Studio 2010 Express as a compiler. The first two examples in the Getting Started documentation build fine, but the third (Subclassing a Widget example) gives me some errors:
    @
    1>main.obj : error LNK2001: unresolved external symbol "public: virtual struct QMetaObject const * __thiscall Notepad::metaObject(void)const " (?metaObject@Notepad@@UBEPBUQMetaObject@@XZ)
    1>main.obj : error LNK2001: unresolved external symbol "public: virtual void * __thiscall Notepad::qt_metacast(char const *)" (?qt_metacast@Notepad@@UAEPAXPBD@Z)
    1>main.obj : error LNK2001: unresolved external symbol "public: virtual int __thiscall Notepad::qt_metacall(enum QMetaObject::Call,int,void * *)" (?qt_metacall@Notepad@@UAEHW4Call@QMetaObject@@HPAPAX@Z)
    1>main.obj : error LNK2001: unresolved external symbol "public: static struct QMetaObject const Notepad::staticMetaObject" (?staticMetaObject@Notepad@@2UQMetaObject@@B)
    1>C:\Users\Matt\documents\visual studio 2010\Projects\Qt_test\Debug\Qt_test.exe : fatal error LNK1120: 4 unresolved externals
    @
    I've just been hitting the f7 key to build, I'm not sure how to use the command line. It's worked so far, but not now. The code is straight out of the tutorial. Am I doing something wrong?

    [edit: code tags added, koahnig]



  • Do you have the QT plugin installed?

    If you don´t , do it. Then, exclude all CPP and H files from the project, and include them again. It will add some compile options for your files.
    If you have any file with a Q_OBJECT word just after the class declaration, then it should to a MOC_ing proccess for those files while compiling (see the output). It if doesn´t , check it out.

    If it mocs files, then you have to search them (.moc) in the project files, hitting "update" button to show new files. Include them in the project and compile again. :-)



  • By QT plugin, you mean [url=http://doc.qt.digia.com/vs-add-in/index.html]this[/url] Visual Studio add-on? There's a note that it won't work with the free Express versions, which is what I have. Is there anything I could do without it, or should I switch IDE?



  • You do not need a plug-in. I use Visual Studio 2010 without plugins.

    Your errors look like you need the Meta Object Compiler (moc.exe) to run over your header files first: if your class declarations inherit from QObject and if you find the Q_OBJECT macro inside your class declaration, like here, ...

    @class YourClass: public QObject
    {
    Q_OBJECT
    public:
    //...and so on...
    }@

    ... the moc.exe must take this header file as input. It then produces a new source file which must get compiled: so you must call "moc YourClass.h -o YourClass.moc". It produces the file YourClass.moc which now must get compiled. This can easily be achieved by adding at the end of your .cpp with the following line:

    @
    //...
    //normal YourClass.cpp contents
    //...
    #include "YourClass.moc" //last line
    @

    [You can take a look on how the .moc file looks. It is a C++ source file, but look at how complicated it looks! If you would not use the moc.exe which interpretes the Q_OBJECT macro, you would have to write that file all on your own! This stuff is a big, big feature of Qt! By the way, the .moc extension could also be different, but almost everyone uses .moc]

    If your header file changes, you must again call moc.exe. You must do this for every class with the Q_OBJECT macro.

    Hint for convenience
    To get started you can do the above steps by hand. I did the same but later on I made it a little more convenient for myself: I did the following:

    • added the directory of moc.exe to the path environment variable, so I can call moc.exe from any location
    • added a batch job to my VS project, e.g. CallMoc.bat ( you do not have to add it to the project, but by adding it, it's faster to edit)
    • The batch job contains the calls to moc.exe for every needed class, e.g.:
      ** moc YourClass.h -o YourClass.moc
      ** moc YourClass2.h -o YourClass2.moc
    • So, if I write a new class for which I need to call moc.exe, I just add a line in CallMoc.bat (instead of going to the command line prompt and call it by hand)
    • Of course I still need to add the "#include YourClassXYZ.moc" lines at the end of my cpp files.
    • To be sure that the batch job is always called, I add it to the pre-build-events: Project Properties --> Build Events --> Pre-Build Event --> Command Line="call CallMoc.bat"
    • Now the .moc files are always created with every build, so you can not forget to call it.

    Hope this helps. Please provide feedback, it took some time to post this. If this helps and if so, add [SOLVED] to the title of this topic.



  • It's still not working, but I suspect I called moc.exe the wrong way. Here's main.h:
    [code]#include <QtGui>
    class Notepad : public QWidget
    {
    Q_OBJECT
    public:
    Notepad();
    private slots:
    void quit();
    private:
    QTextEdit *textEdit;
    QPushButton *quitButton;
    };[/code]
    And main.cpp:
    [code]#include "main.h"
    Notepad::Notepad()
    {
    textEdit = new QTextEdit;
    quitButton = new QPushButton(tr("Quit"));
    connect(quitButton, SIGNAL(clicked()), this, SLOT(quit()));
    QVBoxLayout *layout = new QVBoxLayout;
    layout->addWidget(textEdit);
    layout->addWidget(quitButton);
    setLayout(layout);
    setWindowTitle(tr("Notepad"));
    }
    void Notepad::quit()
    {
    QMessageBox messageBox;
    messageBox.setWindowTitle(tr("Notepad"));
    messageBox.setText(tr("Do you really want to quit?"));
    messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
    messageBox.setDefaultButton(QMessageBox::No);
    if (messageBox.exec() == QMessageBox::Yes)
    qApp->quit();
    }
    int main(int argc, char **argv)
    {
    QApplication app(argc, argv);
    Notepad notepad;
    notepad.show();
    return app.exec();
    }
    #include "main.moc"[/code]
    I opened the project properties, went to Configuration Properties->Build Events->Pre-Build Event and in the Command Line field I put moc main.h -o main.moc. I get these compile errors:
    [code]1>------ Build started: Project: Qt_test, Configuration: Debug Win32 ------
    1> main.cpp
    1>c:\users\owner\documents\visual studio 2010\projects\qt_test\qt_test\main.h(3): error C2011: 'Notepad' : 'class' type redefinition
    1> c:\users\owner\documents\visual studio 2010\projects\qt_test\qt_test\main.h(3) : see declaration of 'Notepad'
    1>c:\users\owner\documents\visual studio 2010\projects\qt_test\qt_test\main.moc(43): error C2027: use of undefined type 'Notepad'
    1> c:\users\owner\documents\visual studio 2010\projects\qt_test\qt_test\main.h(3) : see declaration of 'Notepad'
    1>c:\users\owner\documents\visual studio 2010\projects\qt_test\qt_test\main.moc(46): error C2065: 'staticMetaObject' : undeclared identifier
    1>c:\users\owner\documents\visual studio 2010\projects\qt_test\qt_test\main.moc(46): error C2228: left of '.cast' must have class/struct/union
    1> type is ''unknown-type''
    1>c:\users\owner\documents\visual studio 2010\projects\qt_test\qt_test\main.moc(49): error C2027: use of undefined type 'Notepad'
    1> c:\users\owner\documents\visual studio 2010\projects\qt_test\qt_test\main.h(3) : see declaration of 'Notepad'
    1>c:\users\owner\documents\visual studio 2010\projects\qt_test\qt_test\main.moc(49): error C2227: left of '->quit' must point to class/struct/union/generic type
    1>c:\users\owner\documents\visual studio 2010\projects\qt_test\qt_test\main.moc(56): error C2027: use of undefined type 'Notepad'
    1> c:\users\owner\documents\visual studio 2010\projects\qt_test\qt_test\main.h(3) : see declaration of 'Notepad'
    1>c:\users\owner\documents\visual studio 2010\projects\qt_test\qt_test\main.moc(60): error C2027: use of undefined type 'Notepad'
    1> c:\users\owner\documents\visual studio 2010\projects\qt_test\qt_test\main.h(3) : see declaration of 'Notepad'
    1>c:\users\owner\documents\visual studio 2010\projects\qt_test\qt_test\main.moc(69): error C2027: use of undefined type 'Notepad'
    1> c:\users\owner\documents\visual studio 2010\projects\qt_test\qt_test\main.h(3) : see declaration of 'Notepad'
    1>c:\users\owner\documents\visual studio 2010\projects\qt_test\qt_test\main.moc(70): error C2270: 'metaObject' : modifiers not allowed on nonmember functions
    1>c:\users\owner\documents\visual studio 2010\projects\qt_test\qt_test\main.moc(71): error C2227: left of '->metaObject' must point to class/struct/union/generic type
    1>c:\users\owner\documents\visual studio 2010\projects\qt_test\qt_test\main.moc(71): error C2227: left of '->metaObject' must point to class/struct/union/generic type
    1>c:\users\owner\documents\visual studio 2010\projects\qt_test\qt_test\main.moc(74): error C2027: use of undefined type 'Notepad'
    1> c:\users\owner\documents\visual studio 2010\projects\qt_test\qt_test\main.h(3) : see declaration of 'Notepad'
    1>c:\users\owner\documents\visual studio 2010\projects\qt_test\qt_test\main.moc(78): error C2355: 'this' : can only be referenced inside non-static member functions
    1>c:\users\owner\documents\visual studio 2010\projects\qt_test\qt_test\main.moc(79): error C2352: 'QWidget::qt_metacast' : illegal call of non-static member function
    1> c:\qt\4.8.3opensource\src\gui\kernel\qwidget.h(149) : see declaration of 'QWidget::qt_metacast'
    1>c:\users\owner\documents\visual studio 2010\projects\qt_test\qt_test\main.moc(82): error C2027: use of undefined type 'Notepad'
    1> c:\users\owner\documents\visual studio 2010\projects\qt_test\qt_test\main.h(3) : see declaration of 'Notepad'
    1>c:\users\owner\documents\visual studio 2010\projects\qt_test\qt_test\main.moc(84): error C2352: 'QWidget::qt_metacall' : illegal call of non-static member function
    1> c:\qt\4.8.3opensource\src\gui\kernel\qwidget.h(149) : see declaration of 'QWidget::qt_metacall'
    1>c:\users\owner\documents\visual studio 2010\projects\qt_test\qt_test\main.moc(89): error C2355: 'this' : can only be referenced inside non-static member functions
    ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========[/code]



  • I could recreate your problem. The solution is easy: just put an include guard around your main.h contents:

    @#ifndef NOTEPAD_H
    #define NOTEPAD_H
    #include <QtGui>
    class Notepad : public QWidget
    {
    //...
    };

    #endif //NOTEPAD_H@

    Reason: you include main.h two times. The first time it's included by main.cpp and the second time it's included by main.moc

    [ By the way: it's always cleaner to put a class definition into a dedicated .cpp and .h file, i.e. notepad.cpp and notepad.h and leave in main.cpp only the main function. And don't forget to always surround the header contents with an include guard -- not only in this case. Helps to avoid headaches ;-) ]



  • Thanks, the include guard did the trick! I'm a self-taught C++ coder, and not a very good one at that, so I didn't even know about include guards. I've seen them before, but didn't really realize their purpose. Handy trick to know.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.