Use a precompiled plugin (via a shared library) in a QML application - qt

I have a QML plugin compiled (to a .so) by another project. I want to re-use this in my own QML application without re-building it each time. I want to copy the .so over and, with minimal additional code, be able to write:
import QQuickMapboxGL 1.0
at the top of my QML files and have it work.
Where do I need to copy the .so in my QML project, and how do I need to add it to the project so that the QML runtime can find it?
What I've tried:
Create a QQuickMapboxGL directory with libqmapboxgl.so in it.
Create a qmldir file in that directory with the contents:
plugin qmapboxgl
Add the following to my .pro file:
INSTALL_DIR = $$PWD/../install
target.path = $$INSTALL_DIR
# Copy the QQuickMapboxGL folder to the install directory
plugin.files = QQuickMapboxGL/*
plugin.path = $$INSTALL_DIR/QQuickMapboxGL
INSTALLS += target plugin
Add a make install build step.
The result of this mad hackery was:
plugin cannot be loaded for module "QQuickMapboxGL": Plugin verification data mismatch in '/my/build/QQuickMapboxGL/libqmapboxgl.so'
I have verified that the plugin and my application are both being compiled with the same version of g++ (g++-5 (Ubuntu 5.4.1-2ubuntu1~14.04) 5.4.1 20160904) and the same Qt download (5.7.0).

The main problem is that the .so is not a QML Plugin; no class inherits from QQmlExtensionPlugin or related. It is just a shared library of code.
Was able to workaround this by:
Adding the header files for MapboxGL to my project
In my main.cpp:
#include "3rdparty/mapbox-gl-native/platform/qt/include/qmapbox.hpp"
Calling QMapbox::registerTypes(); (inside main)
Copying libmapboxgl.so (built via Mapbox's make/cmake) inside a libs directory.
In myproject.pro adding: LIBS += -L./libs -lqmapboxgl
In my QML code import QQuickMapboxGL 1.0 and then using MapboxMap
Copying libmapboxgl.so to somewhere that is referenced by LD_LIBRARY_PATH

Related

Link dynamically against Public\Qt inside ocean

Using Petrel 2016.1
Libraries reference:
https://www.ocean.slb.com/~/media/files/testing%20plug%20ins/libraries/petrel_2016-1_3rd_party_libraries.html
My plugin uses Qt for a window and some plots with qwt. I would like to link against the Qt dlls present at Petrel\Public\Qt to save some space while deploying the app and because is not possible to deploy libs already present in Petrel as public libs by policy.
I've successfully linked with the same Qt version over there. The problem is that PluginPackager.exe does not see the libs. I've tried editing PluginPackager.exe.config inside Petrel dir to include Public\Qt, copied it to the Release folder, copied it to the main project folder and every dir that I may suspect PluginPackager.exe is looking for this file but nothing seems to cause any effect.
I've copied the Qt dlls to the Release folder, so PluginPackager.exe could see them and register the Plugin. It works, even if I delete the Qt dlls from the Release folder afterwards. Petrel is loading them from Public\Qt. The problem is that when I try to open the Qt window, a message saying that Qt failed to load plugin windows.
I figured that it is related to qwindows.dll, which is inside Public\Qt\plugins\platforms. If I set the environment variable QT_QPA_PLATFORM_PLUGIN_PATH to C:..\petrel...\Public\Qt\plugins\platforms, it works fine. I've tried to use addLibraryPath() from QApplication with no success.
I guess we have everything we need inside Public\Qt, but for some reason Petrel is not finding it. Two questions, then:
1- How to make PluginPackager to see all the libs inside Public\Qt?
2- How to make my application to find qwindows.dll?
Plugin has code in C#, C++ cli and C++
EDIT 1:
Ok, for Q.2 I've found a solution by trial and error.
QString path = QDir::currentPath();
QString finalPath = QDir(path).filePath("Public/Qt/plugins");
QApplication::addLibraryPath(finalPath);
This will add the plugins dir to the qt lib search path and does the trick. I hope I can deploy using this.
EDIT 2:
For Q.1
I realize now that the PluginPackager only sees things inside the Extensions folder. The problem was that, in my opinion, the folder name Public is misleading. This led me to think that all libs inside that folder could be used by developers freely. The Ocean guide states that all libs other than the ones inside Extensions are considered internal libs:
The PluginPackager.exe assumes that files in the Petrel installation directory tree other than those in the Extensions folder are internal Petrel libraries.
Well, why name a folder Public if all the libs inside it are internal? This is really confusing. Besides, the Slb.Ocean libs inside the Public folders are Ok to use, the others are not? As PluginPackager.exe.config has Public\ but not the folders inside it.

Use dynamic library in dynamic library

I am always using QDesignerCustomWidgetInteface. I want to use two kinds of CustomWidget in another CustomWidget to combine two of them so that I need not to write some codes again.
So I write codes as below in project file:
LIBS +=-L./debug -lxzquxianplugin
LIBS +=-L./debug -lxzyctextplugin
When I finished the code I debug the codes in creator and started debugging designer. Designer ran well and recognized my new CustomWidget. But when I entered bin/gcc/debug folder and ran executable app Designer that debug mode produced directly without codes and Qt creator, Designer showed that could not find shared library: libxzquxianplugin.so.
I tried to use codes as below:
Debug {
LIBS +=absolute path way of xzquxianplugin
LIBS +=absolute path way of xzyctextplugin
}
But it still failed to find dynamic library when I ran Designer in debug folders. I cannot understand why it happened.
the libs -L switch is used when you want to add a directory to linker search path, you used:
LIBS +=-L. /debug -lxzquxianplugin
Which actually breaks your path because of the space after -L.
So you should have
LIBS +=-L./debug -lxzquxianplugin
given that your lib exists under debug folder.

Configuring Qt builds with Jenkins

I have several Qt projects that are dependent upon a Qt library that I've developed.
The project files (.pro) for projects which use the library define the LIBS and PRE_TARGETDEPS paths. For example: -
PRE_TARGETDEPS += ../ProjectLibrary_Qt_5_2_1_clang_64bit-Debug/projectlibrary.dylib
LIBS += -L../ProjectLibrary_Qt_5_2_1_clang_64bit-Debug -lProjectLibrary
As you can see, there is a defined path to the linked library and they have been building with Shadow Builds, via Qt Creator. The file hierarchy is like this: -
Projects
ProjectLibrary_Qt_5_2_1_clang_64bit-Debug
ProjectLib.dylib (the built library)
DependentProject
DependentProject.pro
(dylib is an OSX extension, but it could equally be .lib for Windows, or .so for linux)
However, Jenkins creates a different folder structure:-
jobs
ProjectLib
workspace
Project.dylib
DependentProject
workspace
DependentProject.pro
Now there is an extra directory (workspace), which would need this reflected in the .pro file and the names of the folders are different.
Obviously, If I just call qmake on the .pro with a Jenkins build, the path to the library is going to be wrong.
So, do I need to create a separate .pro just to be able to reflect the paths when building with Jenkins, or is there another way to handle specifying the location of libraries in the project file, for Jenkins, without having to change the directory structures?
Solution 1) Based on your current build configration
Modify your .pro file like this :
isEmpty(PROJECT_PATH) {
PROJECT_PATH=../ProjectLibrary_Qt_5_2_1_clang_64bit-Debug
}
LIBS += -L$${PROJECT_PATH} -lProjectLibrary
Then in Jenkins , you should pass PROJECT_PATH={path to your project} to qmake
Solution 2)
Using git submodule to fetch ProjectLibrary as a part of your building project. Then you don't need to build the ProjectLibrary by Qt Creator manually.

What is the proper way of deploying C++ QML plugins on mobile device?

I've been playing a lot with the Box2D QML plugin and the things are looking really good.
However, I wanted to deploy my sample app on Android (SGS2), but I can't seem to get it work. Whether I try to run it on AVD or on the device, it doesn't work. androiddeployqt finishes successfully, but then I get "Unable to start 'MyApp'" and no other info as to why it failed to start. I can successfully run qml apps on the AVD and the device, but this has something to do with the plugin and I can't find any reference in order to solve it.
I tried setting up DEPLOYMENTFOLDERS in different ways, but if i get them wrong, then the whole thing fails. Even when I don't get an error, in which case I assume I got it right, it still doesn't start.
I've been struggling with this for quiet some time, and can't find any bit of useful information in order to resolve it.
If you know of any project that uses a c++ plugin and can be successfully deployed on android device, that would be good as well.
I am using Qt 5.2.0 compiled for android and the qt5 branch of box2d
We were getting "module not found" errors while we were trying to get our QML module working inside an Android Qt application. With Qt 5.3, we managed to get our QML plugin recognized only by deploying the plugin to the QT_INSTALL_QML directory where official Qt QML modules reside. This directory is /opt/Qt/5.3/android_armv7/qml in our case.
Plugin Side
Our .pro file for the plugin looks like:
TEMPLATE = lib
TARGET = prova
QT += qml quick multimedia
CONFIG += qt plugin c++11 console
CONFIG -= android_install
TARGET = $$qtLibraryTarget($$TARGET)
uri = com.mycompany.qmlcomponents
# Input
SOURCES += \
src1.cpp \
src2.cpp
HEADERS += \
src1.h \
src2.h
##The below is generated automatically by Qt Creator when you create a new "Qt Quick 2 Extension Plugin" project for Android
#Copies the qmldir file to the build directory
!equals(_PRO_FILE_PWD_, $$OUT_PWD) {
copy_qmldir.target = $$OUT_PWD/qmldir
copy_qmldir.depends = $$_PRO_FILE_PWD_/qmldir
copy_qmldir.commands = $(COPY_FILE) \"$$replace(copy_qmldir.depends, /, $$QMAKE_DIR_SEP)\" \"$$replace(copy_qmldir.target, /, $$QMAKE_DIR_SEP)\"
QMAKE_EXTRA_TARGETS += copy_qmldir
PRE_TARGETDEPS += $$copy_qmldir.target
}
#Copies the qmldir file and the built plugin .so to the QT_INSTALL_QML directory
qmldir.files = qmldir
unix {
installPath = $$[QT_INSTALL_QML]/$$replace(uri, \\., /)
qmldir.path = $$installPath
target.path = $$installPath
INSTALLS += target qmldir
}
Our qmldir (in the plugin source tree root) file is:
module com.mycompany.qmlcomponents
plugin prova
Application Side
The .pro file looks like:
TEMPLATE = app
QT += qml quick widgets multimedia
CONFIG+= console
SOURCES += main.cpp
RESOURCES += qml.qrc
# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =
# Default rules for deployment.
include(deployment.pri)
contains(ANDROID_TARGET_ARCH,armeabi-v7a) {
ANDROID_EXTRA_LIBS = \
/opt/Qt/5.3/android_armv7/qml/com/mycompany/qmlcomponents/libprova.so
}
Important Note: Any library that your qml plugin uses must also be listed in ANDROID_EXTRA_LIBS in order to be bundled into the apk. This includes Qt components as well, listing them in QT+= is not enough if you don't use them in your application.
We don't actually know if the inclusion of the extra libprova.so is necessary. It's most probably not.
The main.cpp looks like:
#include <QApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[]){
QApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:///main.qml")));
return app.exec();
}
The main.qml just includes the plugin like:
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtMultimedia 5.0
import com.mycompany.qmlcomponents 1.0
...
Building and Deployment
The way we build and deploy the plugin is to qmake (from the android-armv7 toolchain of Qt), then make install. It installs the qmldir file and the plugin .so to the QT_INSTALL_QML directory.
The way we build and deploy the project that uses the plugin is to qmake (again, from the android-armv7 toolchain of Qt), then make install INSTALL_ROOT=. (installs to build directory), then run androiddeployqt. The last command creates the Android project structure with the qmldirs in assets/ and libraries in libs/ and bundles the whole thing in an apk via ant. For the details of this procedure, refer to http://qt-project.org/wiki/Android.
In short, we were only able to get our QML plugin recognized inside an Android project by putting it inside the private Qt qml directory. I hope this helps in some way.

building with qmake on Linux - how to prevent qmake from linking to QtCore and QtGui

I have a shared library (with no QT dependency) [library B] that links to another shared library (with no QT dependence as well) [library A].
I am using Qmake and QT Creator 1.3. The problem is that when I build library B and run ldd on the executable, it is being linked to QtCore and QtGui, both of which are pulling in lots of unrequired files, resulting in an executable that is taking long to load, and has unwanted dependencies.
I have tried just about everything to stop qmake from linking these libraries to library B.
A snippet of my project file for library B is shown below:
TEMPLATE = lib
LIBS += -L../datelib/bin -ldatelib_release
QT -= gui core
LIBS -= -lQtGui -lQtCore
CONFIG += dll
CONFIG += debug_and_release
CONFIG(debug, debug|release) {
TARGET =targetnameD
}else {
TARGET = targetname
}
I am using QtCreator 3 on Ubuntu 9.10
QT is version 4.5.2
Put CONFIG -= qt in your .pro file.
You can try with
CONFIG += dll
QT -= gui core
LIBS -= -lQtGui -lQtCore
For apps, you do it like this:
TEMPLATE = app
CONFIG = console
More info here:
qmake common projects
I had similar problem.
What I did was to create new library project with out qtcore and qtgui. Removed all unnecessary files that was created by wizard. Added my files to project folder and modified the *.pro file. It started to work correctly.
It was some problem with QtCreator, it not read correctly .pro file generating .pro.user, witch QtCreator use to build, and wizard generate correct .pro.user file.
I did this with Qt 4.7
Wish this help.
As far as I know, Qt creator doesn't take the .pro configurations into consideration if you don't have them set up separately from the IDE.
You should go to the project's settings, clone the debug configuration, rename it release, set the QMake build configuration to release(!) and change other settings as you see fit. Then you can pick which configuration to build from the IDE.
P.S: Try using Qt Creator 1.3.1 as it fixes a lot of bugs and brings interesting new features.

Resources