283 lines
14 KiB
Makefile
283 lines
14 KiB
Makefile
# Nucleic build channels.
|
|
#
|
|
# Each target sets NUCLEIC_CHANNEL, which Package.swift reads to pick the app
|
|
# executable's product (== process) name and the compile-time channel define that
|
|
# drives BuildChannel / the warning banner:
|
|
#
|
|
# channel process name banner built from how
|
|
# ------- --------------- ---------------------- ----------- ----------------
|
|
# dev nucleic-local red "Local Build" dev make dev / run
|
|
# canary nucleic-canary yellow "Canary" canary make canary
|
|
# beta nucleic-beta blue "Beta" staging make beta
|
|
# rc nucleic-rc gold "Release Candidate" rc make rc
|
|
# stable nucleic none main make stable
|
|
#
|
|
# Build system: the default (SwiftBuild) backend. This repo used to force
|
|
# `--build-system native` to dodge SwiftBuild's in-build codesign, which rejected the
|
|
# `com.apple.provenance` xattrs iCloud stamped on files ("resource fork, Finder
|
|
# information, or similar detritus"). The repo no longer lives in iCloud, so the root
|
|
# cause is gone and `native` — now deprecated in SwiftPM — is no longer needed. Override
|
|
# if ever necessary, e.g. `make dev BUILDSYS='--build-system native'`.
|
|
# dev is a debug build; canary/beta/rc/stable are release-optimized.
|
|
|
|
# The per-session macOS VM mounts this trunk over virtiofs at the SAME absolute /Users/… path
|
|
# as the host, so both environments share one physical .build/. Driving every object file
|
|
# through virtiofs is far slower than the guest's own disk, and SwiftPM's binary-target
|
|
# extraction needs filesystem operations virtiofs does not provide (Sparkle's xcframework
|
|
# fails to unpack there). scripts/lib/build-scratch.sh gives each mount its own scratch tree:
|
|
# nothing extra on the host (default .build/), a `--scratch-path` redirect onto the VM's local
|
|
# disk when building from the share. See BUILD.md "Cross-environment builds". Appended to
|
|
# every swift build/run/test below.
|
|
SCRATCH := $(shell bash ./scripts/lib/build-scratch.sh)
|
|
|
|
BUILDSYS :=
|
|
|
|
# TailscaleKit (the embedded tsnet node behind the Tailnet sync transport) has no SwiftPM
|
|
# distribution — scripts/build-tailscalekit.sh builds it from a pinned libtailscale commit into
|
|
# third_party/TailscaleKit/ (untracked, ~100 MB, needs Go + Xcode). Package.swift declares the
|
|
# binary target only when the xcframework exists; without it the app builds but reports "not
|
|
# built in" from the Settings transport picker. Development builds deliberately keep that fallback:
|
|
# a fresh checkout (including a disposable macOS VM session) must be able to compile the SwiftUI app
|
|
# without first cloning libtailscale, downloading a Go toolchain, and building three Xcode slices.
|
|
# Shipped/package targets still require the framework so release artifacts keep Tailnet support.
|
|
TAILSCALE_XCFRAMEWORK := third_party/TailscaleKit/TailscaleKit.xcframework
|
|
|
|
$(TAILSCALE_XCFRAMEWORK): scripts/build-tailscalekit.sh
|
|
./scripts/build-tailscalekit.sh
|
|
|
|
.PHONY: swift-cache-guard dev run canary beta rc stable test clean tailscalekit app-dev app-canary app-beta app-rc app-stable apps \
|
|
dmg-canary dmg-beta dmg-rc dmg-stable release-canary release-beta release-rc release-stable \
|
|
ios-release ios-release-beta ios-release-canary \
|
|
sync-versions edge-deps edge-build edge-test edge-deploy \
|
|
runner-deps runner-build runner-test runner-deploy
|
|
|
|
# SwiftBuild's explicit-module cache can survive a Swift snapshot/Xcode beta change and retain
|
|
# dependency-scan records for generated C shims that no longer exist. Preserve fetched dependencies
|
|
# but invalidate generated products whenever the active compiler/SDK identity changes.
|
|
swift-cache-guard:
|
|
@bash ./scripts/lib/guard-swift-cache.sh "$(CURDIR)"
|
|
|
|
## tailscalekit: build the vendored TailscaleKit.xcframework (Tailnet sync transport)
|
|
tailscalekit: $(TAILSCALE_XCFRAMEWORK)
|
|
|
|
## dev: build the dev channel (process: nucleic-local; Tailnet is optional — `make tailscalekit` to include it)
|
|
dev: swift-cache-guard
|
|
NUCLEIC_CHANNEL=dev swift build $(SCRATCH) $(BUILDSYS) --product nucleic-local
|
|
|
|
## run: build + launch the dev channel (Tailnet is optional — `make tailscalekit` to include it)
|
|
run: swift-cache-guard
|
|
NUCLEIC_CHANNEL=dev swift run $(SCRATCH) $(BUILDSYS) nucleic-local
|
|
|
|
## canary: build the canary channel, release-optimized (process: nucleic-canary)
|
|
canary: swift-cache-guard $(TAILSCALE_XCFRAMEWORK)
|
|
NUCLEIC_CHANNEL=canary swift build -c release $(SCRATCH) $(BUILDSYS) --product nucleic-canary
|
|
|
|
## beta: build the beta channel, release-optimized (process: nucleic-beta)
|
|
beta: swift-cache-guard $(TAILSCALE_XCFRAMEWORK)
|
|
NUCLEIC_CHANNEL=beta swift build -c release $(SCRATCH) $(BUILDSYS) --product nucleic-beta
|
|
|
|
## rc: build the release-candidate channel, release-optimized (process: nucleic-rc)
|
|
rc: swift-cache-guard $(TAILSCALE_XCFRAMEWORK)
|
|
NUCLEIC_CHANNEL=rc swift build -c release $(SCRATCH) $(BUILDSYS) --product nucleic-rc
|
|
|
|
## stable: build the stable/prod channel, release-optimized (process: nucleic)
|
|
stable: swift-cache-guard $(TAILSCALE_XCFRAMEWORK)
|
|
NUCLEIC_CHANNEL=stable swift build -c release $(SCRATCH) $(BUILDSYS) --product nucleic
|
|
|
|
## app-dev: package the dev channel as dist/Nucleic Dev.app
|
|
app-dev: $(TAILSCALE_XCFRAMEWORK)
|
|
./scripts/package-app.sh dev
|
|
|
|
## app-canary: package the canary channel as dist/Nucleic Canary.app
|
|
app-canary: $(TAILSCALE_XCFRAMEWORK)
|
|
./scripts/package-app.sh canary
|
|
|
|
## app-beta: package the beta channel as dist/Nucleic Beta.app
|
|
app-beta: $(TAILSCALE_XCFRAMEWORK)
|
|
./scripts/package-app.sh beta
|
|
|
|
## app-rc: package the release-candidate channel as dist/Nucleic RC.app
|
|
app-rc: $(TAILSCALE_XCFRAMEWORK)
|
|
./scripts/package-app.sh rc
|
|
|
|
## app-stable: package the stable channel as dist/Nucleic.app
|
|
app-stable: $(TAILSCALE_XCFRAMEWORK)
|
|
./scripts/package-app.sh stable
|
|
|
|
## apps: package all channels
|
|
apps: app-dev app-canary app-beta app-rc app-stable
|
|
|
|
## dmg-canary: build a signed DMG from dist/Nucleic Canary.app (run app-canary first)
|
|
dmg-canary:
|
|
./scripts/make-dmg.sh canary
|
|
|
|
## dmg-beta: build a signed DMG from dist/Nucleic Beta.app (run app-beta first)
|
|
dmg-beta:
|
|
./scripts/make-dmg.sh beta
|
|
|
|
## dmg-rc: build a signed DMG from dist/Nucleic RC.app (run app-rc first)
|
|
dmg-rc:
|
|
./scripts/make-dmg.sh rc
|
|
|
|
## dmg-stable: build a signed DMG from dist/Nucleic.app (run app-stable first)
|
|
dmg-stable:
|
|
./scripts/make-dmg.sh stable
|
|
|
|
# Releases bump ./VERSION: build number always +1, plus a semver bump via BUMP. Default is minor,
|
|
# except the fast-moving canary/dev channels which default to build-only (no marketing-version
|
|
# change). BUMP overrides either.
|
|
# make release-beta # 0.1.0 (827) -> 0.2.0 (828): minor (the default)
|
|
# make release-canary # 0.1.0 (827) -> 0.1.0 (828): build-only (canary's default)
|
|
# make release-beta BUMP=major # -> 1.0.0 (828)
|
|
# make release-beta BUMP=patch # -> 0.1.1 (828)
|
|
# make release-canary BUMP=patch # -> 0.1.1 (828): override canary's build-only default
|
|
# make release-beta BUMP=build # -> 0.1.0 (828): build number only
|
|
|
|
## release-canary: signed + notarized + stapled DMG release (canary channel). BUMP=major|minor|patch|build (default: build)
|
|
release-canary:
|
|
NUCLEIC_BUMP=$(BUMP) ./scripts/release-macos.sh canary
|
|
|
|
## release-beta: signed + notarized + stapled DMG release (beta channel). BUMP=major|minor|patch
|
|
release-beta:
|
|
NUCLEIC_BUMP=$(BUMP) ./scripts/release-macos.sh beta
|
|
|
|
## release-rc: signed + notarized + stapled DMG release (rc channel). BUMP=major|minor|patch
|
|
release-rc:
|
|
NUCLEIC_BUMP=$(BUMP) ./scripts/release-macos.sh rc
|
|
|
|
## release-stable: signed + notarized + stapled DMG release (stable channel). BUMP=major|minor|patch
|
|
release-stable:
|
|
NUCLEIC_BUMP=$(BUMP) ./scripts/release-macos.sh stable
|
|
|
|
## sync-versions: fast-forward each less-stable channel branch's VERSION up to its more-stable upstream (dry-run; APPLY=1 to write). Also runs automatically after a release.
|
|
sync-versions:
|
|
./scripts/sync-version.sh $(if $(APPLY),--apply)
|
|
|
|
## ios-release-beta: archive + upload the public beta iPhone app to TestFlight (bundle ...remote.beta, beta icon — separate from stable). BUMP=major|minor|patch|build (default: minor). Versions ios/VERSION (starts at 0.1.0).
|
|
ios-release-beta:
|
|
NUCLEIC_BUMP=$(BUMP) ./scripts/ios-release.sh beta
|
|
|
|
## ios-release-canary: archive + upload the canary iPhone app to TestFlight (bundle ...remote.canary, canary icon). BUMP=major|minor|patch|build (default: build). Shares ios/VERSION with beta.
|
|
ios-release-canary:
|
|
NUCLEIC_BUMP=$(BUMP) ./scripts/ios-release.sh canary
|
|
|
|
## ios-release: alias for ios-release-beta (the public TestFlight build)
|
|
ios-release: ios-release-beta
|
|
|
|
## test: run the test suite
|
|
test: swift-cache-guard
|
|
swift test $(SCRATCH) $(BUILDSYS)
|
|
|
|
## clean: remove build products
|
|
clean:
|
|
swift package clean $(SCRATCH)
|
|
|
|
# --- nucleic-edge cloud service (Cloudflare Worker; cloud/nucleic-edge) -------
|
|
# Build = typecheck + bundle via wrangler's dry-run (no upload, no auth).
|
|
# Deploy = `wrangler deploy` (needs Cloudflare auth; see cloud/nucleic-edge/README.md).
|
|
# The Worker's npm deps install on demand whenever package*.json changes.
|
|
|
|
EDGE_DIR := cloud/nucleic-edge
|
|
|
|
$(EDGE_DIR)/node_modules: $(EDGE_DIR)/package.json $(EDGE_DIR)/package-lock.json
|
|
cd $(EDGE_DIR) && npm install
|
|
@touch $@
|
|
|
|
## edge-deps: install the nucleic-edge Worker's npm dependencies
|
|
edge-deps: $(EDGE_DIR)/node_modules
|
|
|
|
## edge-build: typecheck + bundle the Worker without uploading (wrangler dry-run)
|
|
edge-build: $(EDGE_DIR)/node_modules
|
|
cd $(EDGE_DIR) && npm run typecheck && npm run check
|
|
|
|
## edge-test: run the nucleic-edge Worker unit tests
|
|
edge-test: $(EDGE_DIR)/node_modules
|
|
cd $(EDGE_DIR) && npm test
|
|
|
|
## edge-deploy: build, then deploy the Worker to Cloudflare (wrangler deploy)
|
|
edge-deploy: edge-build
|
|
cd $(EDGE_DIR) && npm run deploy
|
|
|
|
# --- nucleic-runner cloud service (Cloudflare Worker; cloud/nucleic-runner) ---
|
|
# The Covalence runner control plane (docs/COVALENCE_RUNNER.md §8): pool enrollment,
|
|
# placement/load-balancing, the max-containers cap, container lifecycle.
|
|
|
|
RUNNER_DIR := cloud/nucleic-runner
|
|
|
|
$(RUNNER_DIR)/node_modules: $(RUNNER_DIR)/package.json $(RUNNER_DIR)/package-lock.json
|
|
cd $(RUNNER_DIR) && npm install
|
|
@touch $@
|
|
|
|
## runner-deps: install the nucleic-runner Worker's npm dependencies
|
|
runner-deps: $(RUNNER_DIR)/node_modules
|
|
|
|
## runner-build: typecheck + bundle the Worker without uploading (wrangler dry-run)
|
|
runner-build: $(RUNNER_DIR)/node_modules
|
|
cd $(RUNNER_DIR) && npm run typecheck && npm run check
|
|
|
|
## runner-test: run the nucleic-runner Worker unit tests
|
|
runner-test: $(RUNNER_DIR)/node_modules
|
|
cd $(RUNNER_DIR) && npm test
|
|
|
|
## runner-deploy: build, then deploy the Worker to Cloudflare (wrangler deploy)
|
|
runner-deploy: runner-build
|
|
cd $(RUNNER_DIR) && npm run deploy
|
|
|
|
# --- custom vminitd guest image (third_party/containerization) ---
|
|
# Nucleic boots a CUSTOM vminit initfs (guest PID 1, gRPC over vsock) instead of Apple's stock image,
|
|
# because we carry guest-side patches in third_party/containerization/vminitd (see its PATCHES.md).
|
|
# NUCLEIC_VMINIT_REF is the tag this builds — the NEXT image. ContainerEngine.vminitReference is the
|
|
# currently-deployed/validated tag. On a new guest patch: bump the `-nucleicN` suffix here, `make
|
|
# vminit-image` + `make vminit-image-push`, validate in a real container, THEN set vminitReference to
|
|
# match — so this may be one revision ahead while a build is validated. Built locally rather than in
|
|
# CI: the host framework needs the macOS 26+ Virtualization SDK, which GitHub-hosted runners lack.
|
|
#
|
|
# One-time setup on a fresh machine (installs swiftly + the aarch64 musl static SDK the guest
|
|
# cross-build needs; ~1 GB of downloads): make vminit-image-prep
|
|
#
|
|
# WARNINGS_AS_ERRORS=false is forced because Xcode's Swift 6.4 rejects upstream's `-warnings-as-errors`
|
|
# once SwiftPM also passes `-suppress-warnings` to dependencies.
|
|
|
|
CTZN_DIR := third_party/containerization
|
|
NUCLEIC_VMINIT_REF ?= ghcr.io/abkslm/vminit:0.34.0-nucleic5
|
|
|
|
.PHONY: vminit-image-prep vminit-image vminit-image-login vminit-image-push
|
|
|
|
## vminit-image-prep: one-time — install swiftly + the musl static SDK for the guest cross-build
|
|
vminit-image-prep:
|
|
$(MAKE) -C $(CTZN_DIR)/vminitd cross-prep
|
|
|
|
## vminit-image: build the custom vminit guest image locally into the cctl content store
|
|
vminit-image:
|
|
$(MAKE) -C $(CTZN_DIR) containerization WARNINGS_AS_ERRORS=false
|
|
$(MAKE) -C $(CTZN_DIR) vminitd WARNINGS_AS_ERRORS=false
|
|
rm -f $(CTZN_DIR)/bin/init.rootfs.tar.gz $(CTZN_DIR)/bin/init.block $(CTZN_DIR)/bin/initfs.ext4
|
|
cd $(CTZN_DIR) && ./bin/cctl rootfs create \
|
|
--vminitd vminitd/bin/vminitd \
|
|
--vmexec vminitd/bin/vmexec \
|
|
--ext4 ./bin/initfs.ext4 \
|
|
--label org.opencontainers.image.source=https://github.com/apple/containerization \
|
|
--image $(NUCLEIC_VMINIT_REF) \
|
|
bin/init.rootfs.tar.gz
|
|
@echo ""
|
|
@echo "Built $(NUCLEIC_VMINIT_REF) into the local cctl content store."
|
|
@echo "Auth once with 'make vminit-image-login' (stores a GHCR token in your Keychain), then"
|
|
@echo "'make vminit-image-push'. Finally set the vminit GHCR package Public."
|
|
|
|
# cctl is a build artifact (not committed) and the image lives in a user-global content store, so the
|
|
# login/push targets only need the tool. Build it on first use so they work from a fresh checkout
|
|
# (e.g. after the session worktree that ran `make vminit-image` is gone); real target → built once,
|
|
# skipped thereafter. `make vminit-image` rebuilds it explicitly.
|
|
$(CTZN_DIR)/bin/cctl:
|
|
$(MAKE) -C $(CTZN_DIR) containerization WARNINGS_AS_ERRORS=false
|
|
|
|
## vminit-image-login: one-time — store a GHCR credential in the macOS Keychain (prompts for a
|
|
## username + a write:packages PAT; cctl push then authenticates from the Keychain, no env vars)
|
|
vminit-image-login: $(CTZN_DIR)/bin/cctl
|
|
cd $(CTZN_DIR) && ./bin/cctl login ghcr.io
|
|
|
|
## vminit-image-push: push the built image to GHCR (auth from the Keychain via vminit-image-login,
|
|
## or REGISTRY_HOST/USERNAME/TOKEN env as a fallback)
|
|
vminit-image-push: $(CTZN_DIR)/bin/cctl
|
|
cd $(CTZN_DIR) && ./bin/cctl images push $(NUCLEIC_VMINIT_REF)
|