The aim of this project is to try to add remote debugging capabilities into an existing QGIS docker image.
Features:
- Compiled with CMAKE_BUILD_TYPE: DEBUG
- Include remote VNC connection
- SSH + Rsync Server available
- Entrypoint script injection abilities. It is able to run a script before container online
To build the image:
docker-compose build
However, the point of creating this project is to let Docker Hub build your image so you can just use it immediately. So, I recommend that you clone the repo and built it yourself using docker hub, then pull it.
To use the image:
Copy .example.env
as .env
in the root project folder.
This will contain environment variable override.
Let's say we want to run debugging using GDB and view the interface (using VNC, not Xvfb).
Copy resources/sample_debugger_scripts/gdb/docker-compose.override.yml
to docker-compose.override.yml
. All location are relative to repo's root directory.
To use VNC Display, change into this:
version: '3'
services:
qgis:
command: /bin/bash -c "while [ 'TRUE' ]; do gdbserver 0.0.0.0:34567 /QGIS/build/output/bin/qgis; done"
environment:
# VNC Display uses DISPLAY :98
DISPLAY: ":98"
ports:
- "34567:34567"
Short explanation:
- We are running gdbserver on the container and expose it to port 34567, then run prebuilt QGIS binary located in
/QGIS/build/output/bin/qgis
- We are using Tightvncserver display in DISPLAY :98
- We are exposing port 34567 to host, so local gdb client can connect to it
Run the services:
docker-compose up -d
VNC port are exposed to port 5998
(which is 5900 + Display number). These rules are declared in the main docker-compose.yml
file. You can connect to it using VNC Viewer application with default credentials:
host: localhost:5998
user: root
pass: userpass
With above gdbserver command, QGIS will run when gdb has connected. How you connect to it depends on the IDE you choose, but to quickly check it, run gdb and perform internal command:
gdb
gdb> target remote localhost:34567
gdb> info sources
To do some various things and modifications, see example below.
Docker will use environment variable defined in .env
file.
Overriding those will change the value in docker-compose.yml file
Changing cmake behaviour can be done via docker build variable CMAKE_OPTIONS
.
Using docker build:
docker build --build-arg CMAKE_OPTIONS=<super long CMAKE Flags> -t local/qgis-debug .
Using docker-compose build:
docker-compose --build-arg CMAKE_OPTIONS=<super long CMAKE flags> build
Using Docker Hub, just set CMAKE_OPTIONS in the autobuild settings for the build args.
Inside the containers, the project directory is in /QGIS
. The cmake build directory is in /QGIS/build
. The CCACHE_DIR is in /QGIS/.ccache_image_build
. Simply use docker cp to extract this out. You can look at example in sync-cache.sh
After it was extracted, you can volume mount those directory to make sure any changes for the build are persisted. This is very useful if you do debug + edit workflow. Since recompiling means you need to change the source code, don't forget to mount the source code from your local QGIS repo:
Some sample docker-compose.override.yml
with this intention.
version: '3'
services:
qgis:
command: /bin/bash -c "while [ 'TRUE' ]; do gdbserver 0.0.0.0:34567 /QGIS/build/output/bin/qgis; done"
environment:
DISPLAY: ":98"
ports:
- "34567:34567"
volumes:
- ${QGIS_REPO}/build:/QGIS/build
- ${QGIS_REPO}/.ccache_image_build:/QGIS/.ccache_image_build
- ${QGIS_REPO}/src:/QGIS/src
Add new environment variable in .env
file in this project directory to let docker-compose know where QGIS_REPO
is:
QGIS_REPO=/home/<user>/apps/QGIS/qgis
In addition to that, it is sometimes useful to extract the headers file.
The header files are located inside containers in dir /usr/include
. You can copy this file along in your QGIS project repo.
If you use other CMAKE flags, then you need to set it inside the docker-compose override recipe:
version: '3'
services:
qgis:
# I will only put relevant key in environment key
environment:
CMAKE_OPTIONS: "<super long CMAKE flags>"
You need to apply the cmake conf:
docker-compose exec qgis /build-debug.sh
For subsequent rebuilding, execute this command:
docker-compose exec qgis ninja install
You can hook above command to your IDE to make it autorebuild on demand.
You might want to hook extra scripts before your debug server/setup ready.
The image is equipped with a docker-entrypoint.sh
script that will execute extra sh
scripts in the directory inside containers: /docker-entrypoint-scripts.d
.
So, if you want to include the scripts, customize your docker-compose override recipe:
version: '3'
services:
qgis:
# I will only put relevant key in environment key
volumes:
# Mounting a directory
- "${PWD}/your-scripts-dir:/docker-entrypoint-scripts.d
# Mounting a file
# - "${PWD}/your-script.sh:/docker-entrypoint-scripts.d/your-script.sh
These scripts are going to be executed when you first run docker-compose up -d
in a fresh stack.
Since there is a possible case where you want to install extra python modules/app, you can do that by mounting the requirements.txt file. Any file with name suffix requirements.txt
will be inspected.
version: '3'
services:
qgis:
# I will only put relevant key in environment key
volumes:
# Mounting a python requirements.txt
- "${PWD}/my-dependencies.requirements.txt:/docker-entrypoint-scripts.my-dependencies.requirements.txt
I mainly uses VSCode and PyCharm.
To Debug C++ code, you can use VSCode
- VSCode
- Official C++ VSCode extension
- gdb
In the resources/sample_debugger_scripts/gdb
there are sample scripts usable by VSCode.
The file resources/sample_debugger_scripts/gdb/.vscode/launch.json
is for the .vscode/launch.json
file. It is used to launch the debugger when user press F5 in vscode.
The file resources/sample_debugger_scripts/gdb/.vscode/tasks.json
is for the .vscode/tasks.json
file. It is used to run build task.
Link the volume mount used by docker-compose in this repository with the same location in your QGIS repo openned by vscode. If you use QGIS_REPO
environment variable, coupled with this setup: Extracting build cache, then that means the .ccache_image_build
, build
, and src
dir are linked with the location in your QGIS repo.
In the launch.json
file there is an options to specify file mapping. You can specify source code map (from host to container), so that when gdbserver refer to a source code in the container, VSCode can understand that it refer the same file in your host directory.
The highlighted settings are here:
{
"sourceFileMap": {
// left are container filesystem: right are host filesystem
"/QGIS": "${workspaceRoot}",
// If you extracted the header files, you can also map it here
// "/usr/lib/include": "${workspaceRoot}/build/include"
},
In addition to that, since you will mostly debug Qt Framework, you can include gdb command definition in resources/sample_debugger_scripts/gdb/.gdbinit
into your ~/.gdbinit
.
This will allow you to print of Qt5 String in VSCode from the gdb terminal.
From the debug console, execute:
-exec printqs5static <qstring variable>
You can debug Python code (for plugins) using PyCharm Pro edition.
- PyCharm Professional Edition
Debugging using PyCharm Debug Server is a little bit different in architecture. Using GDB, you instantiate debug server inside the container. But, using PyCharm Debug Server, the pydevd debug server is instantiated in your host machine, the place where you run PyCharm itself. That means your containers need to be able to access your host machine to access debug server.
If you add Debug Server configuration in PyCharm there are some instructions PyCharm will provide for you, it can be broken down in two step
- Install pydevd-pycharm package with specific version inside your container
Add the following extra keys to your docker-compose.override.yml
version: '3'
services:
qgis:
environment:
PYCHARM_VERSION: "your-pycharm-version"
volumes:
- ${PWD}/resources/sample_debugger_scripts/pydevd/remote_pydevd_client.sh:/docker-entrypoint-scripts.d/remote_pydevd_client.sh
ports:
# This will be your pydevd ports
- "34568:34568"
- Copy paste the stack trace code into your plugin's
__init__.py
script.
import pydevd
pydevd_pycharm.settrace('<host>', port=34568, stdoutToServer=True, stderrToServer=True)
Replace '' with the ipaddress of your network bridge. You can check by using ifconfig
and see your WiFi/Ethernet or Docker Bridge interface