QGroundControl Tools

July 27, 2026 · View on GitHub

This directory contains development tools, scripts, and configuration files for QGroundControl.

For the condensed day-to-day workflow, see AGENTS.md. This file is the full reference for every just recipe and standalone script.

Table of Contents

Quick Start

Common commands are wrapped in a justfile (requires just >=1.30 for home_directory(); apt install just on Ubuntu ships 1.21, which is too old):

# One-time: install `just` (pulls rust-just into .venv via uv)
python3 tools/setup/install_python.py dev

# or: brew install just / cargo install just / pipx install rust-just

Everyday loop:

just             # List all recipes
just setup       # First-time: deps + submodules + configure + build
just build       # Incremental build
just check       # lint + test — run before declaring done

Full recipe list, grouped by purpose: Just Command Reference. just reads shared version/config from .github/build-config.json (Qt/CMake/GStreamer versions) — see Centralized Configuration.

Directory Structure

tools/
├── analyze.py               # Static analysis and formatting (clang-format, clang-tidy, cppcheck, clazy)
├── build_profile.py         # Summarize Ninja and Clang time-trace build hotspots
├── check_deps.py            # Check for outdated dependencies
├── clean.py                 # Clean build artifacts and caches
├── configure.py             # CMake configuration wrapper
├── coverage.py               # Code coverage reports
├── generate_docs.py         # Generate API docs (Doxygen)
├── moccache.py              # Content-addressed cache for Qt moc (AUTOMOC wrapper)
├── pre_commit.py            # Pre-commit hook runner
├── pseudo_loc.py             # Generate pseudo-localized .ts files for layout testing
├── release.py                # Semantic versioning and release automation
├── run_tests.py              # Qt unit test runner
├── configs/                 # Tool configuration files
│   └── ccache.conf          # ccache configuration
├── analyzers/                # Static analysis scripts
│   └── vehicle_null_check.py
├── coding-style/             # Code style examples
├── common/                   # Shared Python utilities
│   ├── patterns.py          # QGC regex patterns
│   └── file_traversal.py    # File discovery
├── debuggers/                # Debugging tools
│   ├── gdb-pretty-printers/ # GDB/LLDB Qt type formatters
│   ├── profile.sh           # Profiling (valgrind, perf)
│   ├── qt6.natvis           # Visual Studio debugger visualizers
│   └── valgrind.supp        # Valgrind suppressions
├── generators/                # Build-time code generation (mavlink enums, config/settings QML)
├── schemas/                   # JSON schemas for editor validation
├── setup/                     # Environment setup scripts
├── simulation/                # Vehicle simulators
│   ├── mock_vehicle.py      # Lightweight MAVLink simulator
│   └── run-arducopter-sitl.sh  # ArduCopter SITL (Docker)
└── translations/              # Translation tools

Just Command Reference

All recipes are defined in ../justfile and grouped there by section. Run just with no arguments to print this list from the tool itself.

Setup

RecipeDescription
just depsInstall system build dependencies (Debian/Ubuntu, via sudo apt)
just submodulesInitialize/update git submodules

Build

RecipeDescription
just configureConfigure CMake build (Debug by default; pulls submodules first)
just buildBuild the project (uses all cores by default; override with JOBS=N)
just releaseConfigure and build in Release mode (testing disabled)
just clean [ARGS]Clean the build directory; forwards ARGS to tools/clean.py (--cache, --all, --dry-run)
just rebuildclean + configure + build
just setupFull first-time setup: deps + submodules + configure + build

Quality

RecipeDescription
just testRun unit tests via ctest; defaults to labels Unit/Integration, excluding Flaky/Network
just lintRun all pre-commit checks (pre-commit run --all-files)
just formatCheck code formatting with clang-format (no changes)
just format-fixApply clang-format fixes
just analyzeRun static analysis (tools/analyze.py, default tool clang-tidy)
just coverageBuild with coverage instrumentation, run tests, generate report
just checklint + test — run before declaring a task done

