PDA

View Full Version : Plugin compiler error: undefined reference



FinderCheng
29th April 2010, 14:17
Hi, all! I want to put all UI components into one dll so I try to create a plugin. Then my folder tree is:

/ --- test.pro
|
ui ---- ui.pro
| | -- mainwindow.h
| | -- mainwindow.cpp
| | -- ivisible.h // this contains the interface that has only two functions: setVisible(bool) and visible()
|
app ----- app.pro
| --- main.cpp
| --- mainwindow.h // copy from ui/mainwindow.h

and the code is:

test.pro


TEMPLATE = subdirs
CONFIG += ordered
SUBDIRS += ui app


app.pro


TARGET = test
TEMPLATE = app
CONFIG += debug
SOURCES += main.cpp
HEADERS += mainwindow.h
LIBS += -LE:\documents\test\app\plugins -lui


main.cpp


#include <QtGui/QApplication>
#include <QPluginLoader>
#include <QMessageBox>
#include <QDir>
#include "mainwindow.h"

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QDir dir(a.applicationDirPath ());
dir.cdUp();
dir.cd("plugins");
QPluginLoader loader(dir.absolutePath() + "/ui.dll");
QObject *plugin = loader.instance();
if(plugin) {
MainWindow *win = qobject_cast<MainWindow *>(plugin);
win->setVisible(true);
} else {
QMessageBox::information(NULL, "load error", loader.errorString());
}
loader.unload();
return a.exec();
}


mainwindow.h


#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "ivisible.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow, public IVisible {
Q_OBJECT
Q_INTERFACES(IVisible)

public:
MainWindow(QWidget *parent = 0);
~MainWindow();

void setVisible(bool v) { if(v) this->show(); else this->hide(); }
bool visible() const { return this->visible(); }

protected:
void changeEvent(QEvent *e);

private:
Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H


mainwindow.cpp


#include <QtPlugin>

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}

MainWindow::~MainWindow()
{
delete ui;
}

void MainWindow::changeEvent(QEvent *e)
{
QMainWindow::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
ui->retranslateUi(this);
break;
default:
break;
}
}

Q_EXPORT_PLUGIN2(ui, MainWindow)


As you can see, main window is the code created by QtCreator and the interface IVisible has only two functions. My problem is there are errors while compiling:

undefined reference to `MainWindow::~MainWindow()'
undefined reference to `MainWindow::changeEvent(QEvent*)'

I think this is because I only add mainwindow.h to app.pro and Qt cannot find the cpp. But I should do this in order to create the main window in main() function. So how can I solve this problem? Must I create main window in application or create it in a function in the plugin and call it in main()?

Thank you!

caduel
29th April 2010, 19:30
if you call any methods of the type MainWindow this type's code is needed in your app;
if you cast plugin to IVisible instead, you might have more luck.

FinderCheng
30th April 2010, 01:16
if you call any methods of the type MainWindow this type's code is needed in your app;
if you cast plugin to IVisible instead, you might have more luck.

What I want to try to put all UI components into one dll so MainWindow is also in that dll. Then I should call this
MainWindow in main() function in order to show it. I checked the class name returned by QPluginLoader::instance()
and it was a MainWindow. I tried to cast it to IVisible using


IVisible * v = (IVisible *)plugin;
v->setVisible(true);

note that it is not a QObject so I cann't using qobject_cast but it also had the same problem. If I remove HEADERS += mainwindow.h
in app.pro, it is all right. But there is an runtime error when setVisible() called.

So how should I do? If I just want to get the MainWindow instance, how should I code? Or I can try IVisible but whatis the
runtime error?

