Deploy Qt5 QML application - qt

To test QML deployment I've created a very simple QML application. Here is the code:
main.cpp
#include <QApplication>
#include <QQmlApplicationEngine>
#include <QFile>
int main(int argc, char **argv) {
QApplication app(argc, argv);
QQmlApplicationEngine engine;
QString path = app.applicationDirPath() + "/qml/main.qml";
if(QFile::exists(path))
engine.load(path);
else {
return 1;
}
return app.exec();
}
main.qml
import QtQuick 2.2
import QtQuick.Controls 1.2
ApplicationWindow {
id: mainWindow
title: "Test window"
width: 800
height: 600
visible: true
}
To be sure no development library was installed in the system, I've set up a virtual machine with a pure Windows XP installation. Then, I've followed instructions as described here and copied all Qt5*.dll into the program directory, as well as platforms/qwindows.dll and icu*52.dll. Dependency Walker confirmed that no broken dependencies were left, i.e. everything should have been correctly set up.
However, for some reasons, when I run my app I see nothing. Neither a window, nor an error message. Running from console also gives me no error. Despite this, I can see my app running in the Task manager, like it is running in background. Running the app on the development machine goes without problem: the app correctly starts and I can see its windows.
What am I doing wrong? How can I deploy a QML app to be sure it will work on any other - non development - machine?

If you use MinGW, then try to copy all folders from folders qml and plugins to directory with your program. Also copy libraries: icudt52.dll, icuin52.dll, icuuc52.dll, libgcc_s_dw2-1.dll, libstdc++-6.dll, libwinpthread-1.dll, Qt5Core.dll, Qt5Gui.dll, Qt5Network.dll, Qt5Qml.dll, Qt5Quick.dll, Qt5Svg.dll, Qt5Widgets.dll from bin
Eventually the directory will look like this:
Enginio
imageformats
platforms
Qt
QtGraphicalEffects
QtPositioning
QtQml
QtQuick
QtQuick.2
QtSensors
QtWebKit
QtWinExtras
icudt52.dll
icuin52.dll
icuuc52.dll
libgcc_s_dw2-1.dll
libstdc++-6.dll
libwinpthread-1.dll
Qt5Core.dll
Qt5Gui.dll
Qt5Network.dll
Qt5Qml.dll
Qt5Quick.dll
Qt5Svg.dll
Qt5Widgets.dll
YOUR_PROGRAM.exe
This way works on WindowsXP/Win7 where Qt was not installed.

This what i've figured out so far,
You can't just open a qml file in main.cpp, you have to put those qmls into a resource
qml.qrc:
<RCC>
<qresource prefix="/">
<file>main.qml</file>
</qresource>
</RCC>
Then main.cpp must load it from the resource
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
then build and check it works, then deploy as follows:
locate the releasse directory where your EXE lives
locate the directory where your QML lives
create a directory somewhere, say, deploy
then
cd deploy
windeployqt --release --qmldir <qml-dir-location> <exe-location>
NOTE: add location of windeployqt to PATH
eg. C:\Qt\Qt5.5.1\5.5\msvc2013\bin

You should use the deployment tool that comes with Qt. See Qt for Windows - Deployment, there is a section "the Windows deployment tool".

As mentioned by BaCaRoZzo, a general solution that worked pretty well for me is to follow this guide.
To sum it up, copy in an empty directory:
The release version of MyApp.exe, along with .dll you created for this projet
All the .dll files from \mingw48_32\bin\
All the folders from \mingw48_32\plugins\
(If you used QML) All the folders from \mingw48_32\qml\
First, during the test of your application, rename your qt folder so it is not found by $PATH, and double-click on MyApp.exe. This should run the program.
NB: It leads to a very big application, so you will need to delete some extra files and folders.
The easiest way is for the dll: you run the program, and while being run, you delete all the dll in your new project. Only the ones that are not used by MyApp.exe will be deleted. Efficient!
For the Qt folders, proceed by trials and errors.

