From 56054a21b4afc902c96af800028c375b5b2e5c1c Mon Sep 17 00:00:00 2001 From: Zsolt Tasnadi Date: Sun, 2 Aug 2026 18:51:02 +0200 Subject: [PATCH] binary assets --- README.md | 33 ++++++++++++++++++++---------- builder.Dockerfile | 24 ++++++++++++++++------ example-makefile.make | 45 +++++++++++++++++++++++++++++++++++++++-- example-woodpecker.yaml | 5 +++++ 4 files changed, 88 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 44f1eff..41259ac 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,14 @@ CI/CD templates for [Ebitengine](https://ebitengine.org) (Go) game projects, in the same spirit as [tic80-tools](../tic80-tools). - `example-makefile.make` — project Makefile: local dev targets - (`build`, `wasm`, `export`, `watch`, `clean`) plus the Woodpecker - pipeline targets (`ci-version`, `ci-export`, `ci-upload`, - `ci-update`). + (`build`, `wasm`, `export`, `watch`, `clean`), native binary targets + (`binaries`, `binary-win-x86`, `binary-win-x64`, `binary-linux-x64`) + plus the Woodpecker pipeline targets (`ci-version`, `ci-export`, + `ci-binaries`, `ci-upload`, `ci-update`). - `example-woodpecker.yaml` — Woodpecker pipeline: version → export - (Go, `GOOS=js GOARCH=wasm`) → upload (scp to the droparea) → update - (calls the teletypegames `/update` endpoint with - `platform=ebitengine`). + (Go, `GOOS=js GOARCH=wasm`) → binaries (native desktop zips) → + upload (scp to the droparea) → update (calls the teletypegames + `/update` endpoint with `platform=ebitengine`). - `example-tasks.json` — VS Code `.vscode/tasks.json` with the common dev tasks: **Run** (`go run .`, default build task, `Cmd+Shift+B`), **Build & Run**, **Build WASM** and **Make build**. @@ -26,16 +27,26 @@ projects, in the same spirit as [tic80-tools](../tic80-tools). 3. Copy `example-tasks.json` to `.vscode/tasks.json` and replace the binary name (`ebitenginedemo`) with `$(PROJECT)`. -The pipeline uploads `$(PROJECT)-$(VERSION).html.zip` to the droparea, -then triggers +The pipeline uploads `$(PROJECT)-$(VERSION).html.zip` plus the native +binary zips (`$(PROJECT)-$(VERSION)-.zip`, currently `win-x86`, +`win-x64`, `linux-x64`) to the droparea, then triggers `/update?platform=ebitengine&name=$(PROJECT)&version=$(VERSION)`. +The updater picks up the binary zips by naming convention and attaches +them to the release as assets (see `teletypegames/NOTES_BINARY_PLAN.md`). + +Binary zip layout: a single root folder +(`$(PROJECT)-$(VERSION)-/`) containing the executable (plus +LICENSE/README.md when present). The zips are created with unix `zip`, +so the executable bit survives on the linux binary. mac targets need a +mac runner (or osxcross) and are not part of the pipeline yet. ## Builder image `builder.Dockerfile` bakes the pipeline's build-step dependencies -(Go + git/make/zip/curl) into -`git.teletypegames.org/internal/ebitengine-builder`, so the build step -no longer runs `apk add` on every run: +(Go + git/make/zip/curl/jq and the X11/GL/ALSA dev libraries needed by +the cgo `linux-x64` build) into +`git.teletypegames.org/internal/ebitengine-builder`. Debian-based so +the linux binary links against glibc: ```sh docker build --platform linux/amd64 -f builder.Dockerfile \ diff --git a/builder.Dockerfile b/builder.Dockerfile index 3314252..1419ca3 100644 --- a/builder.Dockerfile +++ b/builder.Dockerfile @@ -1,6 +1,10 @@ -# CI builder image for Ebitengine projects: Go toolchain + packaging tools. -# Used by the `build` step in example-woodpecker.yaml instead of installing -# zip/make/curl on every pipeline run. +# CI builder image for Ebitengine projects: Go toolchain + packaging tools +# + the X11/GL/ALSA dev libraries needed for the native linux-x64 (cgo) build. +# Used by the `build` and `binaries` steps in example-woodpecker.yaml instead +# of installing everything on every pipeline run. +# +# Debian-based (not alpine): the linux-x64 game binary must link against +# glibc, otherwise it won't run on regular desktop distros. # # Build & push (the CI runner is linux/amd64): # docker build --platform linux/amd64 -f builder.Dockerfile \ @@ -8,10 +12,18 @@ # docker push git.teletypegames.org/internal/ebitengine-builder:latest # 1.26 covers every current game repo's go.mod directive (1.25.x, 1.26.x). -FROM golang:1.26-alpine +FROM golang:1.26-bookworm -RUN apk add --no-cache git make zip curl +# Ebitengine linux build dependencies: +# https://ebitengine.org/en/documents/install.html (Debian/Ubuntu section) +RUN apt-get update && apt-get install -y --no-install-recommends \ + git make zip curl jq pkg-config \ + libc6-dev libgl1-mesa-dev libglu1-mesa-dev \ + libx11-dev libxcursor-dev libxi-dev libxinerama-dev \ + libxrandr-dev libxxf86vm-dev \ + libasound2-dev \ + && rm -rf /var/lib/apt/lists/* WORKDIR /workspace -CMD ["/bin/sh"] +CMD ["/bin/bash"] diff --git a/example-makefile.make b/example-makefile.make index 86276f0..912cafb 100644 --- a/example-makefile.make +++ b/example-makefile.make @@ -37,6 +37,42 @@ export: wasm @echo "==> Cleaning temporary files" rm -f $(DIST_DIR)/$(WASM_NAME) $(DIST_DIR)/wasm_exec.js $(DIST_DIR)/index.html +# --- native binaries (lásd: teletypegames/NOTES_BINARY_PLAN.md) ------------- +# win-x86 / win-x64: pure Go cross-compile (Windowson nem kell cgo) +# linux-x64: cgo build, linux/amd64 hoston fut (builder image, X11/GL dev libekkel) +BINARY_TARGETS = win-x86 win-x64 linux-x64 + +binaries: + @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_GOOS=windows B_GOARCH=386 B_CGO=0 B_EXT=.exe B_TARGET=win-x86 + +binary-win-x64: + @$(MAKE) binary-build VERSION=$(VERSION) B_GOOS=windows B_GOARCH=amd64 B_CGO=0 B_EXT=.exe B_TARGET=win-x64 + +binary-linux-x64: + @$(MAKE) binary-build VERSION=$(VERSION) B_GOOS=linux B_GOARCH=amd64 B_CGO=1 B_EXT= B_TARGET=linux-x64 + +# belső helper: egy target buildje + zip egyetlen gyökérmappával +# (a zipet unixos zip készíti, így a végrehajtási bit megmarad) +binary-build: + @PKG_DIR="$(PROJECT)-$(VERSION)-$(B_TARGET)"; \ + echo "==> Building $$PKG_DIR"; \ + rm -rf "$$PKG_DIR" "$$PKG_DIR.zip"; \ + mkdir -p "$$PKG_DIR"; \ + CGO_ENABLED=$(B_CGO) GOOS=$(B_GOOS) GOARCH=$(B_GOARCH) go build -o "$$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" + watch: fswatch -o . | while read; do make build; done @@ -59,18 +95,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=ebitengine&version=$$VERSION" -.PHONY: all build wasm export watch clean ci-version ci-export ci-upload ci-update \ No newline at end of file +.PHONY: all build wasm export watch clean binaries binary-win-x86 binary-win-x64 binary-linux-x64 binary-build ci-version ci-export ci-binaries ci-upload ci-update \ No newline at end of file diff --git a/example-woodpecker.yaml b/example-woodpecker.yaml index 55776fe..8210c55 100644 --- a/example-woodpecker.yaml +++ b/example-woodpecker.yaml @@ -10,6 +10,11 @@ steps: commands: - make ci-export + - name: binaries + image: git.teletypegames.org/internal/ebitengine-builder:latest + commands: + - make ci-binaries + - name: artifact image: alpine environment: