EXEC := EdisonVoice CONFIG := debug ## Build products live OUTSIDE the project directory, so an iCloud/file-provider synced ## location can't touch files mid-compile ("input file was modified during the build"). SCRATCH := $(HOME)/Library/Caches/EdisonVoiceBuild/scratch BUILD := $(SCRATCH)/$(CONFIG)/$(EXEC) ## The bundle is assembled and signed OUTSIDE this directory for the same reason: the sync ## provider stamps FinderInfo onto files inside an .app and codesign hard-refuses them. STAGE := $(HOME)/Library/Caches/EdisonVoiceBuild APPNAME := Edison Voice.app BUNDLE := $(STAGE)/$(APPNAME) CONTENTS := $(BUNDLE)/Contents ## TCC keys the Accessibility grant to the code signature. An ad-hoc signature changes every ## build, so the rebuilt binary stops satisfying the stored requirement. Sign with a stable ## Developer ID when available; fall back to ad-hoc ("-") otherwise. SIGN_ID := $(shell security find-identity -v -p codesigning 2>/dev/null \ | grep "Developer ID Application" | head -1 | sed -E 's/.*"(.*)".*/\1/') ifeq ($(strip $(SIGN_ID)),) SIGN_ID := - endif .PHONY: all build test app run install icon clean all: app build: swift build -c $(CONFIG) --scratch-path "$(SCRATCH)" test: swift test --scratch-path "$(SCRATCH)" ## Regenerates AppIcon.icns from Tools/makeicon.swift. Not a dependency of `app` — the ## icon rarely changes and rendering 10 PNGs on every build is wasted time. icon: @swift Tools/makeicon.swift @iconutil -c icns Resources/AppIcon.iconset -o Resources/AppIcon.icns @echo "wrote Resources/AppIcon.icns" ## Assemble a real .app bundle. TCC (microphone + Accessibility) keys on bundle identity ## and code signature, so the raw SwiftPM binary can't be used directly. app: build @rm -rf "$(BUNDLE)" @mkdir -p "$(CONTENTS)/MacOS" "$(CONTENTS)/Resources" @cp $(BUILD) "$(CONTENTS)/MacOS/$(EXEC)" @cp Resources/Info.plist "$(CONTENTS)/Info.plist" @if [ -f Resources/AppIcon.icns ]; then cp Resources/AppIcon.icns "$(CONTENTS)/Resources/"; fi @printf 'APPL????' > "$(CONTENTS)/PkgInfo" @xattr -cr "$(BUNDLE)" @codesign --force --sign "$(SIGN_ID)" \ --entitlements Resources/$(EXEC).entitlements \ --options runtime \ --timestamp=none \ "$(BUNDLE)" @echo "built $(BUNDLE) [signed: $(SIGN_ID)]" run: app @pkill -x $(EXEC) 2>/dev/null || true @open "$(BUNDLE)" ## Ad-hoc signatures change on every rebuild, which resets the Accessibility grant. ## Installing to /Applications keeps the path stable and makes re-granting a one-click fix. install: app @pkill -x $(EXEC) 2>/dev/null || true @rm -rf "/Applications/$(APPNAME)" @cp -R "$(BUNDLE)" "/Applications/$(APPNAME)" @open "/Applications/$(APPNAME)" @echo "installed to /Applications/$(APPNAME)" clean: @rm -rf .build "$(STAGE)" "$(SCRATCH)"