From cad3d1339bf1b4dfd91caacf2853bb99473fca9c Mon Sep 17 00:00:00 2001 From: Caleb Allen Date: Fri, 14 Aug 2026 23:09:24 -0400 Subject: [PATCH] fix(packaging): put the release recipes on v3's build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Neither packaging/arch/PKGBUILD nor the Homebrew formula had been run since Phase 1, and both were still calling v2's CLI: `wails3 build` takes -tags, -obfuscated and -garbleargs and nothing else, so `-clean -trimpath -ldflags` fails at the flag parser. Both also installed from build/bin/, which is v2's output path — v3 writes to bin/, and build/ is tracked build assets now. Three more things the tree needs that neither recipe had. The tasks invoke `wails3` by bare name, so scripts/toolbin has to be on PATH or the build dies at its first sub-task. `wails3 build` has no -ldflags at all, and build:native computes BUILD_FLAGS in its own vars: so a CLI variable cannot override it — LDFLAGS_EXTRA is appended inside the production -ldflags string instead, on linux and darwin alike, empty by default so make build-dev/build-prod are unchanged. And bundling is a separate step from building: `task build` produces a bare binary on both platforms, so the formula's macOS path runs `task package`. The build assets were the scaffold's, not this app's. Info.plist named CFBundleExecutable `yjref` and com.example.yjref, nfpm packaged ./bin/yjref, the .desktop template said "A yjref application" — an .app built from that plist would not have launched. They generate from build/config.yml, whose info block had never been filled from wails.json either; `wails3 task common:update:build-assets` is the fix. nfpm's homepage and license are not derived from it and are set by hand, which is noted in place, and the refresh regenerates build/ios and build/android, which this repo does not carry. arch-package.yml's pacman list moves to webkitgtk-6.0/gtk4 to match the PKGBUILD's depends(): makepkg installs nothing itself, so a mismatch fails at link time rather than at check time. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01UDCbcCZQepnpSQYJ6SxxZm --- .gitea/workflows/arch-package.yml | 6 ++- .gitignore | 8 +++ build/config.yml | 9 +++- build/darwin/Info.dev.plist | 63 +++++++++++----------- build/darwin/Info.plist | 53 +++++++++--------- build/darwin/Taskfile.yml | 5 +- build/linux/Taskfile.yml | 10 +++- build/linux/desktop | 10 ++-- build/linux/nfpm/nfpm.yaml | 25 +++++---- build/windows/info.json | 14 ++--- build/windows/nsis/wails_tools.nsh | 10 ++-- build/windows/wails.exe.manifest | 2 +- packaging/arch/PKGBUILD | 23 ++++++-- packaging/homebrew/Formula/yellowjacket.rb | 42 ++++++++++----- packaging/homebrew/README.md | 13 +++-- 15 files changed, 178 insertions(+), 115 deletions(-) diff --git a/.gitea/workflows/arch-package.yml b/.gitea/workflows/arch-package.yml index 838115e..24bfd58 100644 --- a/.gitea/workflows/arch-package.yml +++ b/.gitea/workflows/arch-package.yml @@ -22,9 +22,13 @@ jobs: steps: - name: Install build dependencies run: | + # Wails v3 resolves GTK4 + WebKitGTK 6.0 by default; webkit2gtk-4.1 + + # gtk3 was v2's stack and is now only the `-tags gtk3` escape hatch. + # These must match the PKGBUILD's depends=() — makepkg installs + # nothing itself, so a mismatch fails at link time, not at check time. pacman -Syu --noconfirm --needed \ base-devel git go nodejs pnpm curl sudo \ - webkit2gtk-4.1 gtk3 alsa-lib + webkitgtk-6.0 gtk4 alsa-lib - name: Create unprivileged build user run: | diff --git a/.gitignore b/.gitignore index 9c00447..750e605 100644 --- a/.gitignore +++ b/.gitignore @@ -62,3 +62,11 @@ bin/ # build/config.yml on every build, and consumed by the deb/rpm/AppImage # packaging tasks that depend on it. A derived file with one source. build/linux/yellowjacket.desktop + +# `wails3 task common:update:build-assets` regenerates the mobile trees +# whether or not anything asks for them. This is a desktop player and +# cannot target iOS/Android, so their includes: entries are dropped from +# Taskfile.yml and the trees themselves are not carried — ignored rather +# than deleted-and-rediscovered on every asset refresh. +build/ios/ +build/android/ diff --git a/build/config.yml b/build/config.yml index 8910198..b2f6594 100644 --- a/build/config.yml +++ b/build/config.yml @@ -4,14 +4,19 @@ version: '3' # This information is used to generate the build assets. +# The version here is the one baked into the platform *metadata* assets +# (Info.plist, the .desktop file, nfpm). It is not what the app reports: +# main.version is stamped at link time from the packaging recipes, which +# derive it from the git tag. Keep it in step with packaging/arch/PKGBUILD's +# pkgver and the Homebrew formula's version when cutting a release. info: companyName: "yellowjacket" # The name of the company productName: "yellowjacket" # The name of the application productIdentifier: "app.yellowjacket" # The unique product identifier - description: "A cross-platform desktop music player" # The application description + description: "Cross-platform desktop music player — local library, MusicBrainz explore & auto-tag" # The application description copyright: "(c) 2026, yellowjacket" # Copyright text comments: "yj@yellowjacket.app" # Comments - version: "0.0.1" # The application version + version: "1.3.0" # The application version # cfBundleIconName: "appicon" # The macOS icon name in Assets.car icon bundles (optional) # # Should match the name of your .icon file without the extension # # If not set and Assets.car exists, defaults to "appicon" diff --git a/build/darwin/Info.dev.plist b/build/darwin/Info.dev.plist index a12f1ef..d4bf0cf 100644 --- a/build/darwin/Info.dev.plist +++ b/build/darwin/Info.dev.plist @@ -1,34 +1,35 @@ + - - CFBundlePackageType - APPL - CFBundleName - My Product - CFBundleExecutable - yjref - CFBundleIdentifier - com.example.yjref - CFBundleVersion - 0.1.0 - CFBundleGetInfoString - This is a comment - CFBundleShortVersionString - 0.1.0 - CFBundleIconFile - icons - CFBundleIconName - appicon - LSMinimumSystemVersion - 12.0.0 - NSHighResolutionCapable - true - NSHumanReadableCopyright - © 2026, My Company - NSAppTransportSecurity - - NSAllowsLocalNetworking - - - + + CFBundleExecutable + yellowjacket + CFBundleGetInfoString + yj@yellowjacket.app + CFBundleIconFile + icons + CFBundleIconName + appicon + CFBundleIdentifier + app.yellowjacket + CFBundleName + yellowjacket + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.3.0 + CFBundleVersion + 1.3.0 + LSMinimumSystemVersion + 12.0.0 + NSAppTransportSecurity + + NSAllowsLocalNetworking + + + NSHighResolutionCapable + true + NSHumanReadableCopyright + (c) 2026, yellowjacket + \ No newline at end of file diff --git a/build/darwin/Info.plist b/build/darwin/Info.plist index cc6b861..abbc300 100644 --- a/build/darwin/Info.plist +++ b/build/darwin/Info.plist @@ -1,29 +1,30 @@ + - - CFBundlePackageType - APPL - CFBundleName - My Product - CFBundleExecutable - yjref - CFBundleIdentifier - com.example.yjref - CFBundleVersion - 0.1.0 - CFBundleGetInfoString - This is a comment - CFBundleShortVersionString - 0.1.0 - CFBundleIconFile - icons - CFBundleIconName - appicon - LSMinimumSystemVersion - 12.0.0 - NSHighResolutionCapable - true - NSHumanReadableCopyright - © 2026, My Company - + + CFBundleExecutable + yellowjacket + CFBundleGetInfoString + yj@yellowjacket.app + CFBundleIconFile + icons + CFBundleIconName + appicon + CFBundleIdentifier + app.yellowjacket + CFBundleName + yellowjacket + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.3.0 + CFBundleVersion + 1.3.0 + LSMinimumSystemVersion + 12.0.0 + NSHighResolutionCapable + true + NSHumanReadableCopyright + (c) 2026, yellowjacket + \ No newline at end of file diff --git a/build/darwin/Taskfile.yml b/build/darwin/Taskfile.yml index e3ee1ee..9cb87c8 100644 --- a/build/darwin/Taskfile.yml +++ b/build/darwin/Taskfile.yml @@ -43,7 +43,10 @@ tasks: cmds: - '{{if eq .OBFUSCATED "true"}}garble {{.GARBLE_ARGS}} build{{else}}go build{{end}} {{.BUILD_FLAGS}} -o "{{.OUTPUT}}"' vars: - BUILD_FLAGS: '{{if eq .DEV "true"}}{{if or .EXTRA_TAGS (eq .OBFUSCATED "true")}}-tags {{if eq .OBFUSCATED "true"}}wails_obfuscated{{if .EXTRA_TAGS}},{{end}}{{end}}{{.EXTRA_TAGS}} {{end}}-buildvcs=false -gcflags=all="-l"{{else}}-tags production{{if eq .OBFUSCATED "true"}},wails_obfuscated{{end}}{{if .EXTRA_TAGS}},{{.EXTRA_TAGS}}{{end}} -trimpath -buildvcs=false -ldflags="-w -s"{{end}}' + # LDFLAGS_EXTRA — see build/linux/Taskfile.yml for why this exists. + # Kept identical on both platforms so the Homebrew formula, which + # builds on either, has one invocation rather than two. + BUILD_FLAGS: '{{if eq .DEV "true"}}{{if or .EXTRA_TAGS (eq .OBFUSCATED "true")}}-tags {{if eq .OBFUSCATED "true"}}wails_obfuscated{{if .EXTRA_TAGS}},{{end}}{{end}}{{.EXTRA_TAGS}} {{end}}-buildvcs=false -gcflags=all="-l"{{else}}-tags production{{if eq .OBFUSCATED "true"}},wails_obfuscated{{end}}{{if .EXTRA_TAGS}},{{.EXTRA_TAGS}}{{end}} -trimpath -buildvcs=false -ldflags="-w -s{{if .LDFLAGS_EXTRA}} {{.LDFLAGS_EXTRA}}{{end}}"{{end}}' DEFAULT_OUTPUT: '{{.BIN_DIR}}/{{.APP_NAME}}' OUTPUT: '{{ .OUTPUT | default .DEFAULT_OUTPUT }}' env: diff --git a/build/linux/Taskfile.yml b/build/linux/Taskfile.yml index 496ee95..122bbf5 100644 --- a/build/linux/Taskfile.yml +++ b/build/linux/Taskfile.yml @@ -59,7 +59,15 @@ tasks: cmds: - '{{if eq .OBFUSCATED "true"}}garble {{.GARBLE_ARGS}} build{{else}}go build{{end}} {{.BUILD_FLAGS}} -o {{.OUTPUT}}' vars: - BUILD_FLAGS: '{{if eq .DEV "true"}}{{if or .EXTRA_TAGS (eq .OBFUSCATED "true")}}-tags {{if eq .OBFUSCATED "true"}}wails_obfuscated{{if .EXTRA_TAGS}},{{end}}{{end}}{{.EXTRA_TAGS}} {{end}}-buildvcs=false -gcflags=all="-l"{{else}}-tags production{{if eq .OBFUSCATED "true"}},wails_obfuscated{{end}}{{if .EXTRA_TAGS}},{{.EXTRA_TAGS}}{{end}} -trimpath -buildvcs=false -ldflags="-w -s"{{end}}' + # LDFLAGS_EXTRA is this repo's one edit to the scaffold: `wails3 + # build` has no -ldflags flag of its own, and the packaging recipes + # (packaging/arch/PKGBUILD, the Homebrew formula) need to stamp + # main.version / main.commit. Pass it as a task variable: + # wails3 task build LDFLAGS_EXTRA="-X 'main.version=v1.3.0'" + # It is appended inside the production -ldflags string, so the + # default -w -s still applies. Empty by default, which is what + # keeps `make build-dev` / `make build-prod` unchanged. + BUILD_FLAGS: '{{if eq .DEV "true"}}{{if or .EXTRA_TAGS (eq .OBFUSCATED "true")}}-tags {{if eq .OBFUSCATED "true"}}wails_obfuscated{{if .EXTRA_TAGS}},{{end}}{{end}}{{.EXTRA_TAGS}} {{end}}-buildvcs=false -gcflags=all="-l"{{else}}-tags production{{if eq .OBFUSCATED "true"}},wails_obfuscated{{end}}{{if .EXTRA_TAGS}},{{.EXTRA_TAGS}}{{end}} -trimpath -buildvcs=false -ldflags="-w -s{{if .LDFLAGS_EXTRA}} {{.LDFLAGS_EXTRA}}{{end}}"{{end}}' DEFAULT_OUTPUT: '{{.BIN_DIR}}/{{.APP_NAME}}' OUTPUT: '{{ .OUTPUT | default .DEFAULT_OUTPUT }}' env: diff --git a/build/linux/desktop b/build/linux/desktop index f0c788a..c8b126d 100644 --- a/build/linux/desktop +++ b/build/linux/desktop @@ -1,13 +1,13 @@ [Desktop Entry] Version=1.0 -Name=My Product -Comment=A yjref application +Name=yellowjacket +Comment=Cross-platform desktop music player — local library, MusicBrainz explore & auto-tag # The Exec line includes %u to pass the URL to the application -Exec=/usr/local/bin/yjref %u +Exec=/usr/local/bin/yellowjacket %u Terminal=false Type=Application -Icon=yjref +Icon=yellowjacket Categories=Utility; -StartupWMClass=yjref +StartupWMClass=yellowjacket diff --git a/build/linux/nfpm/nfpm.yaml b/build/linux/nfpm/nfpm.yaml index d7845a8..aef792c 100644 --- a/build/linux/nfpm/nfpm.yaml +++ b/build/linux/nfpm/nfpm.yaml @@ -3,26 +3,29 @@ # # The lines below are called `modelines`. See `:help modeline` -name: "yjref" +name: "yellowjacket" arch: ${GOARCH} platform: "linux" -version: "0.1.0" +version: "1.3.0" section: "default" priority: "extra" maintainer: ${GIT_COMMITTER_NAME} <${GIT_COMMITTER_EMAIL}> -description: "A yjref application" -vendor: "My Company" -homepage: "https://wails.io" -license: "MIT" +description: "Cross-platform desktop music player — local library, MusicBrainz explore & auto-tag" +vendor: "yellowjacket" +# homepage and license are NOT derived from build/config.yml, so +# `wails3 task common:update:build-assets` leaves them alone — everything +# above them is regenerated from that file and hand edits there are lost. +homepage: "https://git.ljones.me/yonlu/yellowjacket" +license: "custom" # see the repository; packaging/arch/PKGBUILD says the same release: "1" contents: - - src: "./bin/yjref" - dst: "/usr/local/bin/yjref" + - src: "./bin/yellowjacket" + dst: "/usr/local/bin/yellowjacket" - src: "./build/appicon.png" - dst: "/usr/share/icons/hicolor/128x128/apps/yjref.png" - - src: "./build/linux/yjref.desktop" - dst: "/usr/share/applications/yjref.desktop" + dst: "/usr/share/icons/hicolor/128x128/apps/yellowjacket.png" + - src: "./build/linux/yellowjacket.desktop" + dst: "/usr/share/applications/yellowjacket.desktop" # Default dependencies for the GTK4 + WebKitGTK 6.0 stack (Ubuntu 24.04+ / Debian 13+) depends: diff --git a/build/windows/info.json b/build/windows/info.json index 1837fed..8329577 100644 --- a/build/windows/info.json +++ b/build/windows/info.json @@ -1,15 +1,15 @@ { "fixed": { - "file_version": "0.1.0" + "file_version": "1.3.0" }, "info": { "0000": { - "ProductVersion": "0.1.0", - "CompanyName": "My Company", - "FileDescription": "A yjref application", - "LegalCopyright": "© 2026, My Company", - "ProductName": "My Product", - "Comments": "This is a comment" + "ProductVersion": "1.3.0", + "CompanyName": "yellowjacket", + "FileDescription": "Cross-platform desktop music player — local library, MusicBrainz explore & auto-tag", + "LegalCopyright": "(c) 2026, yellowjacket", + "ProductName": "yellowjacket", + "Comments": "yj@yellowjacket.app" } } } \ No newline at end of file diff --git a/build/windows/nsis/wails_tools.nsh b/build/windows/nsis/wails_tools.nsh index 7299303..61d6fda 100644 --- a/build/windows/nsis/wails_tools.nsh +++ b/build/windows/nsis/wails_tools.nsh @@ -5,19 +5,19 @@ !include "FileFunc.nsh" !ifndef INFO_PROJECTNAME - !define INFO_PROJECTNAME "yjref" + !define INFO_PROJECTNAME "yellowjacket" !endif !ifndef INFO_COMPANYNAME - !define INFO_COMPANYNAME "My Company" + !define INFO_COMPANYNAME "yellowjacket" !endif !ifndef INFO_PRODUCTNAME - !define INFO_PRODUCTNAME "My Product" + !define INFO_PRODUCTNAME "yellowjacket" !endif !ifndef INFO_PRODUCTVERSION - !define INFO_PRODUCTVERSION "0.1.0" + !define INFO_PRODUCTVERSION "1.3.0" !endif !ifndef INFO_COPYRIGHT - !define INFO_COPYRIGHT "© 2026, My Company" + !define INFO_COPYRIGHT "(c) 2026, yellowjacket" !endif !ifndef PRODUCT_EXECUTABLE !define PRODUCT_EXECUTABLE "${INFO_PROJECTNAME}.exe" diff --git a/build/windows/wails.exe.manifest b/build/windows/wails.exe.manifest index e505ed8..d62c455 100644 --- a/build/windows/wails.exe.manifest +++ b/build/windows/wails.exe.manifest @@ -1,6 +1,6 @@ - + diff --git a/packaging/arch/PKGBUILD b/packaging/arch/PKGBUILD index f2d9dc8..e2fa916 100644 --- a/packaging/arch/PKGBUILD +++ b/packaging/arch/PKGBUILD @@ -46,17 +46,30 @@ build() { local commit commit="$(git rev-parse --short HEAD)" - # `go tool wails/sqlc/templ` resolve from the tool directives in go.mod, so no - # extra CLIs are needed. Wails runs the frontend install+build itself. + # `go tool wails3/sqlc/templ` resolve from the tool directives in go.mod, so + # no extra CLIs are needed. Wails runs the frontend install+build itself. + # + # v3's build is a Taskfile tree, and the tasks in it invoke `wails3` by bare + # name — so the vendored tool has to be on PATH under that name or the build + # dies at its first sub-task with "wails3: command not found". scripts/toolbin + # is the shim the Makefile uses for the same reason; see the header there. + export PATH="$srcdir/$pkgname/scripts/toolbin:$PATH" + + # `wails3 build` has no -ldflags flag of its own (that was v2), so the version + # stamp goes through the LDFLAGS_EXTRA task variable this repo added to + # build/linux/Taskfile.yml. -trimpath and -w -s are already in the production + # task's own flags, which is where -clean's frontend rebuild went too. go generate ./... - go tool wails3 build -clean -trimpath \ - -ldflags "-s -w -X 'main.version=v$pkgver' -X 'main.commit=$commit'" + go tool wails3 task build \ + LDFLAGS_EXTRA="-X 'main.version=v$pkgver' -X 'main.commit=$commit'" } package() { cd "$srcdir/$pkgname" - install -Dm755 build/bin/yellowjacket "$pkgdir/usr/bin/yellowjacket" + # v3 writes to bin/, not v2's build/bin/ — build/ is tracked build *assets* + # now (build/config.yml, the icon, the platform Taskfiles). + install -Dm755 bin/yellowjacket "$pkgdir/usr/bin/yellowjacket" install -Dm644 "$srcdir/yellowjacket.desktop" \ "$pkgdir/usr/share/applications/yellowjacket.desktop" diff --git a/packaging/homebrew/Formula/yellowjacket.rb b/packaging/homebrew/Formula/yellowjacket.rb index 3e950b7..22e1f31 100644 --- a/packaging/homebrew/Formula/yellowjacket.rb +++ b/packaging/homebrew/Formula/yellowjacket.rb @@ -3,9 +3,10 @@ # YellowJacket — cross-platform desktop music player built with Wails (Go + Lit). # -# This formula builds from source. The Wails toolchain (`go tool wails`) resolves -# from the tool directives in go.mod, and Wails drives the frontend install/build -# itself (pnpm), so only the Go toolchain, Node, and pnpm are needed at build time. +# This formula builds from source. The Wails toolchain (`go tool wails3`) +# resolves from the tool directives in go.mod, and Wails drives the frontend +# install/build itself (pnpm), so only the Go toolchain, Node, and pnpm are +# needed at build time. # # This file is the canonical source. On each tagged release, CI computes the # tarball checksum and syncs an updated copy into the homebrew-yellowjacket tap @@ -26,7 +27,10 @@ class Yellowjacket < Formula depends_on "pnpm" => :build # Wails targets macOS and Linux. On Linux, Homebrew builds against the system - # WebKitGTK/GTK stack, which must be present (webkit2gtk-4.1, gtk3, alsa-lib). + # WebKitGTK/GTK stack, which must be present. Wails v3 resolves GTK4 + + # WebKitGTK 6.0 by default (webkitgtk-6.0, gtk4, alsa-lib); v2's + # webkit2gtk-4.1 + gtk3 is now only an opt-in `-tags gtk3` escape hatch and is + # not what this formula builds. on_linux do depends_on "pkg-config" => :build end @@ -37,24 +41,34 @@ class Yellowjacket < Formula ENV["GOFLAGS"] = "-mod=mod" commit = build.head? ? "HEAD" : "v#{version}" - ldflags = "-s -w -X 'main.version=v#{version}' -X 'main.commit=#{commit}'" + + # v3's build is a Taskfile tree whose tasks invoke `wails3` by bare name, so + # the vendored tool has to be on PATH under that name — scripts/toolbin is + # the shim the Makefile uses for the same reason. And `wails3 build` has no + # -ldflags flag of its own (that was v2), so the version stamp goes through + # the LDFLAGS_EXTRA task variable this repo added to the platform Taskfiles. + # -trimpath and -w -s are already in the production task's own flags. + ENV.prepend_path "PATH", buildpath/"scripts/toolbin" + ldflags_extra = "-X 'main.version=v#{version}' -X 'main.commit=#{commit}'" system "go", "generate", "./..." - system "go", "tool", "wails3", "build", - "-clean", "-trimpath", - "-ldflags", ldflags - # Wails emits a .app bundle on macOS and a bare ELF binary on Linux. The - # bundle is named after `outputfilename` in wails.json; glob for it so a - # rename (or casing difference) can't silently break the install. + # `task build` produces a bare binary in bin/ on both platforms; the .app + # bundle is `task package`, which is a separate step in v3. if OS.mac? - app = Dir["build/bin/*.app"].first - odie "wails build produced no .app bundle in build/bin" if app.nil? + system "go", "tool", "wails3", "task", "package", + "LDFLAGS_EXTRA=#{ldflags_extra}" + # The bundle is named after `productName` in build/config.yml; glob for it + # so a rename (or casing difference) can't silently break the install. + app = Dir["bin/*.app"].first + odie "wails3 task package produced no .app bundle in bin/" if app.nil? prefix.install app exe = Dir[prefix/"*.app/Contents/MacOS/*"].find { |f| File.executable?(f) } bin.write_exec_script exe else - bin.install "build/bin/yellowjacket" + system "go", "tool", "wails3", "task", "build", + "LDFLAGS_EXTRA=#{ldflags_extra}" + bin.install "bin/yellowjacket" end end diff --git a/packaging/homebrew/README.md b/packaging/homebrew/README.md index afd272a..b5beb1b 100644 --- a/packaging/homebrew/README.md +++ b/packaging/homebrew/README.md @@ -65,12 +65,15 @@ authenticated `brew install`) for brew to fetch the release tarball. - **License**: declared as `license :cannot_represent` (custom license). Replace with the correct SPDX identifier once the license is finalized. -- **macOS vs Linux**: `wails build` produces a `YellowJacket.app` bundle on - macOS (installed under the Cellar with an `exec` shim in `bin`) and a bare - `yellowjacket` binary on Linux (installed to `bin`). +- **macOS vs Linux**: under Wails v3 the bundling is a separate step from the + build. `wails3 task build` produces a bare `yellowjacket` binary in `bin/` on + both platforms; on macOS the formula runs `wails3 task package` instead, which + wraps that binary in a `yellowjacket.app` (installed under the Cellar with an + `exec` shim in `bin`). - **Linuxbrew**: building on Linux additionally needs the system WebKitGTK/GTK - stack (`webkit2gtk-4.1`, `gtk3`, `alsa-lib`) — OS packages, not Homebrew deps. - macOS needs only the Xcode Command Line Tools. + stack (`webkitgtk-6.0`, `gtk4`, `alsa-lib`) — OS packages, not Homebrew deps. + v2's `webkit2gtk-4.1`/`gtk3` is now only the `-tags gtk3` escape hatch. macOS + needs only the Xcode Command Line Tools. - **Cask alternative**: if you later ship prebuilt macOS `.dmg`/`.zip` artifacts, a Homebrew *cask* pointing at those installs faster than this source build. This formula is the source-build path.