Repository navigation
Multi Platform Build Workflows
Relevant source files
The following files were used as context for generating this wiki page:
- .github/workflows/build_appimage.yml
- .github/workflows/build_macos.yml
- .github/workflows/build_macos_intel.yml
- .github/workflows/build_windows.yml
- .github/workflows/ci.yml
- .github/workflows/pdf_draft.yml
- .github/workflows/release.yml
- .github/workflows/scorecard.yml
- MeasureLab_macOS.spec
- audio-tools.desktop
- build_appimage.sh
- entitlements_mac.plist
- src/gui/pyinstaller_imports.py
This page details the automated build processes and packaging strategies for MeasureLab across Windows, Linux, and macOS. The build system leverages PyInstaller to bundle the Python environment and dependencies into platform-specific distributions, including standalone executables, AppImages, and DMG installers.
The build pipeline is triggered by tags (e.g., v1.0.0) or manual dispatch via GitHub Actions. It ensures consistency across architectures by using native runners for each target platform.
The following diagram illustrates the transformation from source code to distributable assets across all platforms.
Figure 1: Source to Asset Pipeline
graph TD
subgraph "Source Space"
SRC["src/ (Python Modules)"]
MAIN["main_gui.py (Entry Point)"]
SPEC["MeasureLab_macOS.spec"]
IMPORTS["src/gui/pyinstaller_imports.py"]
end
subgraph "Build Engines"
PYI["PyInstaller Engine"]
LDEPLOY["linuxdeploy (Linux)"]
CDMG["create-dmg (macOS)"]
end
subgraph "Distribution Assets"
WIN_ONE["MeasureLab.exe (onefile)"]
WIN_DIR["MeasureLab/ (onedir + ASIO scripts)"]
LIN_APP["MeasureLab.AppImage"]
MAC_DMG["MeasureLab.dmg (signed/notarized)"]
end
SRC --> IMPORTS
IMPORTS --> PYI
MAIN --> PYI
SPEC --> PYI
PYI -- "Windows" --> WIN_ONE
PYI -- "Windows" --> WIN_DIR
PYI -- "Linux (onefile binary)" --> LDEPLOY
LDEPLOY --> LIN_APP
PYI -- "macOS (.app bundle)" --> CDMG
CDMG --> MAC_DMG
Sources: .github/workflows/release.yml:1-200, src/gui/pyinstaller_imports.py:1-90, MeasureLab_macOS.spec:1-81
The Windows build generates two distinct distribution formats: a single-file executable for portability and a directory-based distribution for performance and ASIO support.
MeasureLab requires specific International Components for Unicode (ICU) libraries from the Windows system directory to support localization features. These are manually staged during the build process:
C:\Windows\System32\icu.dllC:\Windows\System32\icuuc.dllC:\Windows\System32\icuin.dll
These are bundled into the executable using the --add-binary "libs/icu*.dll;." flag.
For the onedir build, specific batch scripts are included in the root folder to help users manage ASIO drivers, which often require specific environment configurations or registry tweaks:
enable_asio.batdisable_asio.batREADME_ASIO.txt
| Entity | Role | Configuration |
|---|---|---|
onefile |
Portable Executable | --onefile --windowed --name MeasureLab |
onedir |
High Performance | --windowed --name MeasureLab |
Icon |
app_icon.ico |
Generated via ImageMagick magick
|
Hidden Imports |
pyfftw |
Explicitly included for FFT acceleration |
Sources: .github/workflows/build_windows.yml:65-94, .github/workflows/release.yml:37-62
Linux distribution focuses on the AppImage format to ensure binary compatibility across various distributions (Ubuntu, Fedora, Arch, etc.).
The build utilizes build_appimage.sh, which coordinates the interaction between PyInstaller and linuxdeploy.
- PyInstaller Phase: Generates a standalone binary targeting the oldest supported GLIBC version.
-
Staging Phase: Creates an
AppDirstructure following the FHS (Filesystem Hierarchy Standard). -
Deployment Phase:
linuxdeployintegrates the.desktopfile and icons, then packages theAppDirinto a compressed AppImage.
Since CI environments are typically headless, the AppImage is verified using xvfb-run. The application is launched with the --self-test flag to ensure the Qt runtime and audio dependencies (PortAudio) initialize correctly without a physical display.
Figure 2: Linux Build and Verification Logic
sequenceDiagram
participant CI as GitHub Runner
participant PYI as PyInstaller
participant LD as linuxdeploy
participant XVFB as xvfb-run (Virtual Framebuffer)
CI->>PYI: pyinstaller --onefile main_gui.py
PYI-->>CI: dist/MeasureLab (Binary)
CI->>LD: ./build_appimage.sh
Note over LD: Packages Binary + .desktop + Icons
LD-->>CI: MeasureLab-x86_64.AppImage
CI->>XVFB: xvfb-run ./MeasureLab.AppImage --self-test
XVFB-->>CI: Exit Code 0 (Success)
Sources: build_appimage.sh:1-43, .github/workflows/build_appimage.yml:71-87
The macOS build supports both ARM64 (Apple Silicon) and Intel architectures. It involves complex signing and entitlement steps to satisfy Gatekeeper requirements.
The MeasureLab_macOS.spec file handles versioning and metadata dynamically:
-
Version Extraction: Reads from
version.jsonand sanitizes it for Apple'sCFBundleShortVersionString(dots/digits only) andCFBundleVersion(digits only). -
Bundle Metadata: Sets
LSMinimumSystemVersionto 13.0 and includesNSMicrophoneUsageDescriptionto trigger the macOS privacy prompt for audio input.
The application is signed with the --options=runtime flag to enable the Hardened Runtime. Specific permissions are granted via entitlements_mac.plist:
-
com.apple.security.device.audio-input: Required forAudioEngineto access hardware. -
com.apple.security.cs.disable-library-validation: Necessary for loading scientific libraries likepyfftwandsndfile. -
com.apple.security.cs.allow-unsigned-executable-memory: Required for JIT-like behavior in some Python extensions.
The build script generates a standard macOS .icns file from a source app_icon.png using the sips (Scriptable Image Processing System) utility to create all required resolutions (16x16 to 512x512@2x).
Sources: MeasureLab_macOS.spec:1-81, entitlements_mac.plist:1-13, .github/workflows/build_macos.yml:61-93
Because MeasureLab uses a dynamic module registry (MODULE_REGISTRY) for lazy-loading UI components, PyInstaller's static analysis cannot automatically detect these dependencies.
The file src/gui/pyinstaller_imports.py contains explicit imports of every measurement widget (e.g., SpectrumAnalyzer, LockInAmplifier, NonlinearAnalyzer).
- This file is wrapped in an
if False:block so it is never executed at runtime. - PyInstaller parses this file during the
Analysisphase to ensure all widget classes and their associated dependencies are included in the final bundle.
Sources: src/gui/pyinstaller_imports.py:1-90, MeasureLab_macOS.spec:18-40
The final stage of the release workflow aggregates all platform assets and performs security verification.
Every asset (ZIP, AppImage, DMG) has a SHA-256 checksum generated. These are concatenated into platform-specific files (e.g., checksums_windows.txt) and uploaded as part of the release.
MeasureLab utilizes the OpenSSF Scorecard to monitor supply chain security. This includes:
- Binary Authorization: Checking for signed commits.
-
Dependency Pinning: Using
constraints.txtand SHA-256 hashes for GitHub Actions. -
Workflow Permissions: Restricting CI tokens to
contents: readby default.
Sources: .github/workflows/release.yml:79-95, .github/workflows/scorecard.yml:1-79