Override test label filters via environment variables or positional args:

just test                              # LABELS=Unit|Integration EXCLUDE=Flaky|Network (defaults)
LABELS="Slow" just test                # override via env var
just test "Slow" "Network"             # override via positional args (labels, exclude)

Run & Deploy

RecipeDescription
just runLaunch the built QGroundControl binary
just docsBuild the VitePress documentation site (npm run docs:build)
just dockerBuild inside the Ubuntu Docker container (deploy/docker/run-docker.sh ubuntu)

Utilities

RecipeDescription
just infoPrint resolved build configuration (Qt version/dir, CMake min, GStreamer, jobs, ...)
just check-depsCheck dependency and submodule versions (tools/check_deps.py)
just distcleanClean build, caches, generated files, and node_modules/

Direct Script Usage

Prefer just recipes for common tasks; call the underlying scripts directly for flags a recipe doesn't expose — see Development Scripts for the per-script flag reference.

# Run tools/ Python tests
cd tools && uv run --extra scripts --extra test pytest tests/ -q

Development Scripts

analyze.py

Run static analysis and formatting on source code. Underlies just format, just format-fix, and just analyze.

./tools/analyze.py                              # Analyze changed files (default tool: clang-tidy)
./tools/analyze.py --all                        # Analyze all files
./tools/analyze.py --tool clang-format --fix    # Format changed files
./tools/analyze.py --tool clang-format --all    # Check formatting (all files)
./tools/analyze.py --tool cppcheck              # Use cppcheck instead of clang-tidy
./tools/analyze.py src/Vehicle/                 # Analyze specific directory

Other --tool choices: clazy, qmllint, vehicle-null-check, qt-translate-noop-check.

clean.py

Clean build artifacts and caches. Underlies just clean and just distclean.

./tools/clean.py              # Clean build directory
./tools/clean.py --all        # Clean everything (build, caches, generated files)
./tools/clean.py --cache      # Clean only caches (ccache, pip, etc.)
./tools/clean.py --dry-run    # Show what would be removed

build_profile.py

Summarize build-time hotspots from Ninja logs and optional Clang time traces.

python3 ./tools/build_profile.py -B build                 # Report slowest Ninja edges and rebuild churn
python3 ./tools/build_profile.py -B build --limit 25      # Show more rows per section
python3 ./tools/build_profile.py -B build --json          # Machine-readable output

For per-translation-unit trace details, configure with -DQGC_TIME_TRACE=ON, rebuild, then rerun the report — it scans the build dir for Clang -ftime-trace JSON and highlights the slowest events.

moccache.py

Content-addressed cache for Qt's moc, wired in automatically as the CMAKE_AUTOMOC_EXECUTABLE (controlled by the QGC_USE_MOCCACHE CMake option, ON by default, non-Windows). Clean builds, branch switches, and sibling build trees reuse previous moc runs. Misses fall through to the real moc and never fail the build. See the dev guide Build Caching section for the cache key, environment variable reference, and usage examples. Tests: tools/tests/test_moccache.py.

coverage.py

Generate code coverage reports. Wrapper around the CMake coverage targets. Underlies just coverage. Uses a dedicated build-coverage/ directory by default (override with -b/--build-dir).

python3 ./tools/coverage.py              # Build with coverage, run tests, generate report
python3 ./tools/coverage.py --report     # Generate report only (after tests)
python3 ./tools/coverage.py --open       # Generate and open in browser
python3 ./tools/coverage.py --clean      # Clean coverage data

Requires: gcovr (pip install gcovr, or python3 tools/setup/install_python.py coverage)

Direct CMake usage:

cmake -B build -DQGC_ENABLE_COVERAGE=ON -DCMAKE_BUILD_TYPE=Debug
cmake --build build
ctest --test-dir build
cmake --build build --target coverage-report  # XML + HTML from existing data
cmake --build build --target coverage         # Run tests + generate XML + HTML
cmake --build build --target coverage-check    # Run tests + generate report + enforce a coverage floor
cmake --build build --target coverage-clean   # Clean .gcda files

