Skip to the content.

Packaging & Distribution

← Back to home

ChimpStackr uses PyInstaller to create native packages for all platforms. Builds are automated via GitHub Actions but can also be done locally.

Quick Reference

Platform Build command Output
macOS ./scripts/build_macos.sh dist/ChimpStackr-macOS.dmg
Windows .\scripts\build_windows.ps1 dist/ChimpStackr-Windows.zip
Linux (AppImage) ./scripts/build_linux.sh dist/ChimpStackr-Linux-x86_64.AppImage
Linux (Flatpak) ./scripts/build_flatpak.sh Flatpak install (local)

Prerequisites

Local Build

# Quick build (all platforms)
pip install pyinstaller
pyinstaller chimpstackr.spec --noconfirm

# Output:
#   dist/chimpstackr/          -- directory with both executables
#   dist/chimpstackr/chimpstackr       -- GUI executable
#   dist/chimpstackr/chimpstackr-cli   -- CLI executable
#   dist/ChimpStackr.app/      -- macOS .app bundle (macOS only)

Verify the build

# Test CLI
dist/chimpstackr/chimpstackr-cli --help
dist/chimpstackr/chimpstackr-cli -i /path/to/images/*.jpg -o /tmp/test.jpg

# Test GUI
open dist/ChimpStackr.app          # macOS
dist/chimpstackr/chimpstackr       # Linux
dist\chimpstackr\chimpstackr.exe   # Windows

CI/CD (GitHub Actions)

The build workflow (.github/workflows/build.yml) triggers on:

Triggering a release

# Tag and push
git tag v0.1.0
git push origin v0.1.0

This runs:

  1. Test on all 3 platforms (Python 3.11)
  2. Build macOS – PyInstaller, optional code signing, DMG creation
  3. Build Windows – PyInstaller, ZIP archive
  4. Build Linux (AppImage) – PyInstaller, AppImage creation
  5. Build Linux (Flatpak) – flatpak-builder, .flatpak bundle
  6. Release – GitHub Release with all artifacts

GitHub Secrets (optional)

For macOS code signing and notarization, set these repository secrets:

Secret Description
MACOS_CODESIGN_IDENTITY Developer ID Application: Your Name (TEAMID)
APPLE_ID Your Apple ID email
APPLE_TEAM_ID Apple Developer Team ID
APPLE_APP_PASSWORD App-specific password from appleid.apple.com

Without these, the macOS build still works but produces an unsigned DMG (users will need to right-click > Open on first launch).

Architecture

Dual executables

The .spec file creates two executables from shared libraries:

Both share the same _internal/ directory with all dependencies, so they’re only bundled once.

macOS .app bundle

On macOS, PyInstaller also creates a ChimpStackr.app bundle with:

Linux AppImage

The build script wraps the PyInstaller output in an AppImage:

Linux Flatpak

Flatpak packaging files are in packaging/flatpak/. The Flatpak build uses the KDE 6.9 runtime with the PySide BaseApp (provides PySide6 bindings linked against the runtime’s Qt6).

App ID: io.github.noah_peeters.ChimpStackr

Files:

File Purpose
packaging/flatpak/io.github.noah_peeters.ChimpStackr.yml Flatpak manifest
packaging/flatpak/io.github.noah_peeters.ChimpStackr.desktop Desktop entry
packaging/flatpak/io.github.noah_peeters.ChimpStackr.metainfo.xml AppStream metadata for software centers

Local build:

# Install prerequisites
sudo apt install flatpak flatpak-builder
flatpak install flathub org.kde.Platform//6.9 org.kde.Sdk//6.9 io.qt.PySide.BaseApp//6.9

# Build and install locally
./scripts/build_flatpak.sh

# Run
flatpak run io.github.noah_peeters.ChimpStackr

# Create a redistributable .flatpak bundle
./scripts/build_flatpak.sh --bundle

Native dependencies (built from source in the manifest):

The CI workflow uses flatpak/flatpak-github-actions with the ghcr.io/flathub-infra/flatpak-github-actions:kde-6.9 container image to build and produce a .flatpak bundle attached to each release.

Heavy dependencies

These need special handling in the .spec file:

Dependency Issue Solution
numba/llvmlite Native JIT compiler libs often missed collect_all('numba')
pyfftw FFTW3 C libraries collect_all('pyfftw')
rawpy libraw native lib collect_all('rawpy')
imageio Package metadata needed at runtime collect_all('imageio')
scipy Many submodules with C extensions collect_all('scipy')

macOS entitlements

The packaging/entitlements.plist grants these hardened runtime exceptions:

Troubleshooting

“No module named X” at runtime

Add it to hiddenimports or use collect_all('X') in the .spec file, rebuild.

macOS “app is damaged” / “unidentified developer”

Unsigned builds trigger Gatekeeper. Users can: right-click > Open, or run:

xattr -cr /Applications/ChimpStackr.app

Linux AppImage won’t run

Install FUSE: sudo apt install libfuse2

Windows antivirus flags the exe

This is common with PyInstaller. Options:

Build is too large

The ~450MB uncompressed size is normal for NumPy + SciPy + Numba + PySide6. The DMG compresses to ~200MB. To reduce: