A Stackoverflow Question
How to build a unified C++ cross-platform Windows and Linux (x86_64/aarch64) build system using Python, CMake, and Docker
The Problem
Developing C++ applications (specifically Qt-based ones) for multiple platforms usually involves a fragmented workflow:
- Maintaining separate OS environments (Windows for MSVC, Linux for GCC).
- Installing and managing massive toolchains (Qt, MinGW, MSVC, aarch64-linux-gnu) on every machine.
- Managing multiple repository clones or constantly switching IDE contexts.
- Dealing with
CMakePresets.jsonconfiguration complexity when supporting multiple compilers and platforms. - Lacking a unified interface to switch between native builds, cross-compilation, and containerized builds.
- Manual environment variable management for toolchain paths, Wine prefixes, and Docker volume mounts.
- No standardized way to share toolchain configurations across projects or team members.
I want a way to build for Windows (native/MinGW/MSVC) and Linux (x86_64/aarch64) from a single Linux host without manually installing all these toolchains or switching operating systems. Ideally, this solution would:
- Support Wine for cross-compiling Windows targets using MinGW or MSVC
- Use Docker containers for isolated Linux builds (GCC x86_64/aarch64) including Wine for cross-compiling
- Parse and use
CMakePresets.jsonfor preset-based configuration - Provide an interactive menu system to select build configurations
- Automatically configure toolchain environments per platform
- Allow optional portable toolchain installation to avoid massive system-wide installs
How can one orchestrate a Python-based build script that uses either native compilers or Docker containers to handle these different environments seamlessly?
My Solution
Python Build Script for C++ CMake Projects
I created this recursive called Python script
for the Piper1GPL repository to build their C++ part (used for creating a python module)
for different compilers so I could build my TTS Qt6 plugin with it.
The script is leaning heavily on CMake with the accompanied CMakePresets.json file (v6+)
and allows compiling for multiple platforms with a single command:
- Native Linux GCC ->
./build.py -mb gnu-debug - Native Linux GCC aarch64 cross-compiler ->
./build.py -mb ga-debug - Native Linux MinGW cross-compiler ->
./build.py -mb gw-debug - Wine + ...
- Windows MSVC 2022 ->
./build.py -mb msvc-debug - Windows MinGW ->
./build.py -mb mingw-debug
- Windows MSVC 2022 ->
- Native Windows MSVC 2022 ->
build.py -mb msvc-debug - Native Windows MinGW ->
build.py -mb mingw-debug - Linux Docker + ...
- Linux GCC ->
./build.py docker -- -mb gnu-debug - Linux GCC aarch64 cross-compiler ->
./build.py docker -- -mb ga-debug - Linux MinGW cross-compiler ->
./build.py docker -- -mb gw-debug - Wine +
- Windows MSVC 2022 ->
./build.py docker -- wine -- -mb msvc-debug - Windows MinGW ->
./build.py docker -- wine -- -mb mingw-debug
- Windows MSVC 2022 ->
- Linux GCC ->
The pattern here is clear and easy to understand since it is recursively called.
Unittests can be performed and applications run using the environment variables set from a
the accompanied build.ini file using commands like these:
# Run all unit tests.
./build.py docker -- wine -- -t msvc-debug
# Run a specific application.
./build.py docker -- wine -- run -p msvc-debug -- piper-cli.exe
For a working boilerplate project use command:
./build.py install --project
It uses the script fromsf-cmakeGitHub repository to create a 'hello-world' project for the CLI and the Qt6 GUI.
Watch it in action on YouTube for Linux and Windows.
DoxyGen is also avaiable as build target nameddoccumentwhich automatically seeks out the source files from the build targets and allows PlantUML files to be included.
Links: Docker image, Dockerfile