Custom Qt on BlackBerry devices
This document describes approaches how to use a custom Qt build to BlackBerry 10 devices and use it for application development in Qt Creator or on the command line. See Using Qt Creator for Qt Development on BlackBerry 10 for overall description of using Qt Creator with BlackBerry 10 and Deployment on BlackBerry article for more details about deployment .
Extending the built-in Qt 4.8
BlackBerry 10 devices have built-in Qt 4.8 located in the /usr/lib/qt4/ folder. There is no need to setup anything in tooling if you use Qt4. Just create a new project and use a kit representing BlackBerry 10 with Qt4. Qt Creator 3.0 and later detects Qt4 in the BlackBerry 10 NDK and creates appropriate kits automatically. If you use an older version of Qt Creator you might need to create kits manually.
In an exceptional case you might decide to use a custom version of Qt4, you can use the remaining part of this page as a guidance. The major point to be aware of is that Qt4 uses the environment variable QML_IMPORT_PATH to point to the QML plugins and modules, instead of QML2_IMPORT_PATH in Qt5.
Adding a custom Qt build to Qt Creator
The below sections covers Qt5, but it is generally the same for any other Qt build. First, build Qt5 for your BlackBerry 10 device. Further, we will assume that your Qt5 build is installed in "$HOME/development/qnx/qt5" folder and and you used the BlackBerry 10 NDK target 10.2.0.1155 stored in "/opt/bbndk" folder.
Here are the steps how to add this build to Qt Creator:
- Setup the "Qt Version":
- Go to "Tools -> Options…-> Build & Run -> Qt Versions" tab
- Press "Add" button
- Browse qmake binary in your Qt5 build, e.g. $HOME/development/qnx/qt5/qtbase/bin/qmake
- Add a sensible name in the "Version name" field
- In the section "BlackBerry Native SDK", choose the directory with contains "host_" and "target_" folders which has been used for building Qt5 e.g. the /opt/bbndk folder.
- Press "OK" or "Apply" button
- Setup a kit for your Qt5 in Qt Creator:
- Go to "Tools-> Options… -> Build & Run-> Kits" tab
- Press "Add" button to create a new kit, fill its field as:
- Name - specify a sensible name for your kit. Consider reusing the name you gave to the "Qt Version" as above
- Select in " BlackBerry Device" in "Device type"
- Device - select a BlackBerry 10 device or simulator from the list which you previously connected and configured in Qt Creator
- In "Sysroot", se the path to the sysroot folder which starts with the "qnx6" folder within the "target_" folder that you have used for building Qt5 e.g. "/opt/bbndk/target_10_2_0_1155/qnx6/" folder
- Select "GCC BlacckBerry 10" compiler in the "Compiler" section that matches the one for BlackBerry 10 NDK Target used for building Qt5, e.g. "GCC BlackBerry 10 (target_10_2_0_1155)"
- The "Debugger" can keep the default value for for the "System GDB at /usr/bin/gdb" or also set to the debugger provided in the BlackBerry 10 NDK Target used for building Qt5
- Select the Qt5 build you added on the previous previous steps in "Qt-Version"
- The section "Qt mkspec" can stay empty when developing on a BlackBerry 10 device or should be be set to "blackberry-x86-qcc" when developing for BlackBerry 10 Simulator
- Press "OK" or "Apply" button
Now you can create a new project using "File -> New File or Project…-> Applications -> Qt Quick 2 Application (Built-in Types)" or "BlackBerry Qt 5 GUI Application" project template. In "Kit Selection" wizard page, select the kit registered above. When asked whether to create a BAR file descriptor, press "Yes".
Embedding a custom Qt build into a BlackBerry 10 application package
The bar-descriptor.xml file generated in the example at the end of the last section should contain the following or similar lines:
<env var="QML2_IMPORT_PATH" value="app/native/imports"/>
<env var="QT_PLUGIN_PATH" value="app/native/plugins"/>
<env var="LD_LIBRARY_PATH" value="app/native/lib"/>
<asset path="QT_INSTALL_LIBS">lib</asset>
<asset path="QT_INSTALL_PLUGINS">plugins</asset>
<asset path="QT_INSTALL_QML">imports</asset>
The first block sets the environment variables which are set by the navigator before launching the app. This make the application use the Qt run-time bundled into the application package instead of the system one. The deployment of the according artifacts is defined in the second section. See Deployment on BlackBerry for details about handling assets relevant to Qt application development on BlackBerry 10.
Ideally, the environment variables should have more values to cover all possible use cases so that you do not need to touch them frequently in the future:
<env var="LD_LIBRARY_PATH" value="app/native/runtime/qt/lib:/accounts/devuser/qt/lib:$LD_LIBRARY_PATH"/>
<env var="QT_PLUGIN_PATH" value="app/native/runtime/qt/plugins:/accounts/devuser/qt/plugins:$QT_PLUGIN_PATH"/>
<env var="QML2_IMPORT_PATH" value="app/native/runtime/qt/qml:/accounts/devuser/qt/qml:$QML2_IMPORT_PATH"/>
This has a few modifications compared to the previous one:
- It uses "app/native/runtime/qt/" instead of "app/native/" for hosting the Qt runtime. This provides more flexibility, since you might want to install your own libs, Qt plugins or QML modules. You could then use "app/native/" for this and so make sure they do no collide with Qt itself
- It adds "/accounts/devuser/qt/". This path can contain a Qt runtime which you deploy for development purposes as described later on this page.
- It retains the values which might have been set in the platform in the future
This way of setting Qt runtime variables will be used in all templates provided for BlackBerry 10.
Handling symbolic links
When you let Qt Creator run the application on the device, it will first create the application package and upload it to the device. The package will be around 60MB, and now includes the Qt runtime. It may take around a minute to deploy and launch the application on a device. If you look up the actual size of the related binaries in the Qt build you will see that they are actually much smaller, around 15MB. The problem with an over-sized Qt package is that the line <asset path="QT_INSTALL_LIBS">lib</asset> tells the blackberry-nativepackager tool to take the entire libs folder and package it as an asset. This folder usually contains symbolic links to lib names with compatible versions. For security reasons, the blackberry-nativepackager tool adds all symbolic links in a folder as actual files. Due to this, each Qt library is copied multiple times which significantly increases of the package size.
Regardless how big Qt5 build is, deploying it each time wastes time in development. There is a method to significantly increase the deployment speed by using an approach when all apps in development mode (the -devMode option in the blackberry-nativepackager tool) can access the home folder of the devuser. See another section about this on this page.
The only sensible way to reduce the size to a minimum is to manually package only those libraries which are needed. In addition to the explicit listing of the used libraries only, you can also exclude the Qt libraries you don't use to decrease the package size. For that, you can use the <exclude> element to specify the libraries to be excluded as shown in the example below:
<asset path="QT_INSTALL_LIBS">
<exclude name="libQt5Xml.so.5.1.0"/>
<exclude name="libQt5QuickParticles.so.5.1.0"/>
<exclude name="libQt5Test.so.5.1.0"/>
…
lib
</asset>
Similarly, you can explicitly list only those libraries that you are using:
…
<asset path="%QT_INSTALL_LIBS%/libQt5Core.so.5.2.0">lib/libQt5Core.so.5</asset>
…
Note: you can use the ntoarm-readelf command line to find out what libraries your application depends i.e. which should be included in the assets. Just make sure that you inspect the dependencies recursively (i.e. even for the dependent libraries)- readelf tool just reports direct dependencies only.
When you use a custom Qt build in an application, it is easy to make a mistake which will lead to a missing part of the Qt runtime. In such a case, your application will shortly popup on the screen and then disappear again. Check the BlackBerry Hints and Tips to learn who to check the logs and find out what happened.
Sharing a Qt5 runtime on a device between apps for development purposes.
The approach uses the fact the apps in development mode call access the home folder of the "devuser", see Deployment on BlackBerry article for more details. This is an attractive possibility saving a lot of time, since you do not add your custom Qt build each time you deploy your app. If you are working on Qt, you can also use this method to deploy a experimental version of Qt for testing. The only thing to keep in mind that this approach does not work with final, signed packages since they cannot access the devuser account anymore. Basically, this approach is a help to reduce app deployment time during the application development. When you are preparing an application to be submitted to BlackBerry World, you need to switch back to "Embedding a custom Qt5 build into a BlackBerry 10 application package" approach otherwise your application will not start.
The basic idea is to copy the Qt runtime binary artifacts into a subfolder in /accounts/devuser/ on the device, and set relevant environment variables, e.g. LD_LIBRARY_PATH, to point to that Qt installation.
Note: a build of Qt 4.8 is pre-integrated in each BlackBerry 10 firmware and NDK release. You should not waste your time for adding another Qt 4.8 build unless you have a very good reason for this.
The first step is to copying the Qt runtime onto the device. You start with establishing an SSH connection to the device. See BlackBerry Hints and Tips to learn how to do this.
Lets assume that $QTDIR points to the root folder of a cross-compiled Qt5 build for BlackBerry 10 and we are going to use the folder /accounts/devuser/qt:
> ssh -i /path/to/private/key devuser@<device-IP-address> "mkdir -p /accounts/devuser/qt"
> cd $QTDIR
> tar cpf- lib plugins qml | ssh -i /path/to/private/key devuser@<device-IP-address> tar xp -C /accounts/devuser/qt/
If you have a Qt4 build you need to copy the imports folder instead of the qml as above.
Make sure that /path/to/private/key> is the private key part from the public key you used to initiate the SSH daemon on the device with blackberry-connect as outlined in BlackBerry Hints and Tips .
Deploying will be even faster if you strip the libraries before copying them. Note that this removes debug symbols from the Qt libraries as well. On a BlackBerry 10 device this can be done with:
> cd $QTDIR
> find -L . -name "'''.so'''" | xargs ntoarm-strip
Use ntox86-strip for the simulator target. On PlayBook, you can do:
> cd $QTDIR
> find -L . -name "'''.so'''" | xargs arm-unknown-nto-qnx6.5.0-strip
The second and the last step is to check the BAR application descriptor file and to verify that Qt runtime environment variables are set to use it. See the according section on this page about this.
QtCreator 3.1 will integrate all these steps in the IDE and so support sharing a Qt5 runtime from the active BlackBerry kit on a device between apps for development purposes.
Using the new make targets and save time on command line:-)
The recently posted NDK overlay (see Qt5 on BlackBerry10) contains an experimental version of an add-on to make specs which significantly improves the work with a custom Qt5 build on the command line. This add-on automatically adds new make targets for packaging, deployment, signing and even deployment of a Qt runtime for development purposes as mentioned in the previous section. Here is a short summary of the provided commands which is also shown if you type "make bbhelp":
It wraps command line tools included in the NDK and adds several new make targets. A few environment variables need to be set by the user to pass device and user specific information to the scripts used by the make targets:
- DEBUG_TOKEN must be set to a full path to a debug token to be used to package the project app in development mode.
- DEVICE_IP must be set to the <IP address> of the device.
- DEVICE_PASSWORD must be set to the device password.
- BAR_DESCRIPTOR may be set to the name of the BAR (BlackBerry Application Archive) descriptor file to be used.
- KEYSTORE_PASSWORD must be set to the developer certificate password.
- CSK_PASSWORD must be set to the bb id token password.
The following additional make targets are provided:
- deploy_qt: deploys Qt runtime into /accounts/devuser/qt/ on the device.
- bar: packages the assets and binary artifacts from the Qt project into a BAR file ready to be deployed to a device device.
- bar_qt: same as the "bar" target, but adds Qt runtime to the BAR file.
- bar_signed: same as "bar", but additionally signs the BAR file for distribution.
- bar_qt_signed: same as "bar_qt", but additionally signs the BAR file for distribution.
- deploy: deploys an existing .bar file to a device.
- bbhelp: displays this message.
Example Usage:
> make deploy_qt bar deploy
This deploys Qt, creates a BAR file referring to it and deploys it to the device as specified by the environment variables "DEVICE_IP" and "DEVICE_PASSWORD"
> make bar_qt deploy
This creates a BAR file with application artifacts and the Qt runtime and deploys it to the device as specified by the environment variables "DEVICE_IP" and "DEVICE_PASSWORD".
The "bar_qt" make target automatically adds the Qt runtime from the Qt5 build in the overlay by adding it to the bottom of the BAR application descriptor file. This be in conflict with the Qt5 runtime you might had specified using QtCreator or even not be able to parse QtCreator specific variables used in 3.0 and earlier:
<asset path="QT_INSTALL_LIBS">lib</asset>
<asset path="QT_INSTALL_PLUGINS">plugins</asset>
<asset path="QT_INSTALL_QML">imports</asset>
The best way to fix this is to use delete related asset lines the BAR application descriptor file, deploy Qt on the central place with "make deploy_qt" or from QtCreator 3.1 and later and use the values for Qt runtime environment variables as described earlier on this page.
A version of this add-on is currently in the review for a submission as a new feature in Qt 5.4.