You need to deploy the application, for this purpose I use the utility
cqtdeployer
This utility itself collects all the necessary dependencies of your application and you do not have to spend your time on it, or you can automate this process.
You can install from github releases (Windows)
or
from snapstore (Linux)
sudo snap install cqtdeployer
You can use as follows:
Windows:
%cqtdeployer% -bin myApp -qmake path/to/Qt/5.x.x/build/bin/qmake.exe -qmlDir path/to/my/qml/files/dir
Linux:
cqtdeployer -bin myApp -qmake path/to/Qt/5.x.x/build/bin/qmake -qmlDir path/to/my/qml/files/dir
path/to/Qt/5.x.x/build/bin/qmake - This is the way qmake is used to build your program.
path/to/my/qml/files/dir - this is the path directly to your qml file (which you wrote)
And Run application with sh script (Linux) or exe (Windows)
If you'll use the version from snap then make sure that you have all the permissions.
If you need use windows version just install application from installer

use windeployqt --qmldir f:\myApp\sources f:\build-myApp\myApp.exe command.
the first argument after qmldir is your qml folder location and the second argument is where your exe is placed. You would get deployable exe on any env.

For me this answer worked for a QtQuick 2 application (QML app), but I'm adding more details:
Build inside Qt as Release
Find the folder in the file explorer with the executable, usually on a sibling folder to your project folder
Copy executable to an empty folder
Start Qt CMD tool (mine is ), go to the folder with the executable and run:
windeployqt --release --qmldir C:\Qt\5.15.1\msvc2015_64\qml executable.exe
(change 5.15.1\msvc2015_64 for yours)

My answer was:
(1) On Qt Framework set the Release mode for my Application.
(2) After: Project -> Build directory and set a empty directory in the "C:/" folder (I'm development Windows 10). Example: My Folder: "Release" with subfolder "My_app", so the Build directory is "C:/Release/My_app"
(3) Click on "Start debuggin of the startup project"
(4) Create another folder on "C:/" directory (in my case callet "Executable" with subfolder "My_app").
(5) Copy "My_app.exe" of the folder "Release/My_app/release" to "C:/Executable/My_app").
(6) Open Qt mingw.
(7) On the terminal of the Qt MinGw go to folder "Release/My_app/release" through command "cd C:/Executable/My_app"
(8) Run the command "windeploy.exe My_app.exe --qmldir 'full_path_where_are_the_qml_files'" (e.g.: "C:/My_prj/qmlsource", where qmlsource is folder with my qml_files).
This generate all files to run My_app.exe. Just the copy all folder (My_prj folder).

Related

Qt6 qt_generate_deploy_app_script plugin DLL copying

Currently I have to manually copy the platforms and imageformats plugin folders to the directory containing the .exe that MSVC compiled. This is very tedious as the output folders often get deleted if you're working on your CMakeLists.txt or changing compilation target.
Now qt_generate_deploy_app_script seems like an official Qt solution to solve this problem, but it does not work.
I have added the CMake bits to my CMakeLists.txt as stated
qt_generate_deploy_app_script(
TARGET HiveWE
FILENAME_VARIABLE deploy_script
NO_UNSUPPORTED_PLATFORM_ERROR
)
install(SCRIPT ${deploy_script})
I can see some generated deploy scripts appear under build\x64-RelWithDebInfo\.qt, but they do not seem to be run as no DLL folders get copied to where my .exe is.
Am I misinterpreting what qt_generate_deploy_app_script should do or is it simply broken?
If you want to Creat exe in windows From Qt project you should use windeployqt
To Deploy and create Exe output with QT in windows you should follow this way:
put your compiler path in your system path. for example, if you use mingw81_64, you should set it. something like Qt/tools/mingw81_64/bin
copy exe file that provides after building in release mode in one
folder and run mingw81_64 cmd (it has separate cmd) and cd to that
folder path
windeployqt app.exe
you are using Cmake So first create one release output and then use step 3.
This command will get all dll needs for your app and your exe will work .
if you use qml
windeployqt --qmldir (the path of its directory ) app.exe
and also see these youtube videos for more info:
https://www.youtube.com/watch?v=LdSTgR0xJco
https://www.youtube.com/watch?v=hCXAgB6y8eA

Building Qt Qml Plugin using CMake

