Repository navigation
Expand file tree
/
Copy pathMakefile
More file actions
276 lines (243 loc) · 13.5 KB
/
Copy pathMakefile
File metadata and controls
276 lines (243 loc) · 13.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
# ============================================================
# Pando — top-level Makefile
# ============================================================
GOPATH ?= $(shell go env GOPATH)
VERSION ?= $(shell git describe --tags 2>/dev/null || echo dev)
# ------------------------------------------------------------
# Build variant
# ------------------------------------------------------------
# MODULE_TAGS is the single knob for the whole variant axis: it feeds the build
# tags, the version stamp and the artifact names, so a variant can never be
# half-applied (tagged sources but a binary that reports itself as standard).
#
# Building this repository with MODULE_TAGS=enterprise links NO private module:
# composition happens in a generated main module produced by `xpando build`
# (see cmd/xpando). The tag only selects tag-guarded code inside the core, and
# the stamp records which kind of binary this is.
MODULE_TAGS ?=
GO_BUILD_TAGS = $(strip $(MODULE_TAGS))
GO_TAGS_FLAG = $(if $(GO_BUILD_TAGS),-tags "$(GO_BUILD_TAGS)",)
VARIANT := $(if $(findstring enterprise,$(MODULE_TAGS)),enterprise,)
DIST_SUFFIX := $(if $(VARIANT),-$(VARIANT),)
# The variant stamp is separate from the release stamp so that even the
# unstamped fast build reports which variant it is. A binary that carries the
# tags but calls itself standard is worse than no stamp at all.
VARIANT_LDFLAGS := $(if $(VARIANT),-X github.com/digiogithub/pando/internal/version.Variant=$(VARIANT),)
# TELEMETRY_LDFLAGS embeds the Better Stack ingest source token into the
# binary at link time, so it is never committed and never stored in user
# config (see internal/telemetry/build.go). Only set when the caller supplies
# PANDO_BETTERSTACK_TOKEN, so a token-less build (CI PR builds, `go install`,
# forks) carries no empty -X flag and simply reports telemetry as unavailable.
# Local dev: PANDO_BETTERSTACK_TOKEN=$(kvage get pando_betterstack_token) make build
# NOTE: PANDO_BETTERSTACK_TOKEN is interpolated unquoted-inside-single-quotes
# into the -ldflags string below (LDFLAGS := ... -ldflags '$(LDFLAGS)' ...).
# It must never contain a single quote ('), which would break out of that
# shell-quoted argument — Better Stack source tokens are alphanumeric, so
# this is not expected to matter in practice, but it is exactly the kind of
# thing worth flagging for anyone tempted to source this value from
# somewhere less trusted than `kvage`/a CI secret.
TELEMETRY_LDFLAGS :=
ifneq ($(PANDO_BETTERSTACK_TOKEN),)
TELEMETRY_LDFLAGS := -X github.com/digiogithub/pando/internal/telemetry.sourceToken=$(PANDO_BETTERSTACK_TOKEN)
endif
LDFLAGS := -s -w -X github.com/digiogithub/pando/internal/version.Version=$(VERSION) $(VARIANT_LDFLAGS) $(TELEMETRY_LDFLAGS)
DIST_DIR := dist
WEB_UI_DIR := web-ui
WEB_UI_INSTALL_CMD ?= bun install
WEB_UI_EMBEDDED_BUILD_CMD ?= bun run build:embedded
CGO_ENABLED ?= 1
ZIG ?= zig
UPX ?= upx
CC_LINUX_ARM64 ?= $(ZIG) cc -target aarch64-linux-gnu
CXX_LINUX_ARM64 ?= $(ZIG) c++ -target aarch64-linux-gnu
CC_WINDOWS_AMD64 ?= $(ZIG) cc -target x86_64-windows-gnu
CXX_WINDOWS_AMD64 ?= $(ZIG) c++ -target x86_64-windows-gnu
MACOS_MIN_VERSION ?= 11.0
# On Darwin, use native Apple clang for cross-arch builds (zig cannot resolve macOS system libs).
# On Linux/CI, fall back to zig for darwin targets.
ifeq ($(shell uname),Darwin)
CC_DARWIN_AMD64 ?= clang -arch x86_64
CXX_DARWIN_AMD64 ?= clang++ -arch x86_64
CC_DARWIN_ARM64 ?= clang -arch arm64
CXX_DARWIN_ARM64 ?= clang++ -arch arm64
else
CC_DARWIN_AMD64 ?= $(ZIG) cc -target x86_64-macos.$(MACOS_MIN_VERSION)
CXX_DARWIN_AMD64 ?= $(ZIG) c++ -target x86_64-macos.$(MACOS_MIN_VERSION)
CC_DARWIN_ARM64 ?= $(ZIG) cc -target aarch64-macos.$(MACOS_MIN_VERSION)
CXX_DARWIN_ARM64 ?= $(ZIG) c++ -target aarch64-macos.$(MACOS_MIN_VERSION)
endif
MACOS_SYSROOT_FLAGS :=
# Developer ID Application identity used to sign the embedded desktop wrapper
# before it is baked into the CLI binary. Signing (with hardened runtime) is
# required so the wrapper is not killed by macOS when `pando desktop` extracts
# and runs it from a temp dir. It is ALSO notarized here (when NOTARY_PROFILE +
# MACOS_SIGN_KEYCHAIN_PATH are set) so the extracted copy passes Gatekeeper's
# online check; otherwise notarization is skipped (non-fatal) for dev builds.
MACOS_SIGN_IDENTITY ?= 4749EC5719E91D7ADFE5FDB4CB546057A8CFB9AD
MACOS_SIGN_KEYCHAIN_PATH ?=
MACOS_CODESIGN_WRAPPER ?= $(CURDIR)/scripts/codesign-macos
# Hardened-runtime entitlements (JIT / executable memory) needed by the embedded
# wazero WASM runtime; without them macOS SIGKILLs pando when WASM is used.
MACOS_ENTITLEMENTS ?= $(CURDIR)/scripts/pando.entitlements
# notarytool keychain profile for notarizing the embedded desktop wrapper.
# Leave empty to skip wrapper notarization (dev builds).
NOTARY_PROFILE ?=
MACOS_NOTARIZE_WRAPPER ?= $(CURDIR)/scripts/notarize-desktop-wrapper
# ============================================================
# Desktop App (Wails) targets
# ============================================================
WAILS_CMD := $(shell which wails 2>/dev/null || echo "$(GOPATH)/bin/wails")
# webkit2_41 is a Linux-only tag for systems with WebKit2GTK 4.1 instead of 4.0.
# On macOS, WKWebView is used natively — no webkit2gtk tags needed.
ifeq ($(shell uname),Darwin)
WAILS_TAGS :=
else
WAILS_TAGS := $(shell pkg-config --exists webkit2gtk-4.0 2>/dev/null && echo "" || echo "webkit2_41")
endif
# UPX-compressed binaries have an invalid Mach-O header on macOS (Big Sur+): the
# process gets killed on launch and codesign/notarization break. Only pass -upx
# on non-Darwin platforms.
ifeq ($(shell uname),Darwin)
WAILS_UPX_FLAG :=
else
WAILS_UPX_FLAG := -upx
endif
.PHONY: build-enterprise release-enterprise xpando embed-stubs desktop-deps desktop-ui desktop-build desktop-dev desktop-package desktop-embed desktop-clean build build-fast web-ui-embedded dist-clean release release-linux-amd64 release-linux-arm64 release-windows-amd64 release-darwin-amd64 release-darwin-arm64 test-integration help
## Create the generated go:embed placeholders (fresh checkout / CI).
## internal/api/webui/dist and internal/desktop/bin/pando-desktop are build
## artifacts and are gitignored, but their embed patterns must still resolve
## for `go vet`/`go build` to work before the real assets are generated.
## Existing files are never overwritten, so a real build stays untouched.
embed-stubs:
@mkdir -p internal/desktop/bin
@[ -f internal/desktop/bin/pando-desktop ] || : > internal/desktop/bin/pando-desktop
@mkdir -p internal/api/webui/dist
@[ -f internal/api/webui/dist/index.html ] || printf '<!doctype html><title>pando</title>\n' > internal/api/webui/dist/index.html
## Install the Wails CLI (run once)
desktop-deps:
go install github.com/wailsapp/wails/v2/cmd/wails@v2.16.0
## Build only the web-ui frontend in desktop mode (plain HTML shell for the WebView wrapper)
desktop-ui:
@echo "Desktop uses plain HTML shell — no frontend build needed."
## Build embedded web-ui assets used by the API binary
web-ui-embedded:
cd $(WEB_UI_DIR) && $(WEB_UI_INSTALL_CMD) && $(WEB_UI_EMBEDDED_BUILD_CMD)
## Build local CLI binary with embedded web-ui and release version from git tag
build: web-ui-embedded
go build $(GO_TAGS_FLAG) -ldflags '$(LDFLAGS)' -o pando$(DIST_SUFFIX) .
## Build the enterprise-variant CLI binary (tags + version stamp + -enterprise suffix)
build-enterprise: MODULE_TAGS=enterprise
build-enterprise: build
## Build local CLI binary without rebuilding web-ui (fast iteration)
build-fast:
go build $(GO_TAGS_FLAG) $(if $(strip $(VARIANT_LDFLAGS) $(TELEMETRY_LDFLAGS)),-ldflags '$(VARIANT_LDFLAGS) $(TELEMETRY_LDFLAGS)',) -o pando$(DIST_SUFFIX) .
## Build the xpando builder, which composes a binary from core + extension modules
xpando:
go build -ldflags '$(LDFLAGS)' -o xpando ./cmd/xpando
## Run multi-process single-writer integration tests (requires compiled binary)
test-integration: build-fast
PANDO_BINARY=$(CURDIR)/pando$(DIST_SUFFIX) go test -tags=integration ./test/integration/single_writer/... -v -timeout 180s
## Full desktop build: compile pando-desktop Wails binary (requires wails CLI)
desktop-build:
@mkdir -p internal/desktop/bin
@[ -f internal/desktop/bin/pando-desktop ] || echo -n "" > internal/desktop/bin/pando-desktop
cd desktop && $(WAILS_CMD) build $(if $(WAILS_TAGS),-tags $(WAILS_TAGS),) $(WAILS_UPX_FLAG) -o pando-desktop
## Development mode: run Wails dev server with hot-reload
desktop-dev:
cd desktop && $(WAILS_CMD) dev $(if $(WAILS_TAGS),-tags $(WAILS_TAGS),)
## Build the pando-desktop binary and embed it into the main pando binary
## This copies the compiled binary into internal/desktop/bin/ for go:embed
desktop-embed: desktop-build
@mkdir -p internal/desktop/bin
@rm -rf internal/desktop/bin/Pando.app
@if [ "$(shell uname)" = "Darwin" ]; then \
if [ -d desktop/build/bin/Pando.app ]; then \
echo "Signing embedded desktop wrapper (Pando.app) — hardened runtime..."; \
codesign --deep --force -o runtime --entitlements "$(MACOS_ENTITLEMENTS)" --timestamp --sign "$(MACOS_SIGN_IDENTITY)" desktop/build/bin/Pando.app \
|| echo "Warning: codesign of embedded desktop wrapper failed; 'pando desktop' from a standalone binary may be blocked by macOS."; \
NOTARY_PROFILE="$(NOTARY_PROFILE)" MACOS_SIGN_KEYCHAIN_PATH="$(MACOS_SIGN_KEYCHAIN_PATH)" "$(MACOS_NOTARIZE_WRAPPER)" desktop/build/bin/Pando.app \
|| echo "Warning: notarization of embedded desktop wrapper failed; 'pando desktop' from a standalone binary may be killed by Gatekeeper."; \
elif [ -f desktop/build/bin/pando-desktop ]; then \
echo "Signing embedded desktop wrapper (pando-desktop) — hardened runtime..."; \
codesign --force -o runtime --entitlements "$(MACOS_ENTITLEMENTS)" --timestamp --sign "$(MACOS_SIGN_IDENTITY)" desktop/build/bin/pando-desktop \
|| echo "Warning: codesign of embedded desktop wrapper failed."; \
NOTARY_PROFILE="$(NOTARY_PROFILE)" MACOS_SIGN_KEYCHAIN_PATH="$(MACOS_SIGN_KEYCHAIN_PATH)" "$(MACOS_NOTARIZE_WRAPPER)" desktop/build/bin/pando-desktop \
|| echo "Warning: notarization of embedded desktop wrapper failed; 'pando desktop' from a standalone binary may be killed by Gatekeeper."; \
fi; \
fi
@python3 scripts/embed_desktop_artifact.py desktop/build/bin internal/desktop/bin
@echo "Embedded desktop build artifacts into internal/desktop/bin"
## Build production packages for current platform
desktop-package:
cd desktop && $(WAILS_CMD) build $(if $(WAILS_TAGS),-tags $(WAILS_TAGS),) $(WAILS_UPX_FLAG) -clean -o pando-desktop
## Remove desktop build artifacts
desktop-clean:
rm -rf desktop/build/bin
rm -rf internal/desktop/bin/Pando.app
@mkdir -p internal/desktop/bin/Pando.app
@touch internal/desktop/bin/Pando.app/.keep internal/desktop/bin/Pando.app/desktop-placeholder
echo -n "" > internal/desktop/bin/pando-desktop
## Remove distribution artifacts
dist-clean:
rm -rf $(DIST_DIR)
$(DIST_DIR):
mkdir -p $(DIST_DIR)
# $(1) GOOS $(2) GOARCH $(3) artifact platform name $(4) binary extension $(5) extra env
# The artifact is named pando[-variant]-<platform>, so a standard and an
# enterprise release can sit in the same dist/ without overwriting each other.
define build_release
@echo "Building $(1)/$(2)$(if $(VARIANT), [$(VARIANT)],)..."
GOOS=$(1) GOARCH=$(2) CGO_ENABLED=$(CGO_ENABLED) $(5) go build $(GO_TAGS_FLAG) -ldflags '$(LDFLAGS)' -o $(DIST_DIR)/pando$(DIST_SUFFIX)-$(3)$(4) .
if [ "$(1)" != "darwin" ] && command -v $(UPX) >/dev/null 2>&1; then \
$(UPX) --best --lzma $(DIST_DIR)/pando$(DIST_SUFFIX)-$(3)$(4); \
else echo "Skipping UPX for $(3)"; fi
if [ "$(1)" = "darwin" ]; then \
_cs="$(MACOS_CODESIGN_WRAPPER)"; \
if [ -x "$$_cs" ]; then \
echo "Signing $(DIST_DIR)/pando$(DIST_SUFFIX)-$(3)$(4) with $$_cs..."; \
"$$_cs" "$(DIST_DIR)/pando$(DIST_SUFFIX)-$(3)$(4)"; \
fi; \
fi
cd $(DIST_DIR) && zip -qm pando$(DIST_SUFFIX)-$(3).zip pando$(DIST_SUFFIX)-$(3)$(4)
endef
define require_cmd
@sh -c 'command -v "$$1" >/dev/null 2>&1 || { echo "Missing required tool: $$1"; exit 1; }' -- "$(1)"
endef
## Build all release archives in dist/ for Linux, Windows and macOS
release: web-ui-embedded $(DIST_DIR) release-linux-amd64 release-linux-arm64 release-windows-amd64 $(if $(filter Darwin,$(shell uname)),release-darwin-amd64 release-darwin-arm64)
## Build all release archives for the enterprise variant
release-enterprise: MODULE_TAGS=enterprise
release-enterprise: release
## Build Linux x64 release archive in dist/
release-linux-amd64: | $(DIST_DIR)
$(call build_release,linux,amd64,linux-x64,)
## Build Linux arm64 release archive in dist/
release-linux-arm64: | $(DIST_DIR)
$(call require_cmd,$(ZIG))
$(call build_release,linux,arm64,linux-arm64,,CC='$(CC_LINUX_ARM64)' CXX='$(CXX_LINUX_ARM64)')
## Build Windows x64 release archive in dist/
release-windows-amd64: | $(DIST_DIR)
$(call require_cmd,$(ZIG))
$(call build_release,windows,amd64,windows-x64,.exe,CC='$(CC_WINDOWS_AMD64)' CXX='$(CXX_WINDOWS_AMD64)')
ifeq ($(shell uname),Darwin)
NATIVE_ARCH := $(shell uname -m)
## Build macOS x64 release archive in dist/
release-darwin-amd64: | $(DIST_DIR)
ifeq ($(NATIVE_ARCH),x86_64)
$(call build_release,darwin,amd64,darwin-x64,,)
else
$(call require_cmd,$(ZIG))
$(call build_release,darwin,amd64,darwin-x64,,CC='$(CC_DARWIN_AMD64)' CXX='$(CXX_DARWIN_AMD64)' $(MACOS_SYSROOT_FLAGS))
endif
## Build macOS arm64 release archive in dist/
release-darwin-arm64: | $(DIST_DIR)
ifeq ($(NATIVE_ARCH),arm64)
$(call build_release,darwin,arm64,darwin-arm64,,)
else
$(call require_cmd,$(ZIG))
$(call build_release,darwin,arm64,darwin-arm64,,CC='$(CC_DARWIN_ARM64)' CXX='$(CXX_DARWIN_ARM64)' $(MACOS_SYSROOT_FLAGS))
endif
endif
## Show available targets
help:
@grep -E '^## ' Makefile | sed 's/## / /'