Makefile: - vendor-wheels-windows 自動偵測 pip3/pip/python -m pip,MSYS2 bash 裡沒 pip3 也能跑 - vendor-ffmpeg-windows 改用 python zipfile 解壓,移除 unzip 依賴 - 新增 build-server-windows / build-server-linux 兩個 cross-build target - payload-windows / payload-linux 改依賴對應的 build-server-*,不再只印警告 bootstrap-windows.ps1: - 設定 MSYS2_PATH_TYPE=inherit,讓 MSYS2 bash 繼承 Windows PATH 找到 go/pnpm/python/wails Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
502 lines
25 KiB
Makefile
502 lines
25 KiB
Makefile
# visionA-local — Makefile(骨架,M1-1)
|
||
#
|
||
# 這份 Makefile 目前所有 targets 都只是 placeholder,實際內容會在後續任務逐步填入:
|
||
# - M1-2 複製 server core
|
||
# - M1-4 複製 frontend
|
||
# - M1-8 build-server / build-frontend 實作
|
||
# - M1-9 visiona-local (Wails) shell
|
||
# - M1-11 payload-macos
|
||
# - M1-12 installer-macos (dmg)
|
||
# - M2+ Windows / Linux / CI
|
||
#
|
||
# 詳見 .autoflow/04-architecture/build-pipeline.md
|
||
|
||
SHELL := /bin/bash
|
||
VERSION ?= v0.1.0-dev
|
||
BUILD_TIME := $(shell date -u +%Y-%m-%dT%H:%M:%SZ)
|
||
OS := $(shell uname -s | tr A-Z a-z)
|
||
DIST := dist
|
||
PAYLOAD := visiona-local/payload
|
||
|
||
.PHONY: help \
|
||
vendor-sync vendor-python vendor-wheels vendor-ffmpeg vendor-ytdlp \
|
||
vendor-python-windows vendor-wheels-windows vendor-ffmpeg-windows vendor-ytdlp-windows \
|
||
vendor-python-linux vendor-wheels-linux vendor-ffmpeg-linux vendor-ytdlp-linux \
|
||
server build-server \
|
||
frontend build-frontend build-embed \
|
||
payload payload-macos payload-windows payload-linux \
|
||
stage-macos stage-windows \
|
||
wails-macos wails-windows wails-linux \
|
||
dmg exe appimage \
|
||
dev dev-mock test lint fmt clean
|
||
|
||
# ── 幫助 ───────────────────────────────────────────────────────────
|
||
help: ## 列出所有 make targets
|
||
@echo "visionA-local — available targets (M1-1 skeleton)"
|
||
@echo ""
|
||
@echo " 依賴同步:"
|
||
@echo " vendor-sync 下載 python-build-standalone / wheels / ffmpeg / yt-dlp → vendor/"
|
||
@echo ""
|
||
@echo " Build(單元):"
|
||
@echo " server build Go server binary (→ dist/visiona-local-server)"
|
||
@echo " frontend pnpm build Next.js 靜態產物 (→ frontend/out)"
|
||
@echo ""
|
||
@echo " Payload 準備:"
|
||
@echo " payload-macos stage macOS payload → visiona-local/payload/"
|
||
@echo " payload-windows stage Windows payload"
|
||
@echo " payload-linux stage Linux payload"
|
||
@echo ""
|
||
@echo " Wails 應用 build:"
|
||
@echo " wails-macos wails build darwin/amd64"
|
||
@echo " wails-windows wails build windows/amd64"
|
||
@echo " wails-linux wails build linux/amd64"
|
||
@echo ""
|
||
@echo " 安裝檔打包:"
|
||
@echo " dmg macOS .dmg(dmgbuild)"
|
||
@echo " exe Windows .exe(Inno Setup)"
|
||
@echo " appimage Linux .AppImage"
|
||
@echo ""
|
||
@echo " 工具:"
|
||
@echo " clean 清除 dist/ payload/"
|
||
@echo ""
|
||
@echo "Note: 目前所有 target 都是 placeholder(只印 TODO),尚未實作。"
|
||
|
||
# ── 依賴同步 ───────────────────────────────────────────────────────
|
||
PYTHON_VERSION := 3.12.9
|
||
PBS_RELEASE := 20250317
|
||
PBS_URL_DARWIN := https://github.com/astral-sh/python-build-standalone/releases/download/$(PBS_RELEASE)/cpython-$(PYTHON_VERSION)+$(PBS_RELEASE)-x86_64-apple-darwin-install_only.tar.gz
|
||
|
||
FFMPEG_URL_DARWIN := https://evermeet.cx/ffmpeg/getrelease/ffmpeg/zip
|
||
YTDLP_URL_DARWIN := https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_macos
|
||
|
||
vendor-sync: vendor-python vendor-wheels vendor-ffmpeg vendor-ytdlp ## 下載所有第三方依賴到 vendor/(不進 git,第三輪決策 Q-D=D2)
|
||
@echo "==> vendor-sync 完成"
|
||
|
||
vendor-python: ## 下載 python-build-standalone tarball → vendor/python/darwin/
|
||
@mkdir -p vendor/python/darwin
|
||
@if [ ! -f vendor/python/darwin/python.tar.gz ]; then \
|
||
echo "==> 下載 python-build-standalone $(PYTHON_VERSION)+$(PBS_RELEASE) (macOS x86_64 install_only)..."; \
|
||
curl -fL -o vendor/python/darwin/python.tar.gz "$(PBS_URL_DARWIN)"; \
|
||
echo "==> tarball 大小:$$(du -sh vendor/python/darwin/python.tar.gz | cut -f1)"; \
|
||
else \
|
||
echo "==> python tarball 已存在,跳過下載 ($$(du -sh vendor/python/darwin/python.tar.gz | cut -f1))"; \
|
||
fi
|
||
|
||
vendor-wheels: ## 同步 wheels → vendor/wheels/darwin/(內部 wheel 從 visiona-local/wheels 複製,公開相依用 pip download)
|
||
@mkdir -p vendor/wheels/darwin
|
||
@echo "==> 同步內部 wheels(KneronPLUS 等)..."
|
||
@if [ -d visiona-local/wheels/macos ]; then \
|
||
cp visiona-local/wheels/macos/*.whl vendor/wheels/darwin/ 2>/dev/null || true; \
|
||
fi
|
||
@echo "==> 從 PyPI 下載公開相依 wheels (cp312, macosx_x86_64)..."
|
||
@pip3 download \
|
||
--only-binary=:all: \
|
||
--platform macosx_10_9_x86_64 \
|
||
--platform macosx_11_0_x86_64 \
|
||
--platform macosx_12_0_x86_64 \
|
||
--python-version 3.12 \
|
||
--implementation cp \
|
||
--dest vendor/wheels/darwin \
|
||
numpy opencv-python-headless pyusb requests || echo "WARN: pip download 部分失敗(詳見上方訊息)"
|
||
@echo "==> wheels 總覽:"
|
||
@ls -1 vendor/wheels/darwin/*.whl 2>/dev/null | wc -l | xargs -I{} echo " 共 {} 個 wheel"
|
||
@du -sh vendor/wheels/darwin
|
||
|
||
vendor-ffmpeg: ## 下載 ffmpeg static build (macOS x86_64) → vendor/ffmpeg/darwin/(預設要求 LGPL,必要時可用 VISIONA_ALLOW_GPL_FFMPEG=1 暫時放行 GPL)
|
||
@mkdir -p vendor/ffmpeg/darwin
|
||
@if [ -f vendor/ffmpeg/darwin/ffmpeg ]; then \
|
||
echo "==> ffmpeg 已存在,跳過 ($$(du -sh vendor/ffmpeg/darwin/ffmpeg | cut -f1))"; \
|
||
else \
|
||
echo "==> 下載 ffmpeg static build (macOS) from evermeet.cx..."; \
|
||
curl -fL -o /tmp/ffmpeg-latest.zip "$(FFMPEG_URL_DARWIN)"; \
|
||
unzip -o /tmp/ffmpeg-latest.zip -d vendor/ffmpeg/darwin/; \
|
||
rm -f /tmp/ffmpeg-latest.zip; \
|
||
chmod +x vendor/ffmpeg/darwin/ffmpeg; \
|
||
echo "==> ffmpeg 大小:$$(du -sh vendor/ffmpeg/darwin/ffmpeg | cut -f1)"; \
|
||
vendor/ffmpeg/darwin/ffmpeg -version 2>&1 | head -3; \
|
||
echo "==> 授權檢查:"; \
|
||
if vendor/ffmpeg/darwin/ffmpeg -version 2>&1 | grep -q -- '--enable-gpl'; then \
|
||
if [ "$${VISIONA_ALLOW_GPL_FFMPEG:-0}" = "1" ]; then \
|
||
echo " !! WARNING: 此 build 含 --enable-gpl(GPL build) !!"; \
|
||
echo " !! VISIONA_ALLOW_GPL_FFMPEG=1 已啟用,暫時允許(僅限本地驗收,不可發佈) !!"; \
|
||
else \
|
||
echo "!! 錯誤:此 build 含 --enable-gpl,違反 LGPL 策略 !!"; \
|
||
echo "!! macOS 暫無現成 LGPL binary 來源,需自行 build 或用 VISIONA_ALLOW_GPL_FFMPEG=1 暫時放行 !!"; \
|
||
rm -f vendor/ffmpeg/darwin/ffmpeg; \
|
||
exit 1; \
|
||
fi; \
|
||
else \
|
||
echo " OK: 未偵測到 --enable-gpl"; \
|
||
fi; \
|
||
fi
|
||
|
||
vendor-ytdlp: ## 下載 yt-dlp standalone (macOS) → vendor/yt-dlp/darwin/
|
||
@mkdir -p vendor/yt-dlp/darwin
|
||
@if [ ! -f vendor/yt-dlp/darwin/yt-dlp ]; then \
|
||
echo "==> 下載 yt-dlp (macOS)..."; \
|
||
curl -fL -o vendor/yt-dlp/darwin/yt-dlp "$(YTDLP_URL_DARWIN)"; \
|
||
chmod +x vendor/yt-dlp/darwin/yt-dlp; \
|
||
echo "==> yt-dlp 大小:$$(du -sh vendor/yt-dlp/darwin/yt-dlp | cut -f1)"; \
|
||
vendor/yt-dlp/darwin/yt-dlp --version 2>&1 | head -1; \
|
||
else \
|
||
echo "==> yt-dlp 已存在,跳過 ($$(du -sh vendor/yt-dlp/darwin/yt-dlp | cut -f1))"; \
|
||
fi
|
||
|
||
# ── Build(單元) ──────────────────────────────────────────────────
|
||
server: build-server ## alias for build-server
|
||
|
||
build-server: build-embed ## build Go server binary → dist/visiona-local-server(會先 build frontend + embed)
|
||
@mkdir -p $(DIST)
|
||
cd server && go build -o ../$(DIST)/visiona-local-server .
|
||
@echo "built: $(DIST)/visiona-local-server"
|
||
|
||
build-server-windows: build-embed ## 交叉/原生 build Windows server → payload/windows/bin/visiona-local-server.exe
|
||
@mkdir -p payload/windows/bin
|
||
cd server && GOOS=windows GOARCH=amd64 go build -o ../payload/windows/bin/visiona-local-server.exe .
|
||
@echo "built: payload/windows/bin/visiona-local-server.exe"
|
||
|
||
build-server-linux: build-embed ## 交叉/原生 build Linux server → payload/linux/bin/visiona-local-server
|
||
@mkdir -p payload/linux/bin
|
||
cd server && GOOS=linux GOARCH=amd64 go build -o ../payload/linux/bin/visiona-local-server .
|
||
@echo "built: payload/linux/bin/visiona-local-server"
|
||
|
||
frontend: build-frontend ## alias for build-frontend
|
||
|
||
build-frontend: ## pnpm build → frontend/out/
|
||
@echo "==> pnpm build frontend..."
|
||
cd frontend && pnpm install --frozen-lockfile && pnpm build
|
||
@echo "==> frontend/out 完成:"
|
||
@du -sh frontend/out
|
||
|
||
build-embed: build-frontend ## 同步 frontend/out → server/web/out 供 go:embed
|
||
@echo "==> 同步 frontend/out → server/web/out..."
|
||
rm -rf server/web/out
|
||
mkdir -p server/web/out
|
||
cp -R frontend/out/. server/web/out/
|
||
@du -sh server/web/out
|
||
|
||
# ── Payload 準備 ───────────────────────────────────────────────────
|
||
payload: payload-$(OS) ## 依當前 OS 準備 payload
|
||
|
||
payload-macos: build-server vendor-python vendor-wheels vendor-ffmpeg vendor-ytdlp ## 準備 macOS payload → payload/darwin/(含 python runtime + wheels + ffmpeg + yt-dlp)
|
||
@echo "==> 建立 macOS payload (binary + models + scripts + python + wheels + ffmpeg + yt-dlp)..."
|
||
rm -rf payload/darwin
|
||
mkdir -p payload/darwin/bin payload/darwin/data payload/darwin/scripts payload/darwin/python payload/darwin/wheels
|
||
cp dist/visiona-local-server payload/darwin/bin/
|
||
cp vendor/ffmpeg/darwin/ffmpeg payload/darwin/bin/
|
||
cp vendor/yt-dlp/darwin/yt-dlp payload/darwin/bin/
|
||
chmod +x payload/darwin/bin/ffmpeg payload/darwin/bin/yt-dlp
|
||
cp -R server/data/* payload/darwin/data/
|
||
cp -R server/scripts/* payload/darwin/scripts/
|
||
cp vendor/python/darwin/python.tar.gz payload/darwin/python/
|
||
@cp vendor/wheels/darwin/*.whl payload/darwin/wheels/ 2>/dev/null || true
|
||
@echo "==> macOS payload 完成:"
|
||
@du -sh payload/darwin
|
||
@echo ""
|
||
@echo "payload/darwin 結構:"
|
||
@find payload/darwin -maxdepth 2 -type d | sed 's|^| |'
|
||
@echo ""
|
||
@echo "payload/darwin/python:"
|
||
@ls -lh payload/darwin/python
|
||
@echo "payload/darwin/wheels:"
|
||
@ls -1 payload/darwin/wheels | head -20
|
||
|
||
stage-macos: payload-macos ## 將 payload/darwin/ 放到 Wails build/darwin/Resources/
|
||
@echo "==> 放置 payload 到 Wails build/darwin/Resources..."
|
||
rm -rf visiona-local/build/darwin/Resources
|
||
mkdir -p visiona-local/build/darwin/Resources
|
||
cp -R payload/darwin/. visiona-local/build/darwin/Resources/
|
||
@echo "==> stage 完成:"
|
||
@du -sh visiona-local/build/darwin/Resources
|
||
|
||
# ── M4:Windows vendor + payload + wails + exe ─────────────────────
|
||
# 注意:wails-windows 與 exe 必須在 Windows runner 上跑;在 macOS 上會明確 fail。
|
||
# payload-windows / vendor-*-windows 是 curl 下載,跨平台可跑(server.exe 步驟除外)。
|
||
|
||
PBS_URL_WINDOWS := https://github.com/astral-sh/python-build-standalone/releases/download/$(PBS_RELEASE)/cpython-$(PYTHON_VERSION)+$(PBS_RELEASE)-x86_64-pc-windows-msvc-install_only.tar.gz
|
||
FFMPEG_URL_WINDOWS := https://github.com/BtbN/FFmpeg-Builds/releases/latest/download/ffmpeg-master-latest-win64-gpl.zip
|
||
YTDLP_URL_WINDOWS := https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp.exe
|
||
|
||
vendor-python-windows: ## 下載 python-build-standalone Windows x86_64 → vendor/python/windows/
|
||
@mkdir -p vendor/python/windows
|
||
@if [ ! -f vendor/python/windows/python.tar.gz ]; then \
|
||
echo "==> 下載 python-build-standalone $(PYTHON_VERSION)+$(PBS_RELEASE) (Windows x86_64 install_only)..."; \
|
||
curl -fL -o vendor/python/windows/python.tar.gz "$(PBS_URL_WINDOWS)"; \
|
||
echo "==> tarball 大小:$$(du -sh vendor/python/windows/python.tar.gz | cut -f1)"; \
|
||
else \
|
||
echo "==> python (Windows) tarball 已存在,跳過 ($$(du -sh vendor/python/windows/python.tar.gz | cut -f1))"; \
|
||
fi
|
||
|
||
vendor-wheels-windows: ## 同步 Windows wheels → vendor/wheels/windows/
|
||
@mkdir -p vendor/wheels/windows
|
||
@echo "==> 同步內部 wheels (Windows, KneronPLUS 等)..."
|
||
@if [ -d visiona-local/wheels/windows ]; then \
|
||
cp visiona-local/wheels/windows/*.whl vendor/wheels/windows/ 2>/dev/null || true; \
|
||
fi
|
||
@echo "==> 從 PyPI 下載公開相依 wheels (cp312, win_amd64)..."
|
||
@PIP_CMD=$$(command -v pip3 || command -v pip); \
|
||
if [ -z "$$PIP_CMD" ]; then \
|
||
PY=$$(command -v python3 || command -v python || command -v py); \
|
||
if [ -n "$$PY" ]; then PIP_CMD="$$PY -m pip"; fi; \
|
||
fi; \
|
||
if [ -z "$$PIP_CMD" ]; then \
|
||
echo "WARN: 找不到 pip / python,跳過 PyPI 下載(僅使用內部 wheels)"; \
|
||
else \
|
||
echo "==> 使用 $$PIP_CMD"; \
|
||
$$PIP_CMD download \
|
||
--only-binary=:all: \
|
||
--platform win_amd64 \
|
||
--python-version 3.12 \
|
||
--implementation cp \
|
||
--dest vendor/wheels/windows \
|
||
numpy opencv-python-headless pyusb requests || echo "WARN: pip download 部分失敗(詳見上方訊息)"; \
|
||
fi
|
||
@echo "==> Windows wheels 總覽:"
|
||
@ls -1 vendor/wheels/windows/*.whl 2>/dev/null | wc -l | xargs -I{} echo " 共 {} 個 wheel"
|
||
@du -sh vendor/wheels/windows 2>/dev/null || true
|
||
|
||
vendor-ffmpeg-windows: ## 下載 ffmpeg Windows static build → vendor/ffmpeg/windows/
|
||
@mkdir -p vendor/ffmpeg/windows
|
||
@if [ -f vendor/ffmpeg/windows/ffmpeg.exe ]; then \
|
||
echo "==> ffmpeg.exe 已存在,跳過"; \
|
||
else \
|
||
echo "==> 下載 ffmpeg Windows build from BtbN..."; \
|
||
echo "!! WARNING: BtbN 為 GPL build;license 由 PM 最終確認 !!"; \
|
||
curl -fL -o /tmp/ffmpeg-win.zip "$(FFMPEG_URL_WINDOWS)"; \
|
||
PY=$$(command -v python3 || command -v python || command -v py); \
|
||
if [ -z "$$PY" ]; then echo "ERROR: 需要 python 來解壓 zip"; exit 1; fi; \
|
||
$$PY -c "import zipfile, os, shutil; z=zipfile.ZipFile('/tmp/ffmpeg-win.zip'); \
|
||
members=[n for n in z.namelist() if n.endswith('/bin/ffmpeg.exe')]; \
|
||
assert members, 'ffmpeg.exe not found in zip'; \
|
||
src=z.open(members[0]); dst=open('vendor/ffmpeg/windows/ffmpeg.exe','wb'); \
|
||
shutil.copyfileobj(src, dst); src.close(); dst.close(); z.close()"; \
|
||
rm -f /tmp/ffmpeg-win.zip; \
|
||
echo "==> ffmpeg.exe 大小:$$(du -sh vendor/ffmpeg/windows/ffmpeg.exe | cut -f1)"; \
|
||
fi
|
||
|
||
vendor-ytdlp-windows: ## 下載 yt-dlp.exe → vendor/yt-dlp/windows/
|
||
@mkdir -p vendor/yt-dlp/windows
|
||
@if [ ! -f vendor/yt-dlp/windows/yt-dlp.exe ]; then \
|
||
echo "==> 下載 yt-dlp.exe..."; \
|
||
curl -fL -o vendor/yt-dlp/windows/yt-dlp.exe "$(YTDLP_URL_WINDOWS)"; \
|
||
echo "==> yt-dlp.exe 大小:$$(du -sh vendor/yt-dlp/windows/yt-dlp.exe | cut -f1)"; \
|
||
else \
|
||
echo "==> yt-dlp.exe 已存在,跳過"; \
|
||
fi
|
||
|
||
payload-windows: build-server-windows vendor-python-windows vendor-wheels-windows vendor-ffmpeg-windows vendor-ytdlp-windows ## 準備 Windows payload → payload/windows/
|
||
@echo "==> 建立 Windows payload (binary + models + scripts + python + wheels + ffmpeg + yt-dlp)..."
|
||
@# 注意:不 rm -rf payload/windows,因為 build-server-windows 已先把 .exe 放進去
|
||
mkdir -p payload/windows/bin payload/windows/data payload/windows/scripts payload/windows/python payload/windows/wheels
|
||
@if [ ! -f payload/windows/bin/visiona-local-server.exe ]; then \
|
||
echo "!! ERROR: payload/windows/bin/visiona-local-server.exe 不存在,build-server-windows 可能失敗 !!"; \
|
||
exit 1; \
|
||
fi
|
||
cp vendor/ffmpeg/windows/ffmpeg.exe payload/windows/bin/
|
||
cp vendor/yt-dlp/windows/yt-dlp.exe payload/windows/bin/
|
||
cp -R server/data/. payload/windows/data/
|
||
cp -R server/scripts/. payload/windows/scripts/
|
||
cp vendor/python/windows/python.tar.gz payload/windows/python/
|
||
@cp vendor/wheels/windows/*.whl payload/windows/wheels/ 2>/dev/null || true
|
||
@echo "==> Windows payload 完成:"
|
||
@du -sh payload/windows
|
||
@echo ""
|
||
@echo "payload/windows 結構:"
|
||
@find payload/windows -maxdepth 2 -type d | sed 's|^| |'
|
||
|
||
stage-windows: payload-windows ## 將 payload/windows/ 放到 Wails build/windows/Resources/
|
||
@echo "==> 放置 payload 到 Wails build/windows/Resources..."
|
||
rm -rf visiona-local/build/windows/Resources
|
||
mkdir -p visiona-local/build/windows/Resources
|
||
cp -R payload/windows/. visiona-local/build/windows/Resources/
|
||
@echo "==> stage 完成:"
|
||
@du -sh visiona-local/build/windows/Resources
|
||
|
||
# ── M5:Linux vendor + payload + wails + AppImage ──────────────────
|
||
# 注意:wails-linux 與 appimage 必須在 Linux runner 上跑;在 macOS 上會明確 fail。
|
||
# payload-linux / vendor-*-linux 是 curl 下載,跨平台可跑(server 步驟除外)。
|
||
|
||
PBS_URL_LINUX := https://github.com/astral-sh/python-build-standalone/releases/download/$(PBS_RELEASE)/cpython-$(PYTHON_VERSION)+$(PBS_RELEASE)-x86_64-unknown-linux-gnu-install_only.tar.gz
|
||
FFMPEG_URL_LINUX := https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz
|
||
YTDLP_URL_LINUX := https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_linux
|
||
|
||
vendor-python-linux: ## 下載 python-build-standalone Linux x86_64 → vendor/python/linux/
|
||
@mkdir -p vendor/python/linux
|
||
@if [ ! -f vendor/python/linux/python.tar.gz ]; then \
|
||
echo "==> 下載 python-build-standalone $(PYTHON_VERSION)+$(PBS_RELEASE) (Linux x86_64 install_only)..."; \
|
||
curl -fL -o vendor/python/linux/python.tar.gz "$(PBS_URL_LINUX)"; \
|
||
echo "==> tarball 大小:$$(du -sh vendor/python/linux/python.tar.gz | cut -f1)"; \
|
||
else \
|
||
echo "==> python (Linux) tarball 已存在,跳過 ($$(du -sh vendor/python/linux/python.tar.gz | cut -f1))"; \
|
||
fi
|
||
|
||
vendor-wheels-linux: ## 同步 Linux wheels → vendor/wheels/linux/
|
||
@mkdir -p vendor/wheels/linux
|
||
@echo "==> 同步內部 wheels (Linux, KneronPLUS 等)..."
|
||
@if [ -d visiona-local/wheels/linux ]; then \
|
||
cp visiona-local/wheels/linux/*.whl vendor/wheels/linux/ 2>/dev/null || true; \
|
||
fi
|
||
@echo "==> 從 PyPI 下載公開相依 wheels (cp312, manylinux2014_x86_64)..."
|
||
@pip3 download \
|
||
--only-binary=:all: \
|
||
--platform manylinux2014_x86_64 \
|
||
--python-version 3.12 \
|
||
--implementation cp \
|
||
--dest vendor/wheels/linux \
|
||
numpy opencv-python-headless pyusb requests || echo "WARN: pip download 部分失敗(詳見上方訊息)"
|
||
@echo "==> Linux wheels 總覽:"
|
||
@ls -1 vendor/wheels/linux/*.whl 2>/dev/null | wc -l | xargs -I{} echo " 共 {} 個 wheel"
|
||
@du -sh vendor/wheels/linux 2>/dev/null || true
|
||
|
||
vendor-ffmpeg-linux: ## 下載 ffmpeg Linux static build → vendor/ffmpeg/linux/
|
||
@mkdir -p vendor/ffmpeg/linux
|
||
@if [ -f vendor/ffmpeg/linux/ffmpeg ]; then \
|
||
echo "==> ffmpeg (Linux) 已存在,跳過 ($$(du -sh vendor/ffmpeg/linux/ffmpeg | cut -f1))"; \
|
||
else \
|
||
echo "==> 下載 ffmpeg static build (Linux x86_64) from johnvansickle..."; \
|
||
echo "!! WARNING: johnvansickle build 為 GPL build;正式發佈前需改用 LGPL 來源 !!"; \
|
||
curl -fL -o /tmp/ffmpeg-linux.tar.xz "$(FFMPEG_URL_LINUX)"; \
|
||
mkdir -p /tmp/ffmpeg-linux-extract; \
|
||
tar xf /tmp/ffmpeg-linux.tar.xz -C /tmp/ffmpeg-linux-extract --strip-components=1; \
|
||
cp /tmp/ffmpeg-linux-extract/ffmpeg vendor/ffmpeg/linux/; \
|
||
chmod +x vendor/ffmpeg/linux/ffmpeg; \
|
||
rm -rf /tmp/ffmpeg-linux* ; \
|
||
echo "==> ffmpeg (Linux) 大小:$$(du -sh vendor/ffmpeg/linux/ffmpeg | cut -f1)"; \
|
||
if [ "$${VISIONA_ALLOW_GPL_FFMPEG:-0}" != "1" ]; then \
|
||
echo " ⚠️ 提醒:此 build 為 GPL,僅限本地驗收,發佈前請改用 LGPL build"; \
|
||
fi; \
|
||
fi
|
||
|
||
vendor-ytdlp-linux: ## 下載 yt-dlp (Linux) → vendor/yt-dlp/linux/
|
||
@mkdir -p vendor/yt-dlp/linux
|
||
@if [ ! -f vendor/yt-dlp/linux/yt-dlp ]; then \
|
||
echo "==> 下載 yt-dlp (Linux)..."; \
|
||
curl -fL -o vendor/yt-dlp/linux/yt-dlp "$(YTDLP_URL_LINUX)"; \
|
||
chmod +x vendor/yt-dlp/linux/yt-dlp; \
|
||
echo "==> yt-dlp (Linux) 大小:$$(du -sh vendor/yt-dlp/linux/yt-dlp | cut -f1)"; \
|
||
else \
|
||
echo "==> yt-dlp (Linux) 已存在,跳過"; \
|
||
fi
|
||
|
||
payload-linux: build-server-linux vendor-python-linux vendor-wheels-linux vendor-ffmpeg-linux vendor-ytdlp-linux ## 準備 Linux payload → payload/linux/
|
||
@echo "==> 建立 Linux payload (binary + models + scripts + python + wheels + ffmpeg + yt-dlp)..."
|
||
mkdir -p payload/linux/bin payload/linux/data payload/linux/scripts payload/linux/python payload/linux/wheels
|
||
@if [ ! -f payload/linux/bin/visiona-local-server ]; then \
|
||
echo "!! ERROR: payload/linux/bin/visiona-local-server 不存在,build-server-linux 可能失敗 !!"; \
|
||
exit 1; \
|
||
fi
|
||
@chmod +x payload/linux/bin/visiona-local-server
|
||
@cp vendor/ffmpeg/linux/ffmpeg payload/linux/bin/ 2>/dev/null && chmod +x payload/linux/bin/ffmpeg || echo "!! WARN: ffmpeg 缺失"
|
||
@cp vendor/yt-dlp/linux/yt-dlp payload/linux/bin/ 2>/dev/null && chmod +x payload/linux/bin/yt-dlp || echo "!! WARN: yt-dlp 缺失"
|
||
@if [ -d server/data ]; then cp -R server/data/. payload/linux/data/; fi
|
||
@if [ -d server/scripts ]; then cp -R server/scripts/. payload/linux/scripts/; fi
|
||
@cp vendor/python/linux/python.tar.gz payload/linux/python/ 2>/dev/null || echo "!! WARN: python tarball 缺失"
|
||
@cp vendor/wheels/linux/*.whl payload/linux/wheels/ 2>/dev/null || true
|
||
@echo "==> Linux payload 完成:"
|
||
@du -sh payload/linux 2>/dev/null || true
|
||
@echo ""
|
||
@echo "payload/linux 結構:"
|
||
@find payload/linux -maxdepth 2 -type d 2>/dev/null | sed 's|^| |'
|
||
|
||
# ── Wails build ────────────────────────────────────────────────────
|
||
wails-macos: stage-macos ## wails build darwin/amd64 → visiona-local/build/bin/visiona-local.app
|
||
cd visiona-local && wails build -platform darwin/amd64 -clean
|
||
cp -R visiona-local/build/darwin/Resources/bin \
|
||
visiona-local/build/darwin/Resources/data \
|
||
visiona-local/build/darwin/Resources/scripts \
|
||
visiona-local/build/darwin/Resources/python \
|
||
visiona-local/build/darwin/Resources/wheels \
|
||
visiona-local/build/bin/visiona-local.app/Contents/Resources/
|
||
codesign --force --deep --sign - visiona-local/build/bin/visiona-local.app
|
||
codesign --verify --verbose visiona-local/build/bin/visiona-local.app
|
||
@du -sh visiona-local/build/bin/visiona-local.app
|
||
|
||
wails-windows: stage-windows ## ⚠️ 必須在 Windows runner 上執行:wails build -platform windows/amd64
|
||
@case "$$(uname -s 2>/dev/null)" in \
|
||
MINGW*|CYGWIN*|MSYS*) : ;; \
|
||
*) \
|
||
echo ""; \
|
||
echo "❌ wails-windows 只能在 Windows runner 上 build(偵測到 $$(uname -s))"; \
|
||
echo " 請在 Windows 機器上執行此 target,或用 CI 的 Windows runner"; \
|
||
echo " 若只是要檢查前置步驟,可單獨跑 make stage-windows"; \
|
||
echo ""; \
|
||
exit 1 ;; \
|
||
esac
|
||
cd visiona-local && wails build -platform windows/amd64 -clean
|
||
@du -sh visiona-local/build/bin/visiona-local.exe
|
||
|
||
wails-linux: payload-linux ## ⚠️ 必須在 Linux runner 上執行:wails build -platform linux/amd64
|
||
@if [ "$$(uname -s)" != "Linux" ]; then \
|
||
echo ""; \
|
||
echo "❌ wails-linux 只能在 Linux 上 build(偵測到 $$(uname -s))"; \
|
||
echo " 請在 Linux x86_64 runner(GitHub Actions ubuntu-latest 即可)執行"; \
|
||
echo " 若只是要檢查前置步驟,可單獨跑 make payload-linux"; \
|
||
echo ""; \
|
||
exit 1; \
|
||
fi
|
||
cd visiona-local && wails build -platform linux/amd64 -clean
|
||
@du -sh visiona-local/build/bin/visiona-local
|
||
|
||
# ── 安裝檔打包 ─────────────────────────────────────────────────────
|
||
dmg: wails-macos ## hdiutil UDZO → dist/visiona-local.dmg
|
||
mkdir -p $(DIST)
|
||
rm -f $(DIST)/visiona-local.dmg
|
||
hdiutil create -volname "visionA-local" \
|
||
-srcfolder visiona-local/build/bin/visiona-local.app \
|
||
-ov -format UDZO \
|
||
$(DIST)/visiona-local.dmg
|
||
@du -sh $(DIST)/visiona-local.dmg
|
||
@file $(DIST)/visiona-local.dmg
|
||
|
||
exe: wails-windows ## ⚠️ 必須在 Windows 上跑:Inno Setup → dist/visiona-local-*-windows-x64.exe
|
||
@if ! command -v iscc > /dev/null 2>&1 && ! command -v iscc.exe > /dev/null 2>&1; then \
|
||
echo ""; \
|
||
echo "❌ Inno Setup Compiler (iscc) 未安裝"; \
|
||
echo " 請從 https://jrsoftware.org/isdl.php 下載並安裝 Inno Setup 6"; \
|
||
echo " 安裝後將 iscc.exe 目錄加入 PATH"; \
|
||
echo ""; \
|
||
exit 1; \
|
||
fi
|
||
@mkdir -p $(DIST)
|
||
iscc installer/windows/visiona-local.iss
|
||
@echo "==> 產出:"
|
||
@ls -lh $(DIST)/visiona-local-*-windows-x64.exe 2>/dev/null || echo "未找到產出檔"
|
||
|
||
appimage: wails-linux ## ⚠️ 必須在 Linux 上跑:build-appimage.sh → dist/visiona-local-*-linux-x64.AppImage
|
||
@if [ "$$(uname -s)" != "Linux" ]; then \
|
||
echo ""; \
|
||
echo "❌ appimage 只能在 Linux 上 build(偵測到 $$(uname -s))"; \
|
||
echo " 需要 appimagetool,請在 Linux x86_64 runner 執行"; \
|
||
echo ""; \
|
||
exit 1; \
|
||
fi
|
||
@mkdir -p $(DIST)
|
||
VERSION=$(VERSION) bash installer/linux/build-appimage.sh
|
||
@echo "==> 產出:"
|
||
@ls -lh $(DIST)/visiona-local-*-linux-x64.AppImage 2>/dev/null || echo "未找到產出檔"
|
||
|
||
# ── 開發(placeholder) ────────────────────────────────────────────
|
||
dev:
|
||
@echo "TODO: make -j2 dev-server dev-frontend(開發模式)"
|
||
|
||
dev-mock:
|
||
@echo "TODO: make -j2 dev-mock-server dev-frontend(Mock 模式)"
|
||
|
||
test:
|
||
@echo "TODO: go test + pnpm test"
|
||
|
||
lint:
|
||
@echo "TODO: go vet + pnpm lint"
|
||
|
||
fmt:
|
||
@echo "TODO: go fmt"
|
||
|
||
# ── 清理 ───────────────────────────────────────────────────────────
|
||
clean: ## 清除 dist/ 與 payload/ 產物
|
||
@echo "Cleaning dist/ and payload artifacts..."
|
||
rm -rf $(DIST)
|
||
rm -rf $(PAYLOAD)
|
||
@mkdir -p $(DIST) $(PAYLOAD)
|
||
@touch $(DIST)/.gitkeep $(PAYLOAD)/.gitkeep
|
||
@echo "Done."
|