I want to compile Qt Qml Plugin using CMake (instead of QMake) and add this plugin to the some application. Plugin and application script should be in separate CMakeLists.txt.
File structure:
CMakeLists.txt
main.cpp
main.qml
qml.qrc
plugin/
CMakeLists.txt
MyItem.cpp
MyItem.h
Plugin.h
qmldir
I have a script plugin/CMakeLists.txt that generates libmyplugin.dylib and qmldir and put it to the plugin/MyPlugin subfolder of plugin binary dir:
plugin/CMakeLists.txt:
cmake_minimum_required(VERSION 3.8)
add_library(myplugin SHARED
Item.cpp
Item.h
Plugin.h
)
set_target_properties(myplugin PROPERTIES
AUTOMOC TRUE
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/package/MyPlugin
)
# Copy qmldir file
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/package/MyPlugin/qmldir
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/qmldir
COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/qmldir" "${CMAKE_CURRENT_BINARY_DIR}/package/MyPlugin/qmldir"
COMMENT "Copy qmldir"
)
target_sources(myplugin PRIVATE
${CMAKE_CURRENT_BINARY_DIR}/package/MyPlugin/qmldir
)
find_package(Qt5 REQUIRED COMPONENTS Core Qml Quick)
target_link_libraries(viewWorld PUBLIC Qt5::Core Qt5::Qml Qt5::Quick)
Now I need to build myplugin target before/after app target and copy plugin files from <myplugin binary dir>/plugin into location of app target binary (in case of Windows and Linux) or into <app bundle>/Contents/PlugIns (in case of macOS):
CMakeLists.txt:
cmake_minimum_required(VERSION 3.8)
add_executable(app
main.cpp
qml.qrc
)
set_target_properties(app PROPERTIES
AUTORCC TRUE
)
add_subdirectory(plugin)
add_dependencies(app plugin)
# Needs to copy plugin files...
find_package(Qt5 REQUIRED COMPONENTS Core Qml Quick)
target_link_libraries(viewWorld PUBLIC Qt5::Core Qt5::Qml Qt5::Quick)
I need to copy plugin files only if they changed. It would be great to write function that will take app target and plugin target and create appropriate dependencies.
For my Qt projects and qml plugins I using next rules. It's actual for win platform, but I hope it will be helpfull for your macOS
Output directory is same for all projects:
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
So all sub_directories with CMakeLists and it's project targets will build into same directory. It's helpfull for project running and finnaly deploying.
Qml plugins I copy to directory
set_target_properties(targetProject PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin/$<CONFIG>/plugins/${QmlPluginName}/)
After build qml plugin I'm copy qmldir file to RUNTIME_OUTPUT_DIRECTORY
add_custom_command(TARGET ${targetProject} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy
${QML_DIR_FILE}
${CMAKE_BINARY_DIR}/bin/$<CONFIG>/plugins/${QmlPluginName}/qmldir)
After this steps I had hext directory structure:
/build_dir/bin/Debug/
|application.exe
|plugins/
| |QmlPluginName/
| | |qmldir
| | |QmlPluginName.dll
So after this steps don't forget about:
QQmlApplicationEngine engine;
engine.addImportPath("./plugins");
P.S. sorry for my English

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

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

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.

QtCreator's code completion doesn't work for Qt libs

When trying to work in QtCreator, there is a problem with code completion for Qt libs. QtCreator says that it can't find Qt headers, so no code completion for them. I.e. if I write #include <QPainter> or #include <QtGui/QPainter> this line gets underlined with message No such file or directory.
But nevertheless compilation process works flawlessly. So, qmake finds everything correctly and the problem is in the QtCreator. Also, code completion works normally for all own files (created for project).
We've tried numerous fixes including reinstalling Qt twice, trying to mangle with qt.conf in QtCreator's dir, tried to find qmake.cache, searching the registry and googled a lot. We're using QtSdk 1.1 with bundled QtCreator 2.2.1 under Windows Vista, installed in the default location.
There is dirty solution to write path in .pro file, but we don't want to use it.
Choose one of the following files
Qt_install/mkspecs/common/your_os.conf
or
Qt_install/mkspecs/common/your_compiler.conf
By Qt_install I mean the directory where Qt is installed (not qt creator), e.g. C:\Qt\Qt 4.7.4\ and your_compiler should be mingw I guess (don't have a windows install).
In the .conf file, add the line with the path you added in your .pro, something like:
INCLUDEPATH += path1 path2 ...
The mkspecs files are implicitly included in all your .pro so code completion will work in all your projects.

Resources