|
| 1 | +# Building Binaries (macOS DMG & Windows EXE) |
| 2 | + |
| 3 | +This document explains how to build **AnycubicNFCTaggerQT5** into |
| 4 | +distributable binaries for macOS (DMG containing a `.app`) and Windows (standalone `.exe`, optional MSI). |
| 5 | +It assumes you already have the repository checked out and that you will run the commands **from the project root**. |
| 6 | + |
| 7 | +> Notes |
| 8 | +> |
| 9 | +> - Source code and comments are in **English**; regular discussion is in German. |
| 10 | +> - Packaging is based on **cx_Freeze** (via our `freeze_setup.py`) for the app/executable creation, and **dmgbuild** for macOS DMGs. |
| 11 | +> - The macOS DMG configuration lives in `packaging/macos/dmg_settings.py` and automatically discovers the built `.app` under `build/`. |
| 12 | +> - Python 3.12 is supported in our current setup; adjust paths if you use a different Python version. |
| 13 | +> |
| 14 | +> If you run into issues, see the **Troubleshooting** section at the end. |
| 15 | +
|
| 16 | +--- |
| 17 | + |
| 18 | +## 1) Common prerequisites |
| 19 | + |
| 20 | +- **Python**: 3.12.x recommended (matching your dev environment). |
| 21 | +- **Pip / Build tools**: |
| 22 | + ```bash |
| 23 | + python -m pip install --upgrade pip wheel setuptools |
| 24 | + ``` |
| 25 | +- **Project dependencies (minimal)**: |
| 26 | + ```bash |
| 27 | + # From project root: |
| 28 | + python -m pip install -r requirements.txt |
| 29 | + # Plus build-time tools: |
| 30 | + python -m pip install cx-Freeze dmgbuild |
| 31 | + ``` |
| 32 | + |
| 33 | +> Tip: Use a **virtual environment** to isolate build dependencies. |
| 34 | +> |
| 35 | +> ```bash |
| 36 | +> python -m venv .venv |
| 37 | +> source .venv/bin/activate # macOS/Linux |
| 38 | +> .venv\Scripts\activate # Windows (PowerShell or CMD) |
| 39 | +> ``` |
| 40 | +
|
| 41 | +--- |
| 42 | +
|
| 43 | +## 2) macOS: build `.app` and create `.dmg` |
| 44 | +
|
| 45 | +### 2.1 Build the `.app` with cx_Freeze (via `freeze_setup.py`) |
| 46 | +
|
| 47 | +From the project root, run: |
| 48 | +
|
| 49 | +```bash |
| 50 | +# Clean previous build artifacts (optional but recommended): |
| 51 | +rm -rf build dist |
| 52 | +
|
| 53 | +# Build the app bundle via cx_Freeze setup |
| 54 | +python freeze_setup.py build |
| 55 | +``` |
| 56 | +
|
| 57 | +- cx_Freeze creates an **.app bundle** under a path like: |
| 58 | + - `build/AnycubicNFCTaggerQT5.app` (if configured that way), or |
| 59 | + - `build/exe.macosx-<arch>-<pyver>/AnycubicNFCTaggerQT5.app` |
| 60 | + |
| 61 | +> Our `packaging/macos/dmg_settings.py` is designed to **auto-locate** the first `.app` bundle found under `build/`, |
| 62 | +> so you usually don't need to pass it explicitly to `dmgbuild`. |
| 63 | +
|
| 64 | +### 2.2 Create the `.dmg` with dmgbuild |
| 65 | + |
| 66 | +```bash |
| 67 | +# Ensure dist/ exists |
| 68 | +mkdir -p dist |
| 69 | + |
| 70 | +# Create the DMG; the title appears in Finder when opening the image |
| 71 | +python -m dmgbuild -s packaging/macos/dmg_settings.py "AnycubicNFCTaggerQT5" dist/AnycubicNFCTaggerQT5.dmg |
| 72 | +``` |
| 73 | + |
| 74 | +This produces a signed/unsigned **DMG** (depending on your dmgbuild/signing setup) at: |
| 75 | +``` |
| 76 | +dist/AnycubicNFCTaggerQT5.dmg |
| 77 | +``` |
| 78 | + |
| 79 | +#### (Optional) Code signing & notarization |
| 80 | +If you plan to distribute to other Macs without security prompts: |
| 81 | + |
| 82 | +1. **Sign** the `.app` and/or DMG with your Developer ID certificate. |
| 83 | +2. **Notarize** with Apple and **staple** the ticket. |
| 84 | +3. If you already have signing hooks in your dmgbuild settings, ensure your keychain and environment are set up before running the command. |
| 85 | + |
| 86 | +> Detailed signing/notarization steps vary per environment and certificate setup, so they are not included here. |
| 87 | +
|
| 88 | +### 2.3 Verify the DMG |
| 89 | + |
| 90 | +- Mount the DMG (double-click) and drag the `AnycubicNFCTaggerQT5.app` into `/Applications`. |
| 91 | +- Launch the app and confirm it starts without warnings (or with expected macOS Gatekeeper prompts if unsigned). |
| 92 | +- If you see missing library errors, check the **Troubleshooting** section. |
| 93 | + |
| 94 | +--- |
| 95 | + |
| 96 | +## 3) Windows: build standalone `.exe` (and optional MSI) |
| 97 | + |
| 98 | +### 3.1 Build the executable with cx_Freeze (via `freeze_setup.py`) |
| 99 | + |
| 100 | +Open **PowerShell** (or CMD) in the project root: |
| 101 | + |
| 102 | +```powershell |
| 103 | +# Optional cleanup |
| 104 | +rmdir /s /q build dist 2>$null |
| 105 | +
|
| 106 | +# Build with cx_Freeze setup |
| 107 | +python .\freeze_setup.py build |
| 108 | +``` |
| 109 | + |
| 110 | +Typical output: |
| 111 | +``` |
| 112 | +build\exe.win-amd64-3.12\AnycubicNFCTaggerQT5.exe |
| 113 | +``` |
| 114 | +The `exe.win-amd64-3.12` folder contains all required DLLs and files to run the application on another Windows machine (without Python). You can zip this folder for distribution, or continue to create an MSI installer. |
| 115 | + |
| 116 | +### 3.2 (Optional) Create an MSI installer |
| 117 | + |
| 118 | +If `freeze_setup.py` defines the `bdist_msi` command, you can run: |
| 119 | + |
| 120 | +```powershell |
| 121 | +python .\freeze_setup.py bdist_msi |
| 122 | +``` |
| 123 | +The generated MSI will be placed under `dist\`. |
| 124 | + |
| 125 | +### 3.3 Verify the Windows build |
| 126 | + |
| 127 | +- Test the `AnycubicNFCTaggerQT5.exe` on a clean Windows VM. |
| 128 | +- Confirm NFC-related features that do not require hardware at build time still open correctly. |
| 129 | +- If certain plugins or DLLs are missing, see the **Troubleshooting** section. |
| 130 | + |
| 131 | +--- |
| 132 | + |
| 133 | +## 4) Versioning & Reproducibility |
| 134 | + |
| 135 | +- Ensure the app **version** is set in your build metadata inside `freeze_setup.py` (or a central version file). Tag releases in Git to keep artifacts traceable. |
| 136 | +- Prefer pinned versions in `requirements.txt` for reproducible builds. |
| 137 | +- Use consistent Python versions across dev and CI to avoid ABI mismatches. |
| 138 | + |
| 139 | +--- |
| 140 | + |
| 141 | +## 5) Typical folder layout after successful builds |
| 142 | + |
| 143 | +``` |
| 144 | +project-root/ |
| 145 | +├─ build/ |
| 146 | +│ ├─ AnycubicNFCTaggerQT5.app # (macOS) or under exe.macosx-*/... |
| 147 | +│ └─ exe.win-amd64-3.12/AnycubicNFCTaggerQT5.exe # (Windows) with needed DLLs |
| 148 | +├─ dist/ |
| 149 | +│ ├─ AnycubicNFCTaggerQT5.dmg # (macOS) |
| 150 | +│ └─ AnycubicNFCTaggerQT5-<version>.msi # (Windows, optional) |
| 151 | +└─ packaging/ |
| 152 | + └─ macos/ |
| 153 | + └─ dmg_settings.py |
| 154 | +``` |
| 155 | + |
| 156 | +--- |
| 157 | + |
| 158 | +## 6) Troubleshooting |
| 159 | + |
| 160 | +### macOS |
| 161 | +- **App won’t start / missing libraries**: Ensure `cx_Freeze` collected Qt plugins (platforms, imageformats). If not, add them via `include_files` in `freeze_setup.py` options. |
| 162 | +- **DMG creation fails**: Verify `dmgbuild` is installed and that `packaging/macos/dmg_settings.py` exists. It must be able to locate the `.app` inside `build/`. |
| 163 | +- **Gatekeeper warnings**: Unsigned apps will show warnings on first launch. Consider code signing and notarization for smoother distribution. |
| 164 | + |
| 165 | +### Windows |
| 166 | +- **DLL not found** at runtime: Add the missing DLL or Qt plugin directory to `include_files` in `freeze_setup.py` options. |
| 167 | +- **App launches only on dev machine**: You likely depend on a system library missing on the target. Test on a clean VM and include the dependency in the build. |
| 168 | +- **Antivirus flags the EXE**: Signing the executable and using a reputable installer (MSI) can reduce false positives. |
| 169 | + |
| 170 | +### Cross-platform |
| 171 | +- **Wrong Python/Qt build**: Mixing ARM64 vs x86_64 (or different Python minors) can break packaging. Build on the target platform/arch. |
| 172 | +- **Paths with spaces**: Quote your paths or use short forms, especially in Windows PowerShell/CMD. |
| 173 | + |
| 174 | +--- |
| 175 | + |
| 176 | +## 7) One-shot commands (quick reference) |
| 177 | + |
| 178 | +### macOS |
| 179 | +```bash |
| 180 | +python -m venv .venv && source .venv/bin/activate |
| 181 | +python -m pip install --upgrade pip wheel setuptools |
| 182 | +python -m pip install -r requirements.txt |
| 183 | +python -m pip install cx-Freeze dmgbuild |
| 184 | +rm -rf build dist |
| 185 | +python freeze_setup.py build |
| 186 | +mkdir -p dist |
| 187 | +python -m dmgbuild -s packaging/macos/dmg_settings.py "AnycubicNFCTaggerQT5" dist/AnycubicNFCTaggerQT5.dmg |
| 188 | +``` |
| 189 | + |
| 190 | +### Windows (PowerShell) |
| 191 | +```powershell |
| 192 | +python -m venv .venv; .\.venv\Scripts\Activate.ps1 |
| 193 | +python -m pip install --upgrade pip wheel setuptools |
| 194 | +python -m pip install -r requirements.txt |
| 195 | +python -m pip install cx-Freeze dmgbuild |
| 196 | +rmdir /s /q build dist 2>$null |
| 197 | +python .\freeze_setup.py build |
| 198 | +# optional: |
| 199 | +python .\freeze_setup.py bdist_msi |
| 200 | +``` |
| 201 | + |
| 202 | +--- |
| 203 | + |
| 204 | +**That’s it.** You should now have a runnable **DMG** for macOS and a standalone **EXE** (and optional **MSI**) for Windows. |
0 commit comments