I followed http://brandontreb.com/beginning-jailbroken-ios-development-building-and-deployment
to make a tweak. every thing seems fine and make package install is successfull,
but when my iPhone respring, the "helloworld" box did not show up,
done any one knows how to solve this?
my xcode is 4.6 and sdk5.1 is installed
my iPhone is iOS6.1.2
I set those
export THEOS=/opt/theos/
export SDKVERSION=5.1
export THEOS_DEVICE_IP=192.168.1.101
this is Makefile
export ARCHS=armv7
export TARGET=iphone:5.1
include $(THEOS)/makefiles/common.mk
helloworld_FRAMEWORKS = UIKit
TWEAK_NAME = helloworld
helloworld_FILES = Tweak.xm
include $(THEOS)/makefiles/tweak.mk
and this is Tweak.xm
#import <SpringBoard/SpringBoard.h>
%hook SpringBoard
-(void)applicationDidFinishLaunching:(id)application {
%orig;
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Welcome"
message:#"Hello world"
delegate:nil
cancelButtonTitle:#"123"
otherButtonTitles:nil];
[alert show];
[alert release];
}
%end
I figure it out, the *.plist should be
{ Filter = { Bundles = ( "com.apple.springboard" ); }; }
thanks #H2CO3, i find your comment somewhere else
but after i done successfully with the helloworld tweak.
I hook the fopen using MSHookFunction
and then i meet a linking error
Making all for tweak hw...
Preprocessing Tweak.xm...
Compiling Tweak.xm...
Linking tweak hw...
Undefined symbols for architecture armv7:
"_MSHookFunction", referenced from:
global constructors keyed to Tweak.xm.mmin Tweak.xm.51941273.o
ld: symbol(s) not found for architecture armv7
collect2: ld returned 1 exit status
make[2]: *** [.theos/obj/hw.dylib.ba964c90.unsigned] Error 1
make[1]: *** [internal-library-all_] Error 2
make: *** [hw.all.tweak.variables] Error 2
this is Tweak.xm
#import "substrate.h"
static FILE * (*s_orig_fopen) ( const char * filename, const char * mode );
static FILE * my_fopen ( const char * filename, const char * mode ){
return s_orig_fopen(filename, mode);
}
static void entry(void) __attribute__ ((constructor));
static void entry(void) {
MSHookFunction(fopen, my_fopen, &s_orig_fopen);
}
Related
I am currently learning C and am trying to understand the possibilities of dynamic libraries.
My current question is, if I have a simple "Hello World" application in C called "ProgA", and this program dynamically loads a shared library with some example code called "LibB", can LibB access a global variable in ProgA, which was declared as external?
Given is the following example code for demonstration of the problem:
file header.h
#ifndef TEST_H
#define TEST_H
typedef struct test_import_s {
int some_field;
} test_import_t;
extern test_import_t newtestimport;
#endif
file prog_a.c
#include <stdio.h>
#include <windows.h>
#include "header.h"
test_import_t newtestimport = {
.some_field = 42
};
int main()
{
HINSTANCE hinstLib;
typedef void (*FunctionPointer)();
newtestimport.some_field = 42;
hinstLib = LoadLibrary("lib_b.dll");
if (hinstLib != NULL)
{
FunctionPointer initialize_lib_b;
initialize_lib_b = (FunctionPointer)GetProcAddress(hinstLib, "initialize_lib_b");
if (initialize_lib_b != NULL)
{
initialize_lib_b();
}
FreeLibrary(hinstLib);
}
return 0;
}
file lib_b.c
#include <stdio.h>
#include "header.h"
test_import_t *timp;
void initialize_lib_b() {
timp = &newtestimport;
int some_field = timp->some_field;
printf("Result from function: %d\n", some_field);
}
file CMakeLists.txt
cmake_minimum_required(VERSION 3.24)
project(dynamic-library-2 C)
set(CMAKE_C_STANDARD 23)
add_library(lib_b SHARED lib_b.c)
set_target_properties(lib_b PROPERTIES PREFIX "" OUTPUT_NAME "lib_b")
add_executable(prog_a prog_a.c)
target_link_libraries(prog_a lib_b)
In the above example, the headerfile header.h defines the struct test_import_t and an external variable newtestimport using this struct. In the C file of the main program prog_a.c one property of this struct is assigned the value 42. It then dynamically loads the library lib_b.c using the Windows API and executes a function in it. The function then should access the variable newtestimport of the main program and print out the value of the variable (42).
This example does not work. The compiler throws the following error:
====================[ Build | prog_a | Debug ]==================================
C:\Users\user1\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\223.8617.54\bin\cmake\win\x64\bin\cmake.exe --build C:\Users\user1\projects\learning-c\cmake-build-debug --target prog_a -j 9
[1/2] Linking C shared library dynamic-library-2\lib_b.dll
FAILED: dynamic-library-2/lib_b.dll dynamic-library-2/liblib_b.dll.a
cmd.exe /C "cd . && C:\Users\user1\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\223.8617.54\bin\mingw\bin\gcc.exe -fPIC -g -Wl,--export-all-symbols -shared -o dynamic-library-2\lib_b.dll -Wl,--out-implib,dynamic-library-2\liblib_b.dll.a -Wl,--major-image-version,0,--minor-image-version,0 dynamic-library-2/CMakeFiles/lib_b.dir/lib_b.c.obj -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 && cd ."
C:\Users\user1\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\223.8617.54\bin\mingw\bin/ld.exe: dynamic-library-2/CMakeFiles/lib_b.dir/lib_b.c.obj:lib_b.c:(.rdata$.refptr.newtestimport[.refptr.newtestimport]+0x0): undefined reference to `newtestimport'
collect2.exe: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.
How can the example be fixed to accomplish the described goal?
Windows DLLs are self-contained, and can not have undefined references similar to newtestimport, unless these references are satisfied by another DLL.
How can the example be fixed to accomplish the described goal?
The best fix is to pass the address of newtestimport into the function that needs it (initialize_lib_b() here).
If for some reason you can't do that, your next best option is to define the newtestimport as a dllexport variable in another DLL, e.g. lib_c.dll.
Then both the main executable and lib_b.dll would be linked against lib_c.lib, and would both use that variable from lib_c.dll.
P.S. Global variables are a "code smell" and a significant source of bugs. You should avoid them whenever possible, and in your example there doesn't seem to be any good reason to use them.
For some reason I am unable to load my plugins anymore, although it has worked previously. I have a plugin loader code in my MainWindow, which is supposed to load every .dll found in a specific folder. The MainWindow Code contains the following:
Interface
#ifndef PLUGININTERFACE_H
#define PLUGININTERFACE_H
#include <QtPlugin>
// forward declarations
class MainWindow;
struct P3DData;
class PluginInterface
{
public:
virtual bool createPublisher(MainWindow*, P3DData*) = 0;
};
#define PLUGIN_INTERFACE_iid "PluginInterface"
Q_DECLARE_INTERFACE(PluginInterface, PLUGIN_INTERFACE_iid)
#endif // PLUGININTERFACE_H
loadPlugins()
bool MainWindow::loadPlugins()
{
QDir pluginsDir(qApp->applicationDirPath());
pluginsDir.cd("plugins");
const auto entryList = pluginsDir.entryList(QDir::Files);
for(const QString &fileName : entryList)
{
QString dllPath = pluginsDir.absoluteFilePath(fileName);
QPluginLoader* loader = new QPluginLoader(dllPath);
loaderList.push_back(loader);
QObject *plugin = loader->instance();
if (plugin)
{
pluginList.push_back(qobject_cast<PluginInterface *>(plugin));
pluginList.last()->createPublisher(this, simDataPtr);
pluginCount++;
continue;
}
else
{
qDebug() << "[PluginLoader] '" + fileName + "': " + loader->errorString();
delete loaderList.takeLast();
}
}
}
Besides my MainWindow, there is another subdir in my project, which is the plugin "Position". The plugin is deployed into the correct "plugins" folder, which the loadPlugin() method from the MainWindow iterates through. The plugin uses following code to implement the interface:
#include <QObject>
#include "MainWindow.h"
class PositionPublisher : public QObject, PluginInterface
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "PluginInterface")
Q_INTERFACES(PluginInterface)
public:
PositionPublisher();
~PositionPublisher();
bool createPublisher(MainWindow* _window, P3DData* _simDataPtr) override;
//...
};
When trying to run loadPlugins() now, it checks the correct Position.dll file but the "if(plugin)" part returns false and loader->errorString() is executed giving the following error:
[PluginLoader] 'Position.dll': Cannot load library
F:\DEV\build\simNET\bin\plugins\Position.dll: Cannot find the
specified module.
I have already checked and tried the following:
the Plugins folder actually contains the Position.dll file
both projects (MainWindow and Plugin) are built in release mode
the dependencies of the plugin (two libs) exist and the specified path in the pro file is correct
.pro file of plugin:
QT += widgets
TEMPLATE = lib
CONFIG += c++11
CONFIG += plugin
CONFIG += release
SOURCES += \
Position.cpp \
PositionPubSubTypes.cpp \
PositionPublisher.cpp
HEADERS += \
Position.h \
PositionPubSubTypes.h \
PositionPublisher.h
DISTFILES += \
Position.idl
INCLUDEPATH += ../../application
TARGET = $$qtLibraryTarget(Position)
DESTDIR = ../../bin/plugins
INCLUDEPATH += "F:/DEV/prog/FastRTPSv1.5/include"
DEPENDPATH += "F:/DEV/prog/FastRTPSv1.5/include"
LIBS += -L"F:/DEV/prog/FastRTPSv1.5/lib/x64Win64VS2015" -lfastrtps-1.5
PRE_TARGETDEPS += F:/DEV/prog/FastRTPSv1.5/lib/x64Win64VS2015/fastrtps-1.5.lib
INCLUDEPATH += 'F:/Programme/Prepar3D v4/SDK/inc/SimConnect'
DEPENDPATH += 'F:/Programme/Prepar3D v4/SDK/inc/SimConnect'
LIBS += -L'F:/Programme/Prepar3D v4/SDK/lib/SimConnect' -lSimConnect
PRE_TARGETDEPS += 'F:/Programme/Prepar3D v4/SDK/lib/SimConnect/SimConnect.lib'
Does anyone have an idea why it does not load the plugin??
Qt plugin loader is trying to tell you that a Qt module used in your plugin doesn't exist so first you need to check which Qt modules your plugin depends on then,
If you're trying to run the application from Qt Creator itself, and it gives you this error, then maybe the DLL file got deleted for some reason or you're trying to use the plugin with a Qt version that doesn't have its needed modules. (for example, Qt6 doesn't contain the QtSerialPort module but Qt5 did (at the time of writing this)).
If you're trying to run the application directly outside Qt Creator then you need to copy the required module's dll file into your applications root directory.
For some time, I can't debug anymore my application which crashes each time I launch it in debug mode. On the other hand, it runs fine when only execute it.
I did many tests with different configurations:
Windows 7 with mingw32
Windows 10 with mingw32
Ubuntu with gcc
On Linux, no problem, everything works fine.
On windows 7 or 10 the application crashes as soon as it is opened, with the following message (twice) :
Microsoft Visual C++ Runtime Library :
This application has requested the Runtime to terminate it in an unusual way.
The output panel gives the following information:
Debugging starts
section .gnu_debuglink not found in ...\build-Integration GspvMapviewer-Desktop_Qt_5_9_2_MinGW_32bit-Debug\debug\Integration GspvMapviewer.exe.debug
QML debugging is enabled. Only use this in a safe environment.
QML Debugger: Waiting for connection on port 49727...
Invalid parameter passed to C runtime function.
Invalid parameter passed to C runtime function.
ASSERT: "!m_thread.isRunning()" in file qqmldebugserver.cpp, line 655
Invalid parameter passed to C runtime function.
Invalid parameter passed to C runtime function.
Debugging has finished
No problem mentioned in compilation output.
Searching the net, I can't find track on the origin of the problem.
Would you know how to solve this point ?
Thank you in advance.
EDIT1
.pro
QT += quick positioning widgets
CONFIG += c++11
DEFINES += QT_DEPRECATED_WARNINGS
SOURCES += \
main.cpp \
waypointsfilter.cpp
RESOURCES += gspv.qrc \
resource.qrc
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
HEADERS += \
waypointsfilter.h \
waypointsmodel.h \
airport.h \
waypoint.h \
airportsmodel.h \
landmark.h \
runwaymodel.h
OTHER_FILES +=main.qml \
helper.js \
images/marker.png \
images/scale.png \
images/scale_end.png \
map/MapComponent.qml \
map/Marker.qml \
map/MapSliders.qml \
menus/MainMenu.qml \
forms/Message.qml \
forms/MessageForm.ui.qml
DISTFILES += \
forms/SplitInterface.qml \
forms/IME.qml \
map/SimpleMap.qml \
map/Airport.qml \
images/BlackWaypoint.bmp \
map/Runway.qml \
forms/InitialAirport.qml
main.cpp
#include "waypointsmodel.h"
#include "waypointsfilter.h"
#include "airportsmodel.h"
#include <QApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QDebug>
#include <QDateTime>
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication app(argc, argv);
WaypointsModel model;
AirportsModel apModel;
QVariantMap parameters;
parameters[QStringLiteral("esri.useragent")] = QStringLiteral("Générateur Simplifié de Plans de Vol");
model.readFromCSV(QCoreApplication::applicationDirPath() + "/files/Waypoints.txt");
apModel.readFromTXT(QCoreApplication::applicationDirPath() + "/files/Airports.txt");
WaypointsFilter proxyModel(&model);
QQmlApplicationEngine engine;
engine.addImportPath(QStringLiteral(":/imports"));
engine.rootContext()->setContextProperty("waypointsFilter", &proxyModel);
engine.rootContext()->setContextProperty("airportsModel", &apModel);
engine.load(QUrl(QLatin1String("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
QObject::connect(&engine, SIGNAL(quit()), qApp, SLOT(quit()));
QObject *item = engine.rootObjects().first();
Q_ASSERT(item);
// The crash occurs after this line is executed
QMetaObject::invokeMethod(item, "initializeProviders",
Q_ARG(QVariant, QVariant::fromValue(parameters)));
return app.exec();
}
EDIT2
Here is snippet of the faulty code :
function getPlugins()
{
//crash is here !
var plugin = Qt.createQmlObject ('import QtLocation 5.6; Plugin {}', mainWindow)
var myArray = new Array()
for (var i = 0; i<plugin.availableServiceProviders.length; i++) {
var tempPlugin = Qt.createQmlObject ('import QtLocation 5.6; Plugin {name: "' + plugin.availableServiceProviders[i]+ '"}', mainWindow)
if (tempPlugin.supportsMapping()
&& !(tempPlugin.name === "itemsoverlay")
&& !(tempPlugin.name === "here")
&& !(tempPlugin.name === "mapbox")
&& !(tempPlugin.name === "mapboxgl"))
myArray.push(tempPlugin.name)
}
myArray.sort()
return myArray
}
function initializeProviders(pluginParameters)
{
var parameters = new Array()
for (var prop in pluginParameters){
var parameter = Qt.createQmlObject('import QtLocation 5.6; PluginParameter{ name: "'+ prop + '"; value: "' + pluginParameters[prop]+'"}',mainWindow)
console.log ("plugin name :" + prop + "value : " +pluginParameters[prop] )
parameters.push(parameter)
}
mainWindow.parameters = parameters
var plugins = getPlugins()
mainMenu.providerMenu.createMenu(plugins)
for (var i = 0; i<plugins.length; i++) {
if (plugins[i] === "esri")
mainMenu.selectProvider(plugins[i]) //Génère la création de la carte par déclenchement de onSelectProvider
}
}
My concern is this warning : section .gnu_debuglink not found
Why this section is not found into the .exe.debug file ?
Here is the status of debugging just before crash :
and after crash :
.gnu_debuglink is a mechanism that gdb uses to relate the separate debug info to the actual binary. It might be related to the crash caused by plugin loading or gdb might just inform it related to some other plugin being loaded.
I suspect your problem could be related to OOM caused by a bug in Qt which will be fixed in Qt 5.9.5. Meanwhile, you could test if stripping the qtgeoservices_mapboxgld.dll file prevents the crash (that was said in the bugreport comments).
Also, to make your code more robust you should catch exceptions from Qt.createQmlObject because if plugin loading fails it throws error:
try {
var newObject = Qt.createQmlObject('import QtLocation 5.6; ...);
} catch (error) {
console.log ("Error loading QML : ")
for (var i = 0; i < error.qmlErrors.length; i++) {
console.log("lineNumber: " + error.qmlErrors[i].lineNumber)
console.log("columnNumber: " + error.qmlErrors[i].columnNumber)
console.log("fileName: " + error.qmlErrors[i].fileName)
console.log("message: " + error.qmlErrors[i].message)
}
}
"Invalid parameter passed to C runtime function." warning messages a probably caused by Qt calling some C runtime functions when the above mentioned bug hits.
Generic solution for tracking "Invalid parameter passed to C runtime function." origins has been provided by Dennis Yurichev. Below, I provide you steps how to do it (paths from my env).
QML:
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
function initializeProviders(anObject) {
for (var prop in anObject) {
console.log("Object item:", prop, "=", anObject[prop])
}
}
Text {
id: textLabel
anchors.centerIn: parent
text: qsTr("text")
}
}
C++:
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
QVariantMap parameters;
parameters[QStringLiteral("esri.useragent")] = QStringLiteral("Générateur Simplifié de Plans de Vol");
QObject *item = engine.rootObjects().first();
Q_ASSERT(item);
QMetaObject::invokeMethod(item, "initializeProviders",
Q_ARG(QVariant, QVariant::fromValue(parameters)));
// Generate error: file open fails
FILE *pFile = fopen (NULL,"w");
// fputs with invalid file displays in debug mode "Invalid parameter passed to C runtime function."
fputs("abc",pFile);
// fprintf with invalid file crashes the program
fprintf(pFile, "def\n");
return app.exec();
}
In command prompt:
C:\> SET PATH=%PATH%;C:\Qt\5.9.4\mingw53_32\bin
C:\> cd proj\build-quickTest-Desktop_Qt_5_9_4_MinGW_32bit-Debug\debug
C:\> C:\Qt\Tools\mingw530_32\bin\gdb quickTest.exe
(gdb) break OutputDebugStringA
Function "OutputDebugStringA" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (OutputDebugStringA) pending.
(gdb) r
when it breaks print the backtrace
(gdb) bt
<backtrace...>
(gdb) c
Continuing.
warning: QML debugging is enabled. Only use this in a safe environment.
(gdb) bt
<backtrace...>
(gdb) c
Continuing.
warning: qml: Object item: esri.useragent = Générateur Simplifié de Plans de Vol
Breakpoint 1, 0x74d535fc in OutputDebugStringA ()
from C:\Windows\syswow64\KernelBase.dll
(gdb) bt
#0 0x74d535fc in OutputDebugStringA ()
from C:\Windows\syswow64\KernelBase.dll
#1 0x754569c4 in msvcrt!_chkesp () from C:\Windows\syswow64\msvcrt.dll
#2 0x754569d0 in msvcrt!_chkesp () from C:\Windows\syswow64\msvcrt.dll
#3 0x00010001 in ?? ()
#4 0x7543b9b7 in msvcrt!_ftol2_sse_excpt ()
from C:\Windows\syswow64\msvcrt.dll
#5 0x00000000 in ?? ()
(gdb) c
Continuing.
warning: Invalid parameter passed to C runtime function.
Program received signal SIGSEGV, Segmentation fault.
0x770a2302 in ntdll!RtlEnterCriticalSection ()
from C:\Windows\SysWOW64\ntdll.dll
(gdb) bt
#0 0x770a2302 in ntdll!RtlEnterCriticalSection ()
from C:\Windows\SysWOW64\ntdll.dll
#1 0x004080b7 in _lock_file ()
#2 0x00402fe1 in __mingw_vfprintf ()
#3 0x00401656 in fprintf (__stream=0x0,
__format=0x40b1fa <qMain(int, char**)::{lambda()#3}::operator()() const::qst
ring_literal+154> "def\n")
at C:/Qt/Tools/mingw530_32/i686-w64-mingw32/include/stdio.h:289
#4 0x00401b2d in qMain (argc=1, argv=argv#entry=0x21319038)
at ..\quickTest\main.cpp:32
#5 0x00402f05 in WinMain#16 () at qtmain_win.cpp:104
#6 0x0040949d in main ()
(gdb)
We can see that fprintf is called with __stream=0x0 which causes the segfault.
Edit:
I did some testing with mapviewer example. When I ran it in debug mode:
Debugging starts
Invalid parameter passed to C runtime function.
Invalid parameter passed to C runtime function.
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
QMutex: destroying locked mutex
Debugging has finished
Then I stripped qtgeoservices_mapboxgld.dll:
C:\...> SET PATH=C:\Qt\5.9.4\mingw53_32\bin;%PATH%
C:\...> cd C:\Qt\5.9.4\mingw53_32\plugins\geoservices
C:\...> strip qtgeoservices_mapboxgld.dll
After stripping running in debug mode succeeded:
qml: initializeProviders: osm.useragent = QtLocation Mapviewer example
qml: getPlugins: esri
qml: getPlugins: pushing esri
qml: getPlugins: mapbox
qml: getPlugins: pushing mapbox
qml: getPlugins: mapboxgl
qml: getPlugins: pushing mapboxgl
qml: getPlugins: here
qml: getPlugins: pushing here
qml: getPlugins: itemsoverlay
qml: getPlugins: pushing itemsoverlay
qml: getPlugins: osm
qml: getPlugins: pushing osm
This way you should at least get forward in your app bug hunting.
Which Qt and mingw version are you using?
I developed an application along the lines of the SQL Browser example provided with QT in the Demos and Examples section. My development machine is Windows XP (visual studio compiler was used) and the application works well on it. It is able to connect to an external database (MySQL), and I am able browse through tables. I used the QODBC driver for connections. However when I deploy the executable (with all required .dll files) in another computer without QT, it says that I need to provide for the database drivers. I read the documentation and realized that I need to build a PlugIn for QODBC drivers.
First I looked at an example Plugin (Echo Plugin Example) given at http://doc.qt.digia.com/4.6/tools-echoplugin.html. Then I followed the instructions in http://doc.qt.digia.com/4.6/sql-driver.html#qodbc.
cd %QTDIR%\src\plugins\sqldrivers\odbc
qmake odbc.pro
nmake
The above commands built qsqlodbc4.dll. However, I am not successful in developing a Plugin for my application. Here are my steps, and the compilation output:
Created project odbcplugin.pro (see script below) under directory /odbcpluginTest
TEMPLATE = subdirs
SUBDIRS = sqlbrowser \
odbc
CONFIG += release
# install
target.path = $$PWD
sources.path = $$PWD
sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS
INSTALLS += target sources
Created subdirectories: /odbc, /sqlbrowser, /plugins
Inside the directroy /odbcpluginTest /odbc/
(i). Copied odbc.pro and suitably modified the paths and file names (for example, a file originally named as main.cpp has been renamed as mainODBC.cpp to avoid confusing with the file named main.cpp inside /sqlbrowser). See the scripts below:
TEMPLATE = lib
INCLUDEPATH += ../sqlbrowser
SOURCES = mainODBC.cpp
TARGET = qsqlodbc
DESTDIR = ../plugins
CONFIG += release
include(qsql_odbc.pri)
include(qsqldriverbase.pri)
sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS
INSTALLS += target sources
(ii). The file odbcinterface.h that describes the plugin interface is included as a header in odbc.pro. However, it is actually placed inside the directory /sqlbrowser. Hence, the line INCLUDEPATH += ../sqlbrowser is included in the above script.
(iii). Also, copied all related project files (qsql_odbc.pri, qsqldriverbase.pri, qpluginbase.pri, qt_targets.pri). Suitably modified the paths in all project files (there may be mistakes in here).
(iv). The header (qsql_odbc.h) and source (qsql_odbc.cpp) files of qsql_odbc.pri have also been copied.
Inside the directory /odbcpluginTest /sqlbrowser/
(i). Copied sqlbrowser.pro and all related files.
(ii). Created the header file odbcinterface.h that describes the plugin interface (see below) and added it to the HEADERS in sqlbrowser.pro.
#ifndef ODBCINTERFACE_H
#define ODBCINTERFACE_H
#include <QString>
#include <QtSql/qsqldriver.h>
class OdbcInterface
{
public:
virtual ~OdbcInterface() {}
virtual QSqlDriver* create(const QString &) = 0;
virtual QStringList keys() const = 0;
};
QT_BEGIN_NAMESPACE
Q_DECLARE_INTERFACE(OdbcInterface,
"developed similar to com.trolltech.Plugin.EchoInterface/1.0");
QT_END_NAMESPACE
#endif // ODBCINTERFACE_H
iii. Also, modified the browser.h file by adding the lines
#include "odbcinterface.h"
private:
bool loadPlugin();
OdbcInterface *odbcInterface;
Public:
void TestCase1();
iv. Also, modified the browser.cpp file by adding the function definitions:
bool Browser::loadPlugin()
{
QDir pluginsDir(qApp->applicationDirPath());
#if defined(Q_OS_WIN)
pluginsDir.cdUp();
pluginsDir.cdUp();
#endif
pluginsDir.cd("plugins");
foreach (QString fileName, pluginsDir.entryList(QDir::Files)) {
QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName));
QObject *pluginI = pluginLoader.instance();
if (pluginI) {
odbcInterface = qobject_cast<OdbcInterface *>(pluginI);
if (odbcInterface)
return true;
}
}
return false;
}
void Browser::TestCase1()
{
loadPlugin();
QStringList list;
list = odbcInterface->keys();
QMessageBox msgBox;
if(list.length() >0)
{
msgBox.setText("Test1 success");
}
else
{
msgBox.setText("Test1 failure");
}
msgBox.exec();
}
Testing:
In browser.cpp file, the constructor Browser::Browser(QWidget *parent) was modified by appending a call to void Browser::TestCase1()
Compile Output:
15:09:18: Running build steps for project odbcplugin...
15:09:18: Configuration unchanged, skipping qmake step.
15:09:18: Starting: "C:\QtSDK\QtCreator\bin\jom.exe"
cd sqlbrowser\ && C:\QtSDK\QtCreator\bin\jom.exe -nologo -j 2 -f Makefile
C:\QtSDK\QtCreator\bin\jom.exe -nologo -j 2 -f Makefile.Debug
cd odbc\ && C:\QtSDK\QtCreator\bin\jom.exe -nologo -j 2 -f Makefile
C:\QtSDK\QtCreator\bin\jom.exe -nologo -j 2 -f Makefile.Release
link /LIBPATH:"c:\QtSDK\Desktop\Qt\4.8.1\msvc2010\lib" /NOLOGO /DYNAMICBASE /NXCOMPAT /INCREMENTAL:NO /DLL /MANIFEST /MANIFESTFILE:"release\qsqlodbc.intermediate.manifest" /VERSION:4.81 /OUT:..\plugins\qsqlodbc4.dll #C:\DOCUME~1\SHAINE~1\LOCALS~1\Temp\qsqlodbc4.dll.5076.0.jom
Creating library ..\plugins\qsqlodbc4.lib and object ..\plugins\qsqlodbc4.exp
mainODBC.obj : error LNK2001: unresolved external symbol "public: virtual struct QMetaObject const * __thiscall QODBCDriverPlugin::metaObject(void)const " (?metaObject#QODBCDriverPlugin##UBEPBUQMetaObject##XZ)
mainODBC.obj : error LNK2001: unresolved external symbol "public: virtual void * __thiscall QODBCDriverPlugin::qt_metacast(char const *)" (?qt_metacast#QODBCDriverPlugin##UAEPAXPBD#Z)
mainODBC.obj : error LNK2001: unresolved external symbol "public: virtual int __thiscall QODBCDriverPlugin::qt_metacall(enum QMetaObject::Call,int,void * *)" (?qt_metacall#QODBCDriverPlugin##UAEHW4Call#QMetaObject##HPAPAX#Z)
..\plugins\qsqlodbc4.dll : fatal error LNK1120: 3 unresolved externals
jom 1.0.6 - empower your cores
command failed with exit code 1120
command failed with exit code 2
command failed with exit code 2
15:09:19: The process "C:\QtSDK\QtCreator\bin\jom.exe" exited with code 2.
Error while building project odbcplugin (target: Desktop)
When executing build step 'Make'
Greetings all,
I am trying to implement a QT Plugin with CMake. But this "Q_EXPORT_PLUGIN2" directive stops my class from compiling. I can compile the plugin if I commented this out,but it won't work as a plugin if I do so.
QT doc says:
Q_EXPORT_PLUGIN2 ( PluginName, ClassName )
The value of PluginName should
correspond to the TARGET specified in
the plugin's project file
What about in CMake case? What should be the value for 'PluginName'?
Here is my Plugin Interface :
#ifndef RZPLUGIN3DVIEWERFACTORY_H_
#define RZPLUGIN3DVIEWERFACTORY_H_
#include <QObject>
#include "plugin/IRzPluginFactory.h"
class RzPlugin3DViewerFactory :public QObject,public IRzPluginFactory{
Q_OBJECT
Q_INTERFACES(IRzPluginFactory)
private:
QString uid;
public:
RzPlugin3DViewerFactory();
virtual ~RzPlugin3DViewerFactory();
IRzPlugin* createPluginInstance();
IRzPluginContext* createPluginContextInstance();
QString & getPluginUID();
};
#endif /* RZPLUGIN3DVIEWERFACTORY_H_ */
And implementation
#include "RzPlugin3DViewerFactory.h"
#include "RzPlugin3DViewer.h"
RzPlugin3DViewerFactory::RzPlugin3DViewerFactory() {
uid.append("RzPlugin3DView");
}
RzPlugin3DViewerFactory::~RzPlugin3DViewerFactory() {
// TODO Auto-generated destructor stub
}
IRzPlugin* RzPlugin3DViewerFactory::createPluginInstance(){
RzPlugin3DViewer *p=new RzPlugin3DViewer;
return p;
}
IRzPluginContext* RzPlugin3DViewerFactory::createPluginContextInstance()
{
return NULL;
}
QString & RzPlugin3DViewerFactory::getPluginUID()
{
return uid;
}
Q_EXPORT_PLUGIN2(pnp_extrafilters, RzPlugin3DViewerFactory)
Error Message is :
[ 12%] Building CXX object
CMakeFiles/RzDL3DView.dir/RzPlugin3DViewerFactory.cpp
.obj
C:\svn\osaka3d\trunk\osaka3d\rinzo-platform\src\dlplugins\threedviewer\RzPlugin3
DViewerFactory.cpp:36: error: expected
constructor, destructor, or type
conversi on before '(' token make[2]:
*** [CMakeFiles/RzDL3DView.dir/RzPlugin3DViewerFactory.cpp.obj]
Error 1
make[1]: *
[CMakeFiles/RzDL3DView.dir/all] Error
2 make: * [all] Error 2
Ok , I fixed the problem by giving the project name specified in Cmake file.
PROJECT (RinzoDLPlugin3DViewer CXX C)
So,now in CPP file its
Q_EXPORT_PLUGIN2(RinzoDLPlugin3DViewer , RzPlugin3DViewerFactory)
and included qpluginh.h
#include <qplugin.h>
I think the macro should be Q_EXPORT_PLUGIN2(pnp_rzplugin3dviewerfactory, RzPlugin3DViewerFactory) or whatever you have listed as the target name in the .pro file. In fact, the "pnp" part stands for "Plug & Paint" which is the Qt demo program for writing plugins :)
Edit:
Since I misunderstood how CMake works, this information isn't really relevant to the OP. I did do a quick search however and turned up this discussion of Qt, plugins and CMake. I hope there is some useful info there.
http://lists.trolltech.com/qt-interest/2007-05/msg00506.html