The supported entry point is build_app.py. It builds the Flutter application,
automatically builds the Rust bridge, checks the host toolchain, and packages
the result in build/dist/. It uses only the Python standard library; a Python
virtual environment is optional.
For end-user installation, Gatekeeper/SmartScreen recovery, Android APK sideloading, and iOS/iPadOS self-signing with a personal Apple Account, see INSTALLING.md.
| Component | Version / requirement |
|---|---|
| Python | 3.8 or newer |
| Flutter | 3.44.7 stable |
| Rust | rustup; rust-toolchain.toml selects 1.92.0 |
| Android | JDK 17+, SDK Platform 36, NDK 28.2.13676358 |
| Windows | Visual Studio 2022+ with Desktop development with C++ and ATL |
| Apple | A current Xcode supported by Flutter 3.44.7 |
| Linux | Clang, CMake, Ninja, pkg-config, GTK 3 development files |
pubspec.lock and Cargo.lock are committed. CI selects the Flutter and Rust
versions above. A local Flutter SDK is not downloaded by this repository, so
pass its path to the script or put it on PATH.
The table below distinguishes tools required to compile the application from tools needed only for particular package formats:
| Target | Required build dependencies | Optional packaging/signing dependencies |
|---|---|---|
| Windows | Python, Flutter, rustup, Visual Studio C++/ATL and Windows SDK, Perl, NASM | Inno Setup 6 for installer EXE; WiX Toolset 3 for MSI; MakeAppx for MSIX/MSIXBundle; 7-Zip |
| macOS | Python, Flutter, rustup, Xcode and command-line tools | 7-Zip; users provide their own identity if they want to re-sign the unsigned output |
| Linux | Python, Flutter, rustup, compiler/build tools, GTK 3 and libsecret development files, patchelf, Perl, NASM |
dpkg-deb, rpmbuild, zstd, xz, appimagetool, Flatpak, mksquashfs, or 7-Zip according to requested formats |
| Android | Python, Flutter, rustup, JDK 17+, Android SDK Platform 36 and NDK 28.2.13676358, Bash, Perl | Android release keystore; bundletool 1.18.3 for APKS; Platform Tools/ADB for device installation |
| iOS/iPadOS | Python, Flutter, rustup, Xcode and command-line tools | 7-Zip; Apple Account/team, certificate and provisioning profile are needed by the user who re-signs for installation |
Git and network access are normally needed for the first dependency download. They are not application runtime dependencies.
Before building, run the platform-aware diagnostic:
python build_app.py --doctorUse python3 or ./build_app.py on systems where that is the normal spelling.
Run python build_app.py --help for every target, format, option, and example.
Install:
- Python 3.8 or newer (CPython, UV-managed Python, and a UV virtual environment are all valid);
- Flutter 3.44.7 with Windows desktop support enabled;
- rustup;
- Visual Studio with Desktop development with C++, MSVC, CMake tools, and a Windows 10/11 SDK;
- Strawberry Perl, which supplies Perl and NASM needed by the vendored OpenSSL build. A separate Perl and NASM installation is also valid;
- optionally Inno Setup 6 for
exe, WiX Toolset 3 formsi, the Windows SDK MakeAppx tool formsix, and 7-Zip for7z.
This form does not require activating the virtual environment or editing the
permanent user PATH (replace the example locations with local SDK paths):
& C:\path\to\venv\Scripts\python.exe `
.\build_app.py --doctor -p windows -a x64 -f zip `
--flutter-sdk C:\path\to\flutter `
--cargo-home C:\path\to\.cargo
& C:\path\to\venv\Scripts\python.exe `
.\build_app.py -p windows -a x64 -f zip `
--flutter-sdk C:\path\to\flutter `
--cargo-home C:\path\to\.cargoAfter activating the environment and putting Flutter/Cargo on PATH, the
short form is:
python .\build_app.py -p windows -a x64 -f zip
flutter run --release -d windowsThe first cold build compiles vendored OpenSSL and can take several minutes.
Do not interrupt it merely because nmake is quiet. If OpenSSL reports an
openssl-sys custom-build failure, run --doctor: the common causes are
missing Visual Studio C++ tools, Perl, or NASM. After changing those tools, use
--clean once.
Windows x64 and ARM64 packages must be built on native x64 and ARM64 hosts.
The portable output is a complete directory archive containing the executable,
Flutter DLLs, plugins, and data; mdsscope.exe alone is not portable.
Install Flutter, rustup, Python, and Xcode with its command-line tools. Accept
the Xcode license and select the intended Xcode installation. This project uses
Flutter's Swift Package Manager integration and has no CocoaPods Podfile.
python3 build_app.py --doctor -p macos
python3 build_app.py -p macos -a universal \
-f app dmg pkg xcarchive zip 7z tar.gz tar.xz tar.bz2The universal build is verified to contain x64 and arm64 slices in every
Mach-O component. The packager then produces arm64-only, x64-only, and
Universal variants. Release files use the -unsigned suffix. Each application
has only an ad-hoc integrity signature, not a Developer ID identity or Apple
notarization. Users may use Open Anyway, remove quarantine for that one
trusted application, or re-sign it with their own identity as described in
INSTALLING.md.
.app and .xcarchive are directory bundles. Local builds retain those
directories; the corresponding .zip/.xcarchive.zip files are what GitHub
Releases can upload.
For Ubuntu/Debian:
sudo apt-get update
sudo apt-get install -y python3 build-essential clang cmake ninja-build \
pkg-config libgtk-3-dev libsecret-1-dev patchelf perl nasm
python3 build_app.py --doctor -p linux
python3 build_app.py -p linux -a x64 -f deb zipEquivalent common development package sets are:
# Fedora / CentOS Stream / Enterprise Linux
sudo dnf install gcc-c++ clang cmake ninja-build pkgconf-pkg-config \
gtk3-devel libsecret-devel patchelf perl nasm
# Arch Linux
sudo pacman -S base-devel clang cmake ninja pkgconf gtk3 libsecret \
patchelf perl nasmThese commands install build dependencies, not the separate runtime dialog
helper used by file_picker. Install one of zenity, kdialog, or qarma
when Open/Save/Export must work on the build or target machine; see
INSTALLING.md.
Additional formats need their native tools: rpm needs rpmbuild,
pkg.tar.zst needs zstd, pkg.tar.xz needs xz, AppImage needs
appimagetool, Flatpak needs flatpak plus GNOME Platform/SDK 48, Snap needs
mksquashfs, and 7z needs 7-Zip. When -f all is used, unavailable optional formats are skipped;
when a format is named explicitly, its missing tool is an error.
Build Linux x64 and ARM64 on matching native hosts. Flutter desktop builds are not general cross-compilation targets.
ZIP and TAR outputs are portable application bundles, not copies of the raw
Flutter build directory. They carry the Flutter engine, plugins, Rust bridge,
application data and other application-owned libraries. Extract the archive
and run ./mdsscope-linux-<arch>/mdsscope. This file is the native ELF
executable itself; packaging writes relocatable $ORIGIN runpaths into it and
the bundled libraries, so no launcher script or fixed extraction path is
needed. The AppImage is assembled from the same runtime.
GTK 3, GLib/GIO, libsecret, their settings schemas and image/input modules,
glibc, compiler ABI libraries, the X11/Wayland and EGL/OpenGL stacks, the Linux
kernel and graphics drivers deliberately remain provided by the target system.
Keeping the entire desktop stack together prevents an older bundled GTK from
crashing against newer GNOME settings schemas and prevents older X11/EGL
libraries from being mixed with newer Mesa drivers. Install the normal GTK 3,
libsecret and graphics-runtime packages for the distribution. The file dialog
helper (zenity, kdialog, or qarma) is also intentionally system-provided.
Release
automation tests the same archive on newer Debian/Ubuntu, Fedora and Enterprise
Linux environments. This gives one application bundle per CPU architecture; it
does not make a Linux GUI executable independent of the operating-system
desktop runtime.
Ubuntu and Fedora CI containers perform a real GUI smoke launch with their
native EGL/Mesa software-rendering stack. Enterprise Linux 10 no longer ships
Xvfb in its standard repositories, so its x64 and ARM64 jobs verify the complete
ELF dependency closure and glibc ABI without claiming a headless GUI launch.
The same ABI/dependency/startup check can be run locally with:
python3 scripts/verify_linux_portable.py \
build/dist/mdsscope-linux-x64.zip --max-glibc 2.31 --launchInstall Flutter, rustup, Python, JDK 17 or newer, Android SDK command-line tools, SDK Platform 36, and NDK 28.2.13676358. The vendored OpenSSL build also needs Bash and Perl; on Windows, Git for Windows supplies Bash and Strawberry Perl supplies Perl/NASM.
Point the script at an SDK and let it install the exact platform and NDK:
python build_app.py -p android --android-sdk /path/to/Android/Sdk \
--install-android-sdk-components --doctor
python build_app.py -p android -f apk aab apks --android-sdk /path/to/Android/SdkSet BUNDLETOOL_JAR to the pinned bundletool-all-1.18.3.jar when requesting
APKS. The output includes armv7, arm64, x64, and universal APKs, one
multi-architecture AAB, and an APKS archive containing the device-specific
split APK set. AAB is deliberately not duplicated under per-ABI filenames.
Without
release signing variables, local packaging uses the local Android debug
keystore and is suitable for testing, not store publication.
For production signing, set:
export MDSSCOPE_ANDROID_KEYSTORE=/absolute/path/release.jks
export MDSSCOPE_ANDROID_STORE_PASSWORD='...'
export MDSSCOPE_ANDROID_KEY_ALIAS='...'
export MDSSCOPE_ANDROID_KEY_PASSWORD='...'
python build_app.py -p android -f apk aab apksCI uses corresponding encrypted GitHub secrets; private keys are not stored in the repository.
These targets require macOS and Xcode. All repository release outputs are unsigned and can be built without an Apple signing identity:
python3 build_app.py -p ios -p ipados \
-f unsigned-ipa unsigned-app xcarchive zip 7z tar.gz tar.xz tar.bz2One universal Apple mobile binary supports both iPhone and iPad device
families. The script publishes iOS and iPadOS filename aliases. The unsigned
IPA has the standard Payload/MdsScope.app structure, but a normal Apple
mobile device still requires the user to re-sign it with a certificate,
provisioning profile, matching bundle identifier and entitlements. Follow the
self-signing workflow in INSTALLING.md.
Useful options:
--doctor: detailed preflight plusflutter doctor -vandrustup show;--flutter-sdk,--cargo-home,--android-sdk: explicit SDK roots;--clean: clean stale Flutter/CMake output before building;--no-build: package an already-built release without rebuilding;--skip-preflight: intended for controlled CI only;--dist: choose another artifact directory.
The script fails early for impossible host/target combinations and unsupported formats. It removes Python tracebacks for ordinary tool failures and reports the failed command, exit code, and next diagnostic action.
Generated Flutter registrants, plugin metadata, native build products, and
package output are ignored by Git. A successful build must leave git status
clean when it started clean.
On Windows, macOS, and Linux, private application state is stored below the user's home directory:
~/.mdsscope/settings.json
~/.mdsscope/configurations/
~/.mdsscope/cache/
Windows resolves ~ through USERPROFILE. Android, iOS, and iPadOS place the
same .mdsscope structure in the application-support sandbox. Open/Save dialogs
use configurations/ as their desktop default. Existing settings from earlier
builds are migrated once; the unrelated ~/.config/mdsscope/ tree is never
used as a migration source or an import location, even when selected manually.
Passwords and session tokens are stored only in the operating system's secure credential vault: Apple Keychain, Android Keystore-backed encrypted storage, Windows protected credential storage, or Linux Secret Service. Plaintext values left by an earlier build are migrated once and erased. macOS security-scoped bookmarks that authorize an SSH private key are also kept in Keychain. If a Linux desktop has no usable Secret Service provider, credentials are kept only for the current process and must be entered again; they are never written to a plaintext fallback.
python3 -m py_compile build_app.py
python3 build_app.py --help
python3 -m unittest scripts/test_build_app.py
flutter analyze
flutter test
cargo test --manifest-path rust/Cargo.toml --workspace --locked
python3 scripts/verify_icons.pyCI additionally performs real builds for Windows x64/ARM64, Linux x64/ARM64, macOS Universal, Android armv7/arm64/x64, and unsigned iOS/iPadOS.
HarmonyOS NEXT is not an upstream Flutter target. This repository contains no
ArkUI/ArkTS project, OpenHarmony Flutter fork, HAP signing configuration, or
HarmonyOS Rust toolchain, so neither Flutter nor this script can honestly
produce a working HAP. See PLATFORM_SUPPORT.md for the engineering work needed
to add it.