From 5c4b61dc16232e2c0c571dd0d79225517fc95396 Mon Sep 17 00:00:00 2001 From: Zsolt Tasnadi Date: Mon, 3 Aug 2026 21:22:31 +0200 Subject: [PATCH] Add desktop binary export support to the examples win-x86, win-x64, linux-x64 and mac-universal targets, validated on the pong pipeline: Makefile binaries/ci-binaries targets, desktop export presets, ci-binaries step in the Woodpecker example. Mac is a single universal (intel + arm) build with built-in ad-hoc codesign and needs ETC2 ASTC texture import enabled in project.godot. Co-Authored-By: Claude Fable 5 --- README.md | 49 ++++++++++----- example-export_presets.cfg | 124 +++++++++++++++++++++++++++++++++++++ example-makefile.make | 70 ++++++++++++++++++++- example-woodpecker.yaml | 1 + 4 files changed, 227 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index bb8b4cf..15a5d05 100644 --- a/README.md +++ b/README.md @@ -5,17 +5,20 @@ projects, in the same spirit as [ebitengine-tools](../ebitengine-tools) and [tic80-tools](../tic80-tools). - `example-makefile.make` — project Makefile: local dev targets - (`build`, `run`, `web`, `export`, `watch`, `clean`) plus the - Woodpecker pipeline targets (`ci-version`, `ci-export`, `ci-upload`, - `ci-update`). + (`build`, `run`, `web`, `export`, `watch`, `clean`), the desktop + binary targets (`binaries`, `binary-win-x86`, `binary-win-x64`, + `binary-linux-x64`, `binary-mac-universal`) plus the Woodpecker + pipeline targets (`ci-version`, `ci-export`, `ci-binaries`, + `ci-upload`, `ci-update`). - `example-woodpecker.yaml` — Woodpecker pipeline: version → build - (headless web export in the `barichello/godot-ci` image) → upload - (scp to the droparea) → update (calls the teletypegames `/update` - endpoint with `platform=godot`). -- `example-export_presets.cfg` — minimal `export_presets.cfg` with the - **Web** preset the Makefile exports. Threads are disabled - (`variant/thread_support=false`, Godot 4.3+) so the build runs - without COOP/COEP (cross-origin isolation) headers. + (headless web export + desktop binaries in the `barichello/godot-ci` + image) → upload (scp to the droparea) → update (calls the + teletypegames `/update` endpoint with `platform=godot`). +- `example-export_presets.cfg` — `export_presets.cfg` with the **Web** + preset the Makefile exports plus the desktop presets (**Windows + x86**, **Windows x64**, **Linux x64**, **Mac universal**). Web + threads are disabled (`variant/thread_support=false`, Godot 4.3+) so + the build runs without COOP/COEP (cross-origin isolation) headers. - `example-tasks.json` — VS Code `.vscode/tasks.json` with the common dev tasks: **Run** (`godot --path .`, default build task, `Cmd+Shift+B`), **Edit**, **Export Web** and **Make build**. @@ -25,8 +28,18 @@ and [tic80-tools](../tic80-tools). 1. Copy `example-makefile.make` to `Makefile` and set `PROJECT` (the web build is packaged as `$(PROJECT)-$(VERSION).html.zip`). 2. Copy `example-export_presets.cfg` to `export_presets.cfg` (or merge - the `Web` preset into your existing presets). Keep the preset name - in sync with `EXPORT_PRESET` in the Makefile. + the presets into your existing file). Keep the preset names in sync + with the Makefile (`EXPORT_PRESET` for web, the `B_PRESET` values of + the `binary-*` targets for desktop), and set + `application/bundle_identifier` in the Mac preset to your project. + For the universal mac export enable ETC2 ASTC texture import in + `project.godot`: + + ```ini + [rendering] + + textures/vram_compression/import_etc2_astc=true + ``` 3. Copy `example-woodpecker.yaml` to `.woodpecker.yaml` and add the `droparea_ssh_password` / `update_secret_key` secrets in Woodpecker. Match the `godot-builder` image tag to the Godot version the @@ -34,9 +47,15 @@ and [tic80-tools](../tic80-tools). `barichello/godot-ci` image ships the matching export templates. 4. Copy `example-tasks.json` to `.vscode/tasks.json`. -The pipeline uploads `$(PROJECT)-$(VERSION).html.zip` to the droparea, -then triggers -`/update?platform=godot&name=$(PROJECT)&version=$(VERSION)`. +The pipeline uploads `$(PROJECT)-$(VERSION).html.zip` and the desktop +binary zips (`$(PROJECT)-$(VERSION)-.zip`, targets: `win-x86`, +`win-x64`, `linux-x64`, `mac-universal`) to the droparea, then triggers +`/update?platform=godot&name=$(PROJECT)&version=$(VERSION)`, which +attaches them to the release as ReleaseAssets. Godot cross-exports all +desktop platforms from the linux CI image with the official export +templates; mac is a single universal (intel + arm) build with Godot's +built-in ad-hoc codesign — per-arch mac export would need custom-built +templates. ## Builder image diff --git a/example-export_presets.cfg b/example-export_presets.cfg index fa0c4f6..4dbf8a9 100644 --- a/example-export_presets.cfg +++ b/example-export_presets.cfg @@ -41,3 +41,127 @@ html/canvas_resize_policy=2 html/focus_canvas_on_start=true html/experimental_virtual_keyboard=false progressive_web_app/enabled=false + +; Desktop presets: the preset names match the Makefile's binary-* targets +; and the resulting zips follow the ReleaseAsset naming +; (--.zip). Windows/Linux embed the .pck into +; the executable (single-file builds); `modify_resources=false` because +; the CI image has no rcedit. + +[preset.1] + +name="Windows x64" +platform="Windows Desktop" +runnable=true +advanced_options=false +dedicated_server=false +custom_features="" +export_filter="all_resources" +include_filter="" +exclude_filter="" +export_path="" +patches=PackedStringArray() +encryption_include_filters="" +encryption_exclude_filters="" +seed=0 +encrypt_pck=false +encrypt_directory=false +script_export_mode=2 + +[preset.1.options] + +binary_format/architecture="x86_64" +binary_format/embed_pck=true +application/modify_resources=false +codesign/enable=false + +[preset.2] + +name="Windows x86" +platform="Windows Desktop" +runnable=true +advanced_options=false +dedicated_server=false +custom_features="" +export_filter="all_resources" +include_filter="" +exclude_filter="" +export_path="" +patches=PackedStringArray() +encryption_include_filters="" +encryption_exclude_filters="" +seed=0 +encrypt_pck=false +encrypt_directory=false +script_export_mode=2 + +[preset.2.options] + +binary_format/architecture="x86_32" +binary_format/embed_pck=true +application/modify_resources=false +codesign/enable=false + +[preset.3] + +name="Linux x64" +platform="Linux" +runnable=true +advanced_options=false +dedicated_server=false +custom_features="" +export_filter="all_resources" +include_filter="" +exclude_filter="" +export_path="" +patches=PackedStringArray() +encryption_include_filters="" +encryption_exclude_filters="" +seed=0 +encrypt_pck=false +encrypt_directory=false +script_export_mode=2 + +[preset.3.options] + +binary_format/architecture="x86_64" +binary_format/embed_pck=true + +; macOS: a single universal (x86_64 + arm64) build — the official export +; templates only ship a universal binary, per-arch export would need +; custom-built templates. Exported as .zip (the only option when +; exporting from Linux), signed with Godot's built-in ad-hoc codesign +; (codesign/codesign=1), which works on any host platform. arm64 macOS +; refuses to run completely unsigned binaries, so signing is required. +; The universal export also requires ETC2 ASTC texture import in +; project.godot ([rendering] textures/vram_compression/import_etc2_astc=true), +; the arm64 slice refuses to export without it. + +[preset.4] + +name="Mac universal" +platform="macOS" +runnable=true +advanced_options=false +dedicated_server=false +custom_features="" +export_filter="all_resources" +include_filter="" +exclude_filter="" +export_path="" +patches=PackedStringArray() +encryption_include_filters="" +encryption_exclude_filters="" +seed=0 +encrypt_pck=false +encrypt_directory=false +script_export_mode=2 + +[preset.4.options] + +export/distribution_type=1 +binary_format/architecture="universal" +application/bundle_identifier="org.teletypegames.godotdemo" +codesign/codesign=1 +notarization/notarization=0 + diff --git a/example-makefile.make b/example-makefile.make index 3476ac0..2276df8 100644 --- a/example-makefile.make +++ b/example-makefile.make @@ -35,6 +35,67 @@ export: web @echo "==> Cleaning temporary files" rm -rf $(WEB_DIR) +# --- native binaries --------------------------------------------------------- +# Godot cross-exports every desktop platform from linux with the official +# export templates, so unlike ebitengine ALL targets build in CI. Mac is a +# single universal (intel + arm) build: the official templates only ship a +# universal binary, per-arch export would need custom-built templates. +# Zip layout follows the ReleaseAsset convention: a single root folder, +# --/, zipped as --.zip. +BINARY_TARGETS = win-x86 win-x64 linux-x64 mac-universal + +binaries: build + @if [ -z "$(VERSION)" ]; then \ + echo "ERROR: VERSION not set!"; exit 1; \ + fi + @for target in $(BINARY_TARGETS); do \ + $(MAKE) binary-$$target VERSION=$(VERSION) || exit 1; \ + done + +binary-win-x86: + @$(MAKE) binary-build VERSION=$(VERSION) B_PRESET="Windows x86" B_EXT=.exe B_TARGET=win-x86 + +binary-win-x64: + @$(MAKE) binary-build VERSION=$(VERSION) B_PRESET="Windows x64" B_EXT=.exe B_TARGET=win-x64 + +binary-linux-x64: + @$(MAKE) binary-build VERSION=$(VERSION) B_PRESET="Linux x64" B_EXT= B_TARGET=linux-x64 + +binary-mac-universal: + @$(MAKE) binary-build-mac VERSION=$(VERSION) B_PRESET="Mac universal" B_TARGET=mac-universal + +# belső helper: egy win/linux target exportja + zip egyetlen gyökérmappával +# (embed_pck miatt az export egyetlen futtatható fájl) +binary-build: + @set -e; \ + PKG_DIR="$(PROJECT)-$(VERSION)-$(B_TARGET)"; \ + echo "==> Building $$PKG_DIR"; \ + rm -rf "$$PKG_DIR" "$$PKG_DIR.zip"; \ + mkdir -p "$$PKG_DIR"; \ + $(GODOT) --headless --export-release "$(B_PRESET)" "$$(pwd)/$$PKG_DIR/$(PROJECT)$(B_EXT)"; \ + if [ -f LICENSE ]; then cp LICENSE "$$PKG_DIR/"; fi; \ + if [ -f README.md ]; then cp README.md "$$PKG_DIR/"; fi; \ + zip -r "$$PKG_DIR.zip" "$$PKG_DIR" >/dev/null; \ + rm -rf "$$PKG_DIR"; \ + echo "==> $$PKG_DIR.zip kesz" + +# mac helper: a Godot linuxról csak .zip-be tud macOS-t exportálni (benne a +# .app), ezt csomagoljuk át a gyökérmappás konvencióra (zip -ry: exec bitek +# és symlinkek megmaradnak) +binary-build-mac: + @set -e; \ + PKG_DIR="$(PROJECT)-$(VERSION)-$(B_TARGET)"; \ + echo "==> Building $$PKG_DIR"; \ + rm -rf "$$PKG_DIR" "$$PKG_DIR.zip"; \ + mkdir -p "$$PKG_DIR"; \ + $(GODOT) --headless --export-release "$(B_PRESET)" "$$(pwd)/$$PKG_DIR/$(PROJECT)-mac-tmp.zip"; \ + cd "$$PKG_DIR" && unzip -q "$(PROJECT)-mac-tmp.zip" && rm "$(PROJECT)-mac-tmp.zip"; cd ..; \ + if [ -f LICENSE ]; then cp LICENSE "$$PKG_DIR/"; fi; \ + if [ -f README.md ]; then cp README.md "$$PKG_DIR/"; fi; \ + zip -ry "$$PKG_DIR.zip" "$$PKG_DIR" >/dev/null; \ + rm -rf "$$PKG_DIR"; \ + echo "==> $$PKG_DIR.zip kesz" + watch: fswatch -o . --include="\.gd$$" --include="\.tscn$$" | while read; do make build; done @@ -57,18 +118,23 @@ ci-export: @VERSION=$$(cat $(VERSION_FILE)); \ $(MAKE) export VERSION=$$VERSION +ci-binaries: + @VERSION=$$(cat $(VERSION_FILE)); \ + $(MAKE) binaries VERSION=$$VERSION + ci-upload: @VERSION=$$(cat $(VERSION_FILE)); \ FILE="$(PROJECT)-$$VERSION.html.zip"; \ META_SRC="metadata.json"; \ META_DST="$(PROJECT)-$$VERSION.metadata.json"; \ + BINS=$$(ls $(PROJECT)-$$VERSION-*.zip 2>/dev/null || true); \ cp $$META_SRC $$META_DST; \ sshpass -p "$(DROPAREA_SSH_PASSWORD)" scp -o StrictHostKeyChecking=no -P $(DROPAREA_PORT) \ - $$FILE $$META_DST \ + $$FILE $$META_DST $$BINS \ $(DROPAREA_USER)@$(DROPAREA_HOST):$(DROPAREA_TARGET_PATH)/ ci-update: @VERSION=$$(cat $(VERSION_FILE)); \ curl "$(UPDATE_SERVER)/update?secret=$(UPDATE_SECRET)&name=$(PROJECT)&platform=godot&version=$$VERSION" -.PHONY: all build run web export watch clean ci-version ci-export ci-upload ci-update +.PHONY: all build run web export watch clean binaries binary-win-x86 binary-win-x64 binary-linux-x64 binary-mac-universal binary-build binary-build-mac ci-version ci-export ci-binaries ci-upload ci-update diff --git a/example-woodpecker.yaml b/example-woodpecker.yaml index 7d2d253..6d0abd6 100644 --- a/example-woodpecker.yaml +++ b/example-woodpecker.yaml @@ -9,6 +9,7 @@ steps: image: git.teletypegames.org/internal/godot-builder:4.6 commands: - make ci-export + - make ci-binaries - name: artifact image: alpine