faldzip
30th April 2010, 06:44
Why you want your UI components to be a plugin? Can it be a regular library? You will get the .dll linked to your app.
The main idea of plugins is that there is defined one interface (an abstract C++ class) and you communicate with plugins trough that interface (that's why it is called interface...).
So in your case you should cast objects to IVisible and use only IVisible methods on loaded plugins (otherwise there are some methods in MainWindow declared in mainwindow.h but NOT IMPLEMENTED anywhere in your app...) or just get rid of this IVisible, make your plugin a regular library and link it to your app (like you already did).
But remember that in dll you need proper dllimport and dllexport -> create a new project "C++ library" in QtCreator to see how to deal with dll import and export (look at *_global.h, .pro file and class declaration).

FinderCheng
30th April 2010, 11:00
Why you want your UI components to be a plugin? Can it be a regular library? You will get the .dll linked to your app.
The main idea of plugins is that there is defined one interface (an abstract C++ class) and you communicate with plugins trough that interface (that's why it is called interface...).
So in your case you should cast objects to IVisible and use only IVisible methods on loaded plugins (otherwise there are some methods in MainWindow declared in mainwindow.h but NOT IMPLEMENTED anywhere in your app...) or just get rid of this IVisible, make your plugin a regular library and link it to your app (like you already did).
But remember that in dll you need proper dllimport and dllexport -> create a new project "C++ library" in QtCreator to see how to deal with dll import and export (look at *_global.h, .pro file and class declaration).

Thank you! I also think I'm creating a shared library not a plugin. But I don't know how to import this library into my project? It says that I should use QLibrary. But the document only shows how to import functions from dll while I just export classes. Could you tell me how should I do if I've got the dll library by creating shared library project?

I just paste header file and dll file into the same file and add LIBS += -e:/works/test/ui.dll file. Then recompile this project there is no error but when I run it, the exit code is not 0 and no window shown. I don't know why?

faldzip
30th April 2010, 11:44
This:


LIBS += -LE:\documents\test\app\plugins -lui

looks in E:\documents\test\app\plugins for ui.lib. And instead of copying mainwindow.h just add INCLUDEPATH += path/where/headers/are in app.pro file and remove it from HEADERS.
And show your ui.pro and mainwindow.h.

FinderCheng
1st May 2010, 02:34
Hi! I tried to create a library instead of a plugin, so I had to modified existing code as following:

test.pro


# there is no any change
TEMPLATE = subdirs
CONFIG += ordered
SUBDIRS += ui app


app.pro


TARGET = test
TEMPLATE = app
CONFIG += debug
SOURCES += main.cpp
LIBS += E:/documents/test/app/lib/ui.dll # I realized this is the correct syntax on Windows
INCLUDEPATH += ../ui


main.cpp


// Since this is a library, I think I should use it just like QtGui and so on, so I include necessary head files and create an instance as usual
#include <QtGui/QApplication>
#include "mainwindow.h"

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow win;
win.show();
return a.exec();
}


ui.pro


# also I should edit this file in order to generate a library instead of a plugin
TARGET = ui
TEMPLATE = lib
DEFINES += UI_LIBRARY
CONFIG += debug
SOURCES += mainwindow.cpp
HEADERS += mainwindow.h \
ui_global.h
FORMS += mainwindow.ui
DESTDIR = ../app/lib


ui_global.h


#ifndef UI_GLOBAL_H
#define UI_GLOBAL_H

#include <QtCore/qglobal.h>

#if defined(UI_LIBRARY)
# define UISHARED_EXPORT Q_DECL_EXPORT
#else
# define UISHARED_EXPORT Q_DECL_IMPORT
#endif

#endif // UI_GLOBAL_H


mainwindow.h


// OK, this is almost what QtCreator generated for me, I only added show() function in order to let Qt export this function, am I right?
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "ui_global.h"

namespace Ui {
class MainWindow;
}

class UISHARED_EXPORT MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
void show();
protected:
void changeEvent(QEvent *e);
private:
Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H


mainwindow.cpp


#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}

MainWindow::~MainWindow()
{
delete ui;
}

void MainWindow::changeEvent(QEvent *e)
{
QMainWindow::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
ui->retranslateUi(this);
break;
default:
break;
}
}

void MainWindow::show()
{
this->show();
}


OK, when I recompile this project, there is nothing wrong. But I could not run it. It says that "E:\documents\test\app\debug\test.exe exited with code -1073741819" although I have copied ui.dll to the same directory of test.exe.

faldzip
1st May 2010, 08:09
app.pro


TARGET = test
TEMPLATE = app
CONFIG += debug
SOURCES += main.cpp
LIBS += E:/documents/test/app/lib/ui.dll # I realized this is the correct syntax on Windows
INCLUDEPATH += ../ui


I don't think so. Do you have ui.lib file generated with ui.dll. I'm not sure if DESTDIR works with it so check in debug folder. This ui.lib is the right file to link with while compiling and ui.dll it the right file to link with in runtime. And the previous syntax was okay - I use it on both - Windows and Linux.


main.cpp


// Since this is a library, I think I should use it just like QtGui and so on, so I include necessary head files and create an instance as usual
#include <QtGui/QApplication>
#include "mainwindow.h"

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow win;
win.show();
return a.exec();
}


That's correct.



ui.pro


# also I should edit this file in order to generate a library instead of a plugin
TARGET = ui
TEMPLATE = lib
DEFINES += UI_LIBRARY
CONFIG += debug
SOURCES += mainwindow.cpp
HEADERS += mainwindow.h \
ui_global.h
FORMS += mainwindow.ui
DESTDIR = ../app/lib


This file looks okay now (for library).


mainwindow.h


// OK, this is almost what QtCreator generated for me, I only added show() function in order to let Qt export this function, am I right?


No, it is already exported in QtGui.dll as it is part of QWidget class.


OK, when I recompile this project, there is nothing wrong.

Are you sure? You are qmaking and building test.pro or app.pro?
Open VS command prompt, go to the app dir and run:

qmake && nmake and see what you get.

But I could not run it. It says that "E:\documents\test\app\debug\test.exe exited with code -1073741819" although I have copied ui.dll to the same directory of test.exe.
Use Dependency Walker to check library dependencies of your app.exe. And did you try also running it from outside of QtCreator just by double clicking test.exe?

FinderCheng
1st May 2010, 16:49
I don't think so. Do you have ui.lib file generated with ui.dll. I'm not sure if DESTDIR works with it so check in debug folder. This ui.lib is the right file to link with while compiling and ui.dll it the right file to link with in runtime. And the previous syntax was okay - I use it on both - Windows and Linux.

Sorry, I check both DESTDIR and debug folders and there is no such file called ui.lib.


Are you sure? You are qmaking and building test.pro or app.pro?

Yes, I rebuild project with test.pro and app.pro each time and there is no error.


Open VS command prompt, go to the app dir and run:

qmake && nmake and see what you get.

I'm sorry but I have no VS compiler. So I open app.pro as a separate project and build it, nothing wrong here.


Use Dependency Walker to check library dependencies of your app.exe. And did you try also running it from outside of QtCreator just by double clicking test.exe?

I have a little trouble with Dependency Walker. What results should I looking for? I checked test.exe(not app.exe, TARGET = test in app.pro) and its library contains ui.dll. And I tried to open test.exe outside QtCreator, no window opened...