This guide walks you from source to distributable apps for macOS and Windows. The packaging files are already in the project:
| File | Purpose |
|---|---|
PortusSIM.spec |
PyInstaller build recipe (bundles assets, presets, icon) |
make_icons.py |
Generates .ico / .icns from the logo PNGs |
build_mac.sh |
One-command macOS build → .app + .dmg |
build_windows.bat |
One-command Windows build → .exe folder |
PyInstaller cannot cross-compile. You must build each platform on that platform:
- To make the Mac app, run the build on a Mac.
- To make the Windows app, run the build on a Windows PC.
You have a Mac, so you can build the Mac version yourself today. For Windows you'll need access to a Windows machine (a cheap option: a Windows VM, a borrowed PC, or a CI runner — see "Building Windows without a PC" at the end).
- Python 3.11–3.13 installed
- The project folder with all source files
- An internet connection (to install build tools the first time)
cd market_town
chmod +x build_mac.sh
./build_mac.shThis creates:
dist/PortusSIM.app— the applicationdist/PortusSIM-1.0.0.dmg— the disk image you send to people
To test: double-click the .app in dist/. To test the distribution
experience, open the .dmg, drag PortusSIM to Applications, and launch it.
This build is unsigned and un-notarized. When someone other than you opens it, macOS will say "PortusSIM can't be opened because Apple cannot check it for malicious software." This is expected for a prototype. Two ways through:
- User workaround (free): right-click the app → Open → Open in the dialog. Only needed once. Tell your users this.
- Proper fix (costs money): enroll in the Apple Developer Program ($99/yr),
then code-sign and notarize. Worth it only when you go past prototype. The
steps are:
codesign --deep --sign "Developer ID Application: ..."thenxcrun notarytool submit. Setcodesign_identityinPortusSIM.specwhen you get there.
For a 1.0.0 prototype shared with colleagues, the right-click-Open route is completely fine.
On a Windows PC, in the project folder:
build_windows.batThis creates dist\PortusSIM\ containing PortusSIM.exe and its support
files. Share the whole folder (zipped), not just the .exe — the .exe
needs the _internal folder beside it.
A zipped folder works, but a proper installer is friendlier. Use Inno Setup (free): https://jrsoftware.org/isinfo.php
- Install Inno Setup.
- Use its Script Wizard → point it at
dist\PortusSIM\, set the main exe toPortusSIM.exe, app name "PortusSIM", version 1.0.0. - Compile → you get
PortusSIM-1.0.0-setup.exe, a single double-click installer.
Like macOS Gatekeeper, unsigned Windows apps trigger SmartScreen: "Windows protected your PC." Users click More info → Run anyway. To remove this you need a code-signing certificate (~$100–400/yr from a CA) — again, only worth it beyond prototype stage.
The packaged app is read-only, so PortusSIM writes user data (exported results, saved presets) to a per-user folder, not next to the executable:
- macOS:
~/Library/Application Support/PortusSIM/ - Windows:
%APPDATA%\PortusSIM\
The bundled example presets are read-only inside the app; user-saved presets go to the writable folder above.
This is 1.0.0 (set in main.py and PortusSIM.spec). To cut a new
version, bump the string in both places.
If you only have a Mac, options to produce the Windows build:
- GitHub Actions (free, recommended): a
windows-latestrunner builds the.exeon every push. Ask me and I'll write the workflow YAML — it runsbuild_windows.batequivalent steps and uploads the result as an artifact. - A Windows VM (Parallels / VMware / free VirtualBox + a Windows eval ISO).
- A borrowed Windows machine for a one-off build.
-
python test_everything.py→ all 63 tests pass - App launches from source:
python main.py - Icons generated:
assets/logo/PortusSIM.icoand.icnsexist - Built on the target OS (Mac build on Mac, Win build on Windows)
- Launched the packaged app and clicked through all modes
- Confirmed presets load (File → Load preset) and export works
- Told users about the Gatekeeper / SmartScreen first-run step