debuggers/profile.sh

Profile QGC for performance and memory issues.

./tools/debuggers/profile.sh                # CPU profiling with perf
./tools/debuggers/profile.sh --memcheck     # Memory leak detection (valgrind)
./tools/debuggers/profile.sh --callgrind    # CPU profiling (valgrind)
./tools/debuggers/profile.sh --massif       # Heap profiling (valgrind)
./tools/debuggers/profile.sh --heaptrack    # Heap profiling (heaptrack)
./tools/debuggers/profile.sh --sanitize     # Build with AddressSanitizer

check_deps.py

Check for outdated dependencies and submodules. Underlies just check-deps.

python3 ./tools/check_deps.py              # Check all dependencies
python3 ./tools/check_deps.py --submodules # Check git submodules only
python3 ./tools/check_deps.py --qt         # Check Qt version
python3 ./tools/check_deps.py --update     # Update submodules to latest

generate_docs.py

Generate API documentation using Doxygen.

python3 ./tools/generate_docs.py          # Generate HTML docs
python3 ./tools/generate_docs.py --open   # Generate and open in browser
python3 ./tools/generate_docs.py --pdf    # Generate PDF (requires LaTeX)
python3 ./tools/generate_docs.py --clean  # Clean generated docs

Requires: doxygen, graphviz

Setup Scripts

Scripts in setup/ help configure development environments. They read configuration from .github/build-config.json for consistent versioning. install_dependencies is a Python package (tools/setup/install_dependencies/), invoked directly via its __main__.py.

ScriptPlatformDescription
install_dependencies --platform debianLinux (Debian/Ubuntu)Install build dependencies via apt
install_dependencies --platform fedoraLinux (Fedora/RHEL)Install build dependencies via dnf
install_dependencies --platform archLinux (Arch)Install build dependencies via pacman
install_dependencies --platform macosmacOSInstall dependencies via Homebrew + GStreamer
install_dependencies --platform windowsWindowsInstall GStreamer (Vulkan SDK optional)
install_python.pyAllInstall Python tools via uv or pip (see groups below)
install_qt.pyAllInstall Qt SDK via aqtinstall with QGC arch-directory resolution (used by CI)
build-gstreamer.pyAllBuild GStreamer from source (optional)
build_android_openssl.pyAndroidCross-compile OpenSSL as Qt-style Android libraries (optional)
download_artifacts.pyAllDownload build artifacts (in .github/scripts/)
read_config.pyAllRead .github/build-config.json (Python, cross-platform)

install_python.py installs dependency groups defined in tools/pyproject.toml: scripts, precommit, test, ci (default), qt, coverage, dev, lint, all.

Usage Examples

# Linux: Install all dependencies
python3 ./tools/setup/install_dependencies --platform debian

# macOS: Install all dependencies
python3 ./tools/setup/install_dependencies --platform macos

# Windows (as Admin):
python .\tools\setup\install_dependencies --platform windows

# Install Python tooling (pre-commit, test, coverage, etc.)
python3 ./tools/setup/install_python.py precommit,test,coverage

# Build GStreamer from source (optional — CMake auto-downloads pre-built SDKs)
python3 ./tools/setup/build-gstreamer.py --platform linux --prefix /opt/gstreamer

# Read build config values
python3 ./tools/setup/read_config.py --get qt.version

Static Analyzers

Scripts in analyzers/ perform QGC-specific static analysis.

vehicle_null_check.py

Detects unsafe activeVehicle() access patterns that could cause null pointer dereferences.

# Analyze specific files
python3 tools/analyzers/vehicle_null_check.py src/Vehicle/*.cc

# Analyze entire directory
python3 tools/analyzers/vehicle_null_check.py src/

# JSON output for CI/editor integration
python3 tools/analyzers/vehicle_null_check.py --json src/

# Run via pre-commit
pre-commit run vehicle-null-check --all-files

Detects activeVehicle()->method() without a prior null check and unvalidated getParameter() results; output includes fix suggestions per issue. See analyzers/README.md for details.

Shared Utilities

Common utilities in common/ are used by multiple tools:

  • patterns.py - QGC-specific regex patterns (Fact, FactGroup, MAVLink)
  • file_traversal.py - File discovery with proper filtering
  • gh_actions.py - GitHub API helpers (httpx with gh CLI fallback) for workflow runs and artifacts

See common/README.md for API documentation.

Debugging Tools

debuggers/gdb-pretty-printers/

GDB pretty printers for Qt 6 types. Makes debugging Qt containers and strings readable.

# In GDB:
source tools/debuggers/gdb-pretty-printers/qt6.py

# Then:
(gdb) print myQString
\$1 = "Hello, World!"

See debuggers/gdb-pretty-printers/README.md for setup instructions.

debuggers/qt6.natvis

Visual Studio debugger visualizers for Qt6 types. Automatically loaded by VS when debugging.

Simulation Tools

Vehicle simulators for testing QGC without hardware.

Mock Vehicle (Lightweight)

pip install pymavlink
./tools/simulation/mock_vehicle.py              # QGC connects to UDP 14550
./tools/simulation/mock_vehicle.py --tcp --port 5760  # TCP mode

ArduCopter SITL (Full Simulation)

./tools/simulation/run-arducopter-sitl.sh       # Connect to tcp://localhost:5760
./tools/simulation/run-arducopter-sitl.sh --with-latency  # Simulate network lag

See simulation/README.md for details.

Translation Tools

Scripts in translations/ manage internationalization.

ScriptDescription
qgc_lupdate.pyUpdate Qt translation files (runs lupdate + JSON extractor + pseudo-loc)
qgc_lupdate_json.pyExtract translatable strings from JSON files
# From repository root:
python3 tools/translations/qgc_lupdate.py

# Or run JSON extractor directly:
python3 tools/translations/qgc_lupdate_json.py

See translations/README.md for Crowdin integration.

Code Quality Tools

ccache.conf

Configuration for ccache to speed up rebuilds. CMake automatically uses this when ccache is available.

# Manual use:
export CCACHE_CONFIGPATH=/path/to/qgroundcontrol/tools/configs/ccache.conf

coding-style/

Example files demonstrating QGC coding conventions:

  • CodingStyle.h - Header file conventions
  • CodingStyle.cc - Implementation file conventions
  • CodingStyle.qml - QML file conventions

See CODING_STYLE.md for the full style guide.

VS Code Integration

The repository includes VS Code configuration in .vscode/:

  • settings.json - Editor settings, CMake integration
  • extensions.json - Recommended extensions
  • tasks.json - Build, test, format tasks
  • launch.json - Debug configurations

Open the repository in VS Code and install recommended extensions for the best experience.

Centralized Configuration

Version numbers and build settings are centralized in .github/build-config.json:

{
  "qt": { "version": "6.11.1", "modules": "qtgraphs qtlocation ..." },
  "gstreamer": { "version": { "default": "1.28.4", ... }, ... },
  "android": { "platform": "36", "ndk_full_version": "27.2.12479018", "java_version": "21", ... },
  "apple": { "xcode_version": "16.x", "macos_deployment_target": "13.0", ... },
  "build": { "cmake_minimum_version": "3.25", "platform_workflows": "Linux,Windows,MacOS,Android" }
}

Related settings are grouped into objects (qt, android, apple, build, gstreamer). Read a value with the dotted path, e.g. read_config.py --get qt.version or --get android.ndk_full_version. Exported env vars / CI outputs derive from the path (android.ndk_full_versionANDROID_NDK_FULL_VERSION / android_ndk_full_version).

Scripts read from this file to ensure consistent versions across local development and CI.