Undefined references during build of plugin in Qt Creator - qt

I'm trying to create plugin for Qt Creator, so I simply selected new file or project/Libraries/QtCreator plugin. I've specified the sources for Qt Creator as well as build of Qt Creator. When I've tried to build it I'm getting the following three errors:
*C:\...\mypluginplugin.cpp:20: error:
undefined reference to `vtable for MyPlugin::Internal::MyPluginPlugin'* //this is constructor
*C:\...\mypluginplugin.cpp:25: error:
undefined reference to `vtable for MyPlugin::Internal::MyPluginPlugin'* //this is destructor
C:\...\mypluginplugin.hpp:13: error:
undefined reference to `MyPlugin::Internal::MyPluginPlugin::staticMetaObject' //when I double click
on this error it moves me to my .hpp file to the Q_OBJECT macro:
This is my code:
namespace MyPlugin {
namespace Internal {
class MyPluginPlugin : public ExtensionSystem::IPlugin
{
Q_OBJECT// the last, third error moves me here
public:
MyPluginPlugin();
~MyPluginPlugin();
bool initialize(const QStringList &arguments, QString *errorString);
void extensionsInitialized();
ShutdownFlag aboutToShutdown();
private slots:
void triggerAction();
};
} // namespace Internal
} // namespace MyPlugin
Any idea how to solve this problem?
//EDIT
#include "mypluginplugin.hpp"
#include "mypluginconstants.hpp"
#include <coreplugin/icore.h>
#include <coreplugin/icontext.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/command.h>
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/coreconstants.h>
#include <QAction>
#include <QMessageBox>
#include <QMainWindow>
#include <QMenu>
#include <QtPlugin>
using namespace MyPlugin::Internal;
MyPluginPlugin::MyPluginPlugin()
{
// Create your members
}
MyPluginPlugin::~MyPluginPlugin()
{
// Unregister objects from the plugin manager's object pool
// Delete members
}
bool MyPluginPlugin::initialize(const QStringList &arguments, QString *errorString)
{
// Register objects in the plugin manager's object pool
// Load settings
// Add actions to menus
// Connect to other plugins' signals
// In the initialize method, a plugin can be sure that the plugins it
// depends on have initialized their members.
Q_UNUSED(arguments)
Q_UNUSED(errorString)
QAction *action = new QAction(tr("MyPlugin action"), this);
Core::Command *cmd = Core::ActionManager::registerAction(action, Constants::ACTION_ID,
Core::Context(Core::Constants::C_GLOBAL));
cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Alt+Meta+A")));
connect(action, SIGNAL(triggered()), this, SLOT(triggerAction()));
Core::ActionContainer *menu = Core::ActionManager::createMenu(Constants::MENU_ID);
menu->menu()->setTitle(tr("MyPlugin"));
menu->addAction(cmd);
Core::ActionManager::actionContainer(Core::Constants::M_TOOLS)->addMenu(menu);
return true;
}
void MyPluginPlugin::extensionsInitialized()
{
// Retrieve objects from the plugin manager's object pool
// In the extensionsInitialized method, a plugin can be sure that all
// plugins that depend on it are completely initialized.
}
ExtensionSystem::IPlugin::ShutdownFlag MyPluginPlugin::aboutToShutdown()
{
// Save settings
// Disconnect from signals that are not needed during shutdown
// Hide UI (if you add UI that is not in the main window directly)
return SynchronousShutdown;
}
void MyPluginPlugin::triggerAction()
{
QMessageBox::information(Core::ICore::mainWindow(),
tr("Action triggered"),
tr("This is an action from MyPlugin."));
}
Q_EXPORT_PLUGIN2(MyPlugin, MyPluginPlugin)

I figured out what happened. Ok, here is the solution for others - qtcreator simply didn't attach .hpp files to the project, yet there were created. After adding those .hpp files via add existing files, it builds fine now.

Related

Emit Signal in Constructor of Qml Registered Type doesn't Work

I am setting up a resource manager class for my application. to manage all state of resources, i need to emmit a Signal from constructor if it don't succeed to catch resource.
In fact i want to emit signal from constructor of QObject Derived Class that registered for qml via qmlRegisterType.
this is code i have tested on Linux runnng MySql and Qt 5.12.2. but the emit signal doesn't work.
myresoureces.cpp ---- my Class that manage resources
MyResource::MyResource(QObject *parent) : QObject(parent)
{
if(!openResource()) {
// qDebug() << "Check Permission of FileSystem For Example.";
emit openResourceFailed("Check Permission of FileSystem For Example.");
}
}
bool MyResource::openResource()
{
// on situation opening resource failed
return false;
}
main.qml ---- usage of it in qml
// ...
import My.Company.Core 1.0
// ...
MyResource {
onOpenResourceFailed: {
msgDialog.title = "Open Resource Failed!"
msgDialog.text = error
msgDialog.open()
}
}
MessageDialog {
id: msgDialog
}
// ...
main.cpp ---- where i register the class
qmlRegisterType<MyResource>("My.Company.Core", 1, 0, "MyResource");
I expect the Message Dialog to be opened but nothing happened.
The signals will invoke the methods that are connected at the time of the signal emission, in your case in the constructor is not connected to any slot so the data will be lost, a possible solution is to use a QTimer::singleShot(0, ...) to be emitted a moment after the creation:
MyResource::MyResource(QObject *parent=nullptr) : QObject(parent){
if(!openResource()) {
QTimer::singleShot(0, this, [this](){
emit openResourceFailed("Check Permission of FileSystem For Example.");
});
}
}
Another alternative solution is to use QQmlParserStatus as an interface and emit the signal in the componentComplete() method:
*.h
#ifndef MYRESOURCE_H
#define MYRESOURCE_H
#include <QObject>
#include <QQmlParserStatus>
class MyResource: public QObject, public QQmlParserStatus
{
Q_OBJECT
Q_INTERFACES(QQmlParserStatus)
public:
MyResource(QObject *parent=nullptr);
void classBegin();
void componentComplete();
signals:
void openResourceFailed(const QString & error);
private:
bool openResource();
};
#endif // MYRESOURCE_H
*.cpp
#include "myresource.h"
MyResource::MyResource(QObject *parent) : QObject(parent){}
void MyResource::classBegin(){}
void MyResource::componentComplete(){
if(!openResource()) {
emit openResourceFailed("Check Permission of FileSystem For Example.");
}
}
bool MyResource::openResource(){
// on situation opening resource failed
return false;
}

Compiling own QtCreator Plugin fails

I'm trying to create my own QtCreator Plugin by following this guide.
So I cloned this repo and checked the v2.8.1 tagged commit out (c3ed746c).
Then I copied my QtCreator 2.8.1 directory and created a new Qt Creator Plugin project.
Then I create a new file in my project directory called MyPlugin.json.
If I try to compile my plug in I get this error:
e:\qtprojects\build-myplugin-desktop_qt_5_1_1_msvc2012_32bit-debug\debug../../MyPlugin/mypluginplugin.h(6) : fatal error C1083: Cannot open include file: "extensionsystem/iplugin.h": No such file or directory
jom: E:\QtProjects\build-MyPlugin-Desktop_Qt_5_1_1_MSVC2012_32bit-Debug\Makefile.Debug [debug\moc_mypluginplugin.obj] Error 2
jom: E:\QtProjects\build-MyPlugin-Desktop_Qt_5_1_1_MSVC2012_32bit-Debug\Makefile [debug] Error 2
10:56:51: The process "E:\Qt\Qt5\Tools\QtCreator\bin\jom.exe" exited with code 2.
Error while building/deploying project myplugin (kit: Desktop Qt 5.1.1 MSVC2012 32bit)
When executing step 'Make'
10:56:51: Elapsed time: 00:01.
What do I have to do to make it work?
This are the source files:
myplugin.pro
DEFINES += MYPLUGIN_LIBRARY
# MyPlugin files
SOURCES += mypluginplugin.cpp
HEADERS += mypluginplugin.h \
myplugin_global.h \
mypluginconstants.h
# Qt Creator linking
## set the QTC_SOURCE environment variable to override the setting here
QTCREATOR_SOURCES = $$(QTC_SOURCE)
isEmpty(QTCREATOR_SOURCES):QTCREATOR_SOURCES=E:/QtProjects/_QtCreatorPlugIns/qt-creator
## set the QTC_BUILD environment variable to override the setting here
IDE_BUILD_TREE = $$(QTC_BUILD)
isEmpty(IDE_BUILD_TREE):IDE_BUILD_TREE=E:/QtProjects/_QtCreatorPlugIns/QtCreator
## uncomment to build plugin into user config directory
## <localappdata>/plugins/<ideversion>
## where <localappdata> is e.g.
## "%LOCALAPPDATA%\QtProject\qtcreator" on Windows Vista and later
## "$XDG_DATA_HOME/data/QtProject/qtcreator" or "~/.local/share/data/QtProject/qtcreator" on Linux
## "~/Library/Application Support/QtProject/Qt Creator" on Mac
# USE_USER_DESTDIR = yes
PROVIDER = MyCompany
include($$QTCREATOR_SOURCES/src/qtcreatorplugin.pri)
myplugin_global.h
#ifndef MYPLUGIN_GLOBAL_H
#define MYPLUGIN_GLOBAL_H
#include <QtGlobal>
#if defined(MYPLUGIN_LIBRARY)
# define MYPLUGINSHARED_EXPORT Q_DECL_EXPORT
#else
# define MYPLUGINSHARED_EXPORT Q_DECL_IMPORT
#endif
#endif // MYPLUGIN_GLOBAL_H
mypluginconstants.h
#ifndef MYPLUGINCONSTANTS_H
#define MYPLUGINCONSTANTS_H
namespace MyPlugin {
namespace Constants {
const char ACTION_ID[] = "MyPlugin.Action";
const char MENU_ID[] = "MyPlugin.Menu";
} // namespace MyPlugin
} // namespace Constants
#endif // MYPLUGINCONSTANTS_H
mypluginplugin.h
#ifndef MYPLUGIN_H
#define MYPLUGIN_H
#include "myplugin_global.h"
#include <extensionsystem/iplugin.h>
namespace MyPlugin {
namespace Internal {
class MyPluginPlugin : public ExtensionSystem::IPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "MyPlugin.json")
public:
MyPluginPlugin();
~MyPluginPlugin();
bool initialize(const QStringList &arguments, QString *errorString);
void extensionsInitialized();
ShutdownFlag aboutToShutdown();
private slots:
void triggerAction();
};
} // namespace Internal
} // namespace MyPlugin
#endif // MYPLUGIN_H
mypluginplugin.cpp
#include "mypluginplugin.h"
#include "mypluginconstants.h"
#include <coreplugin/icore.h>
#include <coreplugin/icontext.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/command.h>
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/coreconstants.h>
#include <QAction>
#include <QMessageBox>
#include <QMainWindow>
#include <QMenu>
#include <QtPlugin>
using namespace MyPlugin::Internal;
MyPluginPlugin::MyPluginPlugin()
{
// Create your members
}
MyPluginPlugin::~MyPluginPlugin()
{
// Unregister objects from the plugin manager's object pool
// Delete members
}
bool MyPluginPlugin::initialize(const QStringList &arguments, QString *errorString)
{
// Register objects in the plugin manager's object pool
// Load settings
// Add actions to menus
// Connect to other plugins' signals
// In the initialize method, a plugin can be sure that the plugins it
// depends on have initialized their members.
Q_UNUSED(arguments)
Q_UNUSED(errorString)
QAction *action = new QAction(tr("MyPlugin action"), this);
Core::Command *cmd = Core::ActionManager::registerAction(action, Constants::ACTION_ID,
Core::Context(Core::Constants::C_GLOBAL));
cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Alt+Meta+A")));
connect(action, SIGNAL(triggered()), this, SLOT(triggerAction()));
Core::ActionContainer *menu = Core::ActionManager::createMenu(Constants::MENU_ID);
menu->menu()->setTitle(tr("MyPlugin"));
menu->addAction(cmd);
Core::ActionManager::actionContainer(Core::Constants::M_TOOLS)->addMenu(menu);
return true;
}
void MyPluginPlugin::extensionsInitialized()
{
// Retrieve objects from the plugin manager's object pool
// In the extensionsInitialized method, a plugin can be sure that all
// plugins that depend on it are completely initialized.
}
ExtensionSystem::IPlugin::ShutdownFlag MyPluginPlugin::aboutToShutdown()
{
// Save settings
// Disconnect from signals that are not needed during shutdown
// Hide UI (if you add UI that is not in the main window directly)
return SynchronousShutdown;
}
void MyPluginPlugin::triggerAction()
{
QMessageBox::information(Core::ICore::mainWindow(),
tr("Action triggered"),
tr("This is an action from MyPlugin."));
}
Q_EXPORT_PLUGIN2(MyPlugin, MyPluginPlugin)
Directories
E:\QtProjects\_QtCreatorPlugIns> tree
├───qt-creator
│ ├───bin
│ ├───dist
│ ├───doc
│ ├───lib
│ ├───qbs
│ ├───scripts
│ ├───share
│ ├───srcn64interrupt
│ └───testsster
├───QtCreator
│ ├───bin
│ ├───lib0
│ └───share
If you're a linux user, you can download qtcreator-dev. But, i don't know how it works on Windows.
Open terminal
Type : sudo apt-get install qtcreator-dev
Done.

Export QObject-based class to DLL

I'm composing a class which derives from QObject, and I want to export this class into a DLL file so other applications can use it. But I got some mysterious problem here:
The code is shown below:
mydll.h:
#ifndef MYDLL_H
#define MYDLL_H
#include "mydll_global.h"
#include <QObject>
#include <QDebug>
class MYDLLSHARED_EXPORT MyDll : public QObject
{
Q_OBJECT
public:
explicit MyDll(QObject * parent = 0);
void test() const;
};
#endif // MYDLL_H
mydll_global.h:
#ifndef MYDLL_GLOBAL_H
#define MYDLL_GLOBAL_H
#include <QtCore/qglobal.h>
#if defined(MYDLL_LIBRARY)
# define MYDLLSHARED_EXPORT Q_DECL_EXPORT
#else
# define MYDLLSHARED_EXPORT Q_DECL_IMPORT
#endif
#endif // MYDLL_GLOBAL_H
mydll.cpp:
#include "mydll.h"
MyDll::MyDll(QObject * parent) :
QObject(parent)
{
}
void MyDll::test() const {
qDebug() << "Hello from dll!";
}
and the dll is used in another application. The dll is compiled successfully. I've add LIBS += "myDll.dll" in the .pro file of the application using this dll, and I've copied myDll.dll to the working directory of the application.
The compiler reports:
C4273: "MyDll::qt_static_metacall" : inconsistent dll linkage.
C2491: "MyDll::staticMetaObject": definition of dllimport static data member not allowed
What's the problem here?
Your code for mydll_global.h checks whether MYDLL_LIBRARY is defined, but none of the code you have posted defines MYDLL_LIBRARY. Is this declared in a file that you have not shared on the question? If not, you need to add a #define MYDLL_LIBRARY in your build project, or your PCH.

How to send data to and from the browser with a Qt HTML5 Application

None of the tutorials available online show how to create a Qt HTML5 application. Ideally, I just need a way to send data (a string will do) between webkit and Qt.
When I create a Qt HTML5 Application It generates
myApp.pro
html5applicationviewer.pri // comments say dont touch this file
html5applicationviewer.h // comments say dont touch this file
html5applicationviewer.cpp // comments say dont touch this file
main.cpp
index.html
So how do I add a function in C++ to communicate with the browser and how do I add a function in the browser to communicate with C++?
This example is old but still work and is very simple and clean.
Also you may want to take a look to qtwebkit-bridge and the tutorial.
edit
add a file called myclass.h
#include "html5applicationviewer/html5applicationviewer.h"
class MyClass : public Html5ApplicationViewer
{
Q_OBJECT
public:
explicit MyClass(QWidget *parent=0);
private slots:
void addToJavaScript();
public slots:
QString test(const QString &param);
};
add a file called myclass.cpp
#include <QDebug>
#include <QGraphicsWebView>
#include <QWebFrame>
#include "myclass.h"
MyClass::MyClass(QWidget *parent) : Html5ApplicationViewer(parent) {
QObject::connect(webView()->page()->mainFrame(),
SIGNAL(javaScriptWindowObjectCleared()), SLOT(addToJavaScript()));
}
void MyClass::addToJavaScript() {
webView()->page()->mainFrame()->addToJavaScriptWindowObject("MyClass", this);
}
QString MyClass::test(const QString &param) {
qDebug() << "from javascript " << param;
return QString("from c++");
}
in your .pro add
SOURCES += main.cpp myclass.cpp
HEADERS += myclass.h
in your .html add
try {
alert(MyClass.test("test string"));
} catch(err) {
alert(err);
}
in your main.cpp add include:
#include "myclass.h"
and change:
Html5ApplicationViewer viewer;
to:
MyClass viewer;

Using a Singleton Class across a Qt Application and its Plugins

I'm trying to use a Singleton Class (its a program-wide debug logger called 'PrisLog') across my Qt Application. The program also has plugins. I want to make my singleton class available to those plugins, but this doesn't work. From what I can tell, trying to use the class in the plugin results in another instance being created.
-The singleton class is just a *.cpp and *.h file, nothing else. I've linked both my main application and the plugin to these files individually... is this the right way to do it?
-I've attached my singleton class's code below, though I think I've created the class correctly. If I use it from within separate classes in my main application, it works as expected (one instance).
EDIT: Linking both the application and plugin to the same static lib (the singleton class) works. Here's how my qmake *.pro files looked:
MySingletonLib.pro
TEMPLATE = lib
CONFIG += staticlib
HEADERS += \
mysingletonlib.h
SOURCES += \
mysingletonlib.cpp
MyPlugin.pro (also incl #include mysingletonlib.h in myplugin.h)
INCLUDEPATH += path/to/MySingletonLib
LIBS += -Lpath/to/MySingletonLib -lMySingletonLib
MyPlugin.pro (also incl #include mysingletonlib.h in myapp.h)
INCLUDEPATH += path/to/MySingletonLib
LIBS += -Lpath/to/MySingletonLib -lMySingletonLib
And the original code:
#ifndef PRISLOG_H
#define PRISLOG_H
#include <QFile>
#include <QDir>
#include <QString>
#include <QMutex>
#include <QDebug>
#include <QMutexLocker>
#include <QTextStream>
#include <QDateTime>
// PrisLog (singleton) class definition
class PrisLog
{
public:
static PrisLog* Instance();
void SetLogsPath(QString);
QString GetLogsPath();
void SetDebugDestination(QString);
void SetElmRxDestination(QString);
void SetElmTxDestination(QString);
void SetDlgDestination(QString);
QTextStream* GetDebugStream();
QTextStream* GetElmRxStream();
QTextStream* GetElmTxStream();
QTextStream* GetDlgStream();
QMutex* GetDebugMutex();
private:
PrisLog(); // private constructor
PrisLog(const PrisLog&); // prevent copy constructor
PrisLog& operator=(const PrisLog&); // prevent assignment
static PrisLog* m_Instance;
static bool m_InitFlag;
QString m_appPath;
QFile m_DebugFile;
QTextStream m_DebugStream;
QMutex m_DebugMutex;
QFile m_ElmRxFile;
QTextStream m_ElmRxStream;
QFile m_ElmTxFile;
QTextStream m_ElmTxStream;
QFile m_DlgFile;
QTextStream m_DlgStream;
};
// thread-UNSAFE writer, but less expensive
// use: single stream <--> single thread!
class PrisLogWriter
{
public:
PrisLogWriter(QTextStream*);
~PrisLogWriter();
QTextStream* m_stream;
};
// thread-UNSAFE writer, but less expensive
// this version does not include any formatting
// use: single stream <--> single thread!
class PrisLogRawWriter
{
public:
PrisLogRawWriter(QTextStream*);
~PrisLogRawWriter();
QTextStream* m_stream;
};
// thread-safe writer
// use: single stream <--> many threads
class PrisLogSafeWriter
{
public:
PrisLogSafeWriter(QTextStream*, QMutex*);
~PrisLogSafeWriter();
QTextStream* m_stream;
private:
QMutex* m_mutex;
};
#define PRISLOGDEBUG (*(PrisLogSafeWriter(PrisLog::Instance()->GetDebugStream(), PrisLog::Instance()->GetDebugMutex()).m_stream))
#define PRISLOGELMRX (*(PrisLogWriter(PrisLog::Instance()->GetElmRxStream()).m_stream))
#define PRISLOGELMTX (*(PrisLogWriter(PrisLog::Instance()->GetElmTxStream()).m_stream))
#define PRISLOGDLG (*(PrisLogRawWriter(PrisLog::Instance()->GetDlgStream()).m_stream))
#endif // PRISLOG_H
I think you should take this class to a statically linked, but separeted shared dll/so.
If your host application does not use this class, the linker simply won't link it into the binary and your plugin could not use it. Additionally: your binary has no library class interface.
You need to make sure, that only one instance exists. The safest is, that the cpp is compiled only once in the overall exe.
To make sure that the other DLLs can call PrisLog::Instance, this class/function (i.e. all public methods if PrisLog) needs to be declared with __declspec(dllexport), even if it is located within the exe.
The DLLs can then dynamically find the object and method.
BTW: Why don't you use the logging from Qt?

Resources