使用者在 Linux build 看到:
pkg-config --cflags ... webkit2gtk-4.0
Package 'webkit2gtk-4.0' not found
根因:Wails v2.11 預設 cgo pkg-config 指定 webkit2gtk-4.0,但 Ubuntu
22.10 之後的版本已經把系統 package 從 webkit2gtk-4.0 改名為 4.1
(API 大致相容)。使用者 bootstrap 裝的是 libwebkit2gtk-4.1-dev,
pkg-config 找不到 4.0.pc 就 fail。
修法:
1. Makefile wails-linux target 自動偵測 webkit2gtk 版本
- 優先 pkg-config --exists webkit2gtk-4.1 → wails build -tags webkit2_41
(Wails v2.10+ 支援的 build tag,切換到 4.1 的 cgo 宣告)
- 退回 pkg-config --exists webkit2gtk-4.0 → wails build 預設
- 兩者都沒有 → 清楚錯誤訊息 + 建議安裝指令
2. scripts/bootstrap-linux.sh 裝 webkit2gtk dev package 時也做版本偵測
- apt-cache show 優先查 4.1,退回 4.0
- Ubuntu 22.04 及之前 repo 有 4.0;22.10+ / 24.04 repo 只有 4.1
- 兩個都試過才 err
驗證:
- make -n wails-linux dry-run 正常 parse
- bash -n scripts/bootstrap-linux.sh 語法 OK
- macOS 端 make dmg 仍 work(未改 darwin target)
使用者待做:Linux 端 git pull 拉新版 → 重跑 bootstrap-linux.sh
(確保 webkit2gtk-4.1-dev 安裝)→ make appimage。
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
629 lines
32 KiB
Makefile
629 lines
32 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-ffmpeg-macos-build \
|
||
vendor-python-windows vendor-wheels-windows vendor-ffmpeg-windows \
|
||
vendor-python-linux vendor-wheels-linux vendor-ffmpeg-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 exe-only _run-iscc appimage \
|
||
dev test lint fmt \
|
||
clean clean-all clean-build-exe clean-build-dmg clean-build-appimage
|
||
|
||
# ── 幫助 ───────────────────────────────────────────────────────────
|
||
help: ## 列出所有 make targets
|
||
@echo "visionA-local — available targets (M1-1 skeleton)"
|
||
@echo ""
|
||
@echo " 依賴同步:"
|
||
@echo " vendor-sync 下載 python-build-standalone / wheels / ffmpeg → 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(LGPL v3,方案 B 混合)──
|
||
# v2 TDD §2.2:macOS 自 build decoder-only(~20 MB,commit 到 vendor/ffmpeg/macos/),
|
||
# Windows / Linux 用 BtbN 的 n7.1 LGPL build。
|
||
FFMPEG_VERSION := n7.1
|
||
FFMPEG_SRC_URL := https://github.com/FFmpeg/FFmpeg/archive/refs/tags/$(FFMPEG_VERSION).tar.gz
|
||
# sha256 於第一次 build 時由 `make vendor-ffmpeg-macos-build` 計算後填入 vendor/ffmpeg/macos/BUILD.md,
|
||
# 之後每次 build 使用此值做 integrity check(下方 Makefile 變數亦同步更新)。
|
||
FFMPEG_SRC_SHA256 := 7ddad2d992bd250a6c56053c26029f7e728bebf0f37f80cf3f8a0e6ec706431a
|
||
|
||
vendor-sync: vendor-python vendor-wheels vendor-ffmpeg ## 下載所有第三方依賴到 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: ## macOS:LGPL v3 ffmpeg + ffprobe 已 commit 到 vendor/ffmpeg/macos/,本 target 只驗證存在 + LGPL 合規
|
||
@if [ ! -f vendor/ffmpeg/macos/ffmpeg ]; then \
|
||
echo "❌ vendor/ffmpeg/macos/ffmpeg 不存在。"; \
|
||
echo " 第一次 build 請執行:make vendor-ffmpeg-macos-build"; \
|
||
echo " (只需要在升級 ffmpeg 版本時跑一次;平常 clone repo 後 binary 已在 git 內)"; \
|
||
exit 1; \
|
||
fi
|
||
@if [ ! -f vendor/ffmpeg/macos/ffprobe ]; then \
|
||
echo "❌ vendor/ffmpeg/macos/ffprobe 不存在。"; \
|
||
echo " 請執行:make vendor-ffmpeg-macos-build"; \
|
||
exit 1; \
|
||
fi
|
||
@echo "==> vendor/ffmpeg/macos/ffmpeg 存在:$$(du -h vendor/ffmpeg/macos/ffmpeg | cut -f1)"
|
||
@echo "==> vendor/ffmpeg/macos/ffprobe 存在:$$(du -h vendor/ffmpeg/macos/ffprobe | cut -f1)"
|
||
@if vendor/ffmpeg/macos/ffmpeg -version 2>&1 | grep -qE -- '--enable-gpl|libx264|libx265'; then \
|
||
echo "❌ LGPL 驗證失敗:binary 含 --enable-gpl / libx264 / libx265"; \
|
||
exit 1; \
|
||
fi
|
||
@echo "==> LGPL 驗證通過(無 --enable-gpl / libx264 / libx265)"
|
||
|
||
# 只有升級 ffmpeg 版本時才跑此 target;binary 產出後 commit 到 git(v2 TDD R5-6b)。
|
||
# 需要的系統依賴(macOS):
|
||
# brew install pkg-config nasm # 或 yasm
|
||
vendor-ffmpeg-macos-build: ## macOS:從源碼 build LGPL v3 decoder-only ffmpeg + ffprobe(升級時才跑,~15 分鐘)
|
||
@if [ "$$(uname -s)" != "Darwin" ]; then \
|
||
echo "❌ vendor-ffmpeg-macos-build 只能在 macOS 上跑"; exit 1; \
|
||
fi
|
||
@command -v pkg-config >/dev/null 2>&1 || { echo "❌ 需要 pkg-config(brew install pkg-config)"; exit 1; }
|
||
@command -v nasm >/dev/null 2>&1 || command -v yasm >/dev/null 2>&1 || { echo "❌ 需要 nasm 或 yasm(brew install nasm)"; exit 1; }
|
||
@mkdir -p vendor/ffmpeg/macos build/ffmpeg-macos
|
||
@echo "==> 下載 ffmpeg source $(FFMPEG_VERSION)..."
|
||
curl -fL -o build/ffmpeg-macos/source.tar.gz "$(FFMPEG_SRC_URL)"
|
||
@echo "==> 驗證 source tarball sha256..."
|
||
@echo "$(FFMPEG_SRC_SHA256) build/ffmpeg-macos/source.tar.gz" | shasum -a 256 -c || { \
|
||
echo "❌ sha256 不符,請更新 Makefile 中的 FFMPEG_SRC_SHA256 或檢查來源"; \
|
||
echo " 實際 sha256:$$(shasum -a 256 build/ffmpeg-macos/source.tar.gz | awk '{print $$1}')"; \
|
||
exit 1; }
|
||
@rm -rf build/ffmpeg-macos/src build/ffmpeg-macos/install
|
||
@mkdir -p build/ffmpeg-macos/src
|
||
tar xzf build/ffmpeg-macos/source.tar.gz -C build/ffmpeg-macos/src --strip-components=1
|
||
@echo "==> configure(decoder-only LGPL v3)..."
|
||
cd build/ffmpeg-macos/src && ./configure \
|
||
--prefix="$$(pwd)/../install" \
|
||
--enable-version3 \
|
||
--disable-debug \
|
||
--disable-doc \
|
||
--disable-ffplay \
|
||
--disable-network \
|
||
--disable-autodetect \
|
||
--disable-shared \
|
||
--enable-static \
|
||
--disable-everything \
|
||
--enable-small \
|
||
--enable-protocol=file,pipe \
|
||
--enable-demuxer=mov,avi,mpegps,mpegts,matroska,image2 \
|
||
--enable-decoder=h264,hevc,mpeg1video,mpeg2video,mpeg4,mjpeg,prores,vp8,vp9,aac,mp2,mp3,pcm_s16le,pcm_s16be \
|
||
--enable-parser=h264,hevc,mpeg4video,mpegaudio,aac \
|
||
--enable-filter=scale,format,fps,null,anull \
|
||
--enable-muxer=image2pipe,image2,null \
|
||
--enable-encoder=mjpeg \
|
||
--enable-swscale \
|
||
--enable-swresample \
|
||
--extra-cflags="-arch x86_64 -mmacosx-version-min=10.15" \
|
||
--extra-ldflags="-arch x86_64 -mmacosx-version-min=10.15 -Wl,-search_paths_first" \
|
||
--arch=x86_64 \
|
||
--target-os=darwin \
|
||
--cc="clang -arch x86_64"
|
||
cd build/ffmpeg-macos/src && make -j$$(sysctl -n hw.ncpu)
|
||
cd build/ffmpeg-macos/src && make install
|
||
@echo "==> 複製 ffmpeg + ffprobe 到 vendor/ffmpeg/macos/..."
|
||
cp build/ffmpeg-macos/install/bin/ffmpeg vendor/ffmpeg/macos/ffmpeg
|
||
cp build/ffmpeg-macos/install/bin/ffprobe vendor/ffmpeg/macos/ffprobe
|
||
@strip -S -x vendor/ffmpeg/macos/ffmpeg
|
||
@strip -S -x vendor/ffmpeg/macos/ffprobe
|
||
@chmod +x vendor/ffmpeg/macos/ffmpeg vendor/ffmpeg/macos/ffprobe
|
||
@echo "==> ad-hoc 簽章..."
|
||
codesign --force --sign - vendor/ffmpeg/macos/ffmpeg
|
||
codesign --force --sign - vendor/ffmpeg/macos/ffprobe
|
||
@echo "==> 驗證授權(configuration line 不含 --enable-gpl / libx264 / libx265)..."
|
||
@if vendor/ffmpeg/macos/ffmpeg -version 2>&1 | grep -E -- '--enable-gpl|libx264|libx265'; then \
|
||
echo "❌ LGPL 驗證失敗:build 不該出現 gpl / x264 / x265"; exit 1; \
|
||
fi
|
||
@echo "==> 複製 COPYING.LGPLv3 到 vendor/ffmpeg/macos/..."
|
||
cp build/ffmpeg-macos/src/COPYING.LGPLv3 vendor/ffmpeg/macos/COPYING.LGPLv3
|
||
@echo "==> ffmpeg 大小:$$(du -h vendor/ffmpeg/macos/ffmpeg | cut -f1)"
|
||
@echo "==> ffprobe 大小:$$(du -h vendor/ffmpeg/macos/ffprobe | cut -f1)"
|
||
@echo ""
|
||
@echo "✅ macOS LGPL ffmpeg build 完成。接下來請:"
|
||
@echo " 1) 更新 vendor/ffmpeg/macos/BUILD.md 的 Binary sha256 區塊"
|
||
@echo " 2) git add vendor/ffmpeg/macos/{ffmpeg,ffprobe,COPYING.LGPLv3,BUILD.md}"
|
||
|
||
# ── 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 ## 準備 macOS payload → payload/darwin/(含 python runtime + wheels + ffmpeg)
|
||
@echo "==> 建立 macOS payload (binary + models + scripts + python + wheels + ffmpeg + ffprobe)..."
|
||
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/macos/ffmpeg payload/darwin/bin/
|
||
cp vendor/ffmpeg/macos/ffprobe payload/darwin/bin/
|
||
cp vendor/ffmpeg/macos/COPYING.LGPLv3 payload/darwin/bin/ffmpeg-COPYING.LGPLv3
|
||
chmod +x payload/darwin/bin/ffmpeg payload/darwin/bin/ffprobe
|
||
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
|
||
# LGPL v3 build(BtbN n7.1 穩定分支,含 LGPL-safe extra libs)— v2 TDD §3
|
||
FFMPEG_URL_WINDOWS := https://github.com/BtbN/FFmpeg-Builds/releases/latest/download/ffmpeg-n7.1-latest-win64-lgpl-7.1.zip
|
||
|
||
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)..."
|
||
@PY=""; \
|
||
for candidate in "$$VISIONA_PYTHON" "py -3" python3 python; do \
|
||
[ -z "$$candidate" ] && continue; \
|
||
resolved=$$(command -v $${candidate%% *} 2>/dev/null || true); \
|
||
case "$$resolved" in *WindowsApps*) continue ;; esac; \
|
||
if $$candidate --version >/dev/null 2>&1; then PY="$$candidate"; break; fi; \
|
||
done; \
|
||
if [ -z "$$PY" ]; then \
|
||
echo "WARN: 找不到真實 python(WindowsApps stub 不算),跳過 PyPI 下載(僅使用內部 wheels)"; \
|
||
else \
|
||
echo "==> 使用 $$PY -m pip"; \
|
||
$$PY -m pip 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 LGPL v3 build (n7.1) → vendor/ffmpeg/windows/
|
||
@mkdir -p vendor/ffmpeg/windows
|
||
@if [ -f vendor/ffmpeg/windows/ffmpeg.exe ] && [ -f vendor/ffmpeg/windows/ffprobe.exe ]; then \
|
||
echo "==> ffmpeg.exe + ffprobe.exe 已存在,跳過"; \
|
||
else \
|
||
echo "==> 下載 BtbN LGPL ffmpeg (Windows, n7.1)..."; \
|
||
curl -fL -o vendor/ffmpeg/windows/ffmpeg-win.zip "$(FFMPEG_URL_WINDOWS)"; \
|
||
PY=""; \
|
||
for candidate in "$$VISIONA_PYTHON" "py -3" python3 python; do \
|
||
[ -z "$$candidate" ] && continue; \
|
||
resolved=$$(command -v $${candidate%% *} 2>/dev/null || true); \
|
||
case "$$resolved" in *WindowsApps*) continue ;; esac; \
|
||
if $$candidate --version >/dev/null 2>&1; then PY="$$candidate"; break; fi; \
|
||
done; \
|
||
if [ -z "$$PY" ]; then echo "ERROR: 需要真實 python 來解壓 zip(WindowsApps stub 無法使用)"; exit 1; fi; \
|
||
echo "==> 使用 $$PY 解壓 ffmpeg zip(取出 ffmpeg.exe / ffprobe.exe / LICENSE.txt)"; \
|
||
$$PY -c "import zipfile, os; z=zipfile.ZipFile('vendor/ffmpeg/windows/ffmpeg-win.zip'); \
|
||
wanted=['/bin/ffmpeg.exe','/bin/ffprobe.exe','/LICENSE.txt','/COPYING.LGPLv3']; \
|
||
members=[n for n in z.namelist() if any(n.endswith(w) for w in wanted)]; \
|
||
assert any(n.endswith('/bin/ffmpeg.exe') for n in members), 'ffmpeg.exe not found in zip'; \
|
||
assert any(n.endswith('/bin/ffprobe.exe') for n in members), 'ffprobe.exe not found in zip'; \
|
||
os.makedirs('vendor/ffmpeg/windows', exist_ok=True); \
|
||
[open('vendor/ffmpeg/windows/'+m.rsplit('/',1)[1],'wb').write(z.read(m)) for m in members]; \
|
||
print('extracted:', [m.rsplit('/',1)[1] for m in members])" || { echo "ERROR: python 解壓失敗"; exit 1; }; \
|
||
rm -f vendor/ffmpeg/windows/ffmpeg-win.zip; \
|
||
[ -f vendor/ffmpeg/windows/ffmpeg.exe ] || { echo "ERROR: ffmpeg.exe 沒被寫出"; exit 1; }; \
|
||
[ -f vendor/ffmpeg/windows/ffprobe.exe ] || { echo "ERROR: ffprobe.exe 沒被寫出"; exit 1; }; \
|
||
echo "==> ffmpeg.exe 大小:$$(du -h vendor/ffmpeg/windows/ffmpeg.exe | cut -f1)"; \
|
||
echo "==> ffprobe.exe 大小:$$(du -h vendor/ffmpeg/windows/ffprobe.exe | cut -f1)"; \
|
||
fi
|
||
|
||
payload-windows: build-server-windows vendor-python-windows vendor-wheels-windows vendor-ffmpeg-windows ## 準備 Windows payload → payload/windows/
|
||
@echo "==> 建立 Windows payload (binary + models + scripts + python + wheels + ffmpeg)..."
|
||
@# 注意:不 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/ffmpeg/windows/ffprobe.exe payload/windows/bin/
|
||
@# LGPL 授權條款(BtbN build 自帶 LICENSE.txt;COPYING.LGPLv3 不一定在壓縮檔內,失敗不致命)
|
||
@cp vendor/ffmpeg/windows/LICENSE.txt payload/windows/bin/ffmpeg-LICENSE.txt 2>/dev/null || true
|
||
@cp vendor/ffmpeg/windows/COPYING.LGPLv3 payload/windows/bin/ffmpeg-COPYING.LGPLv3 2>/dev/null || true
|
||
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
|
||
# LGPL v3 build(BtbN n7.1 穩定分支)— v2 TDD §4
|
||
FFMPEG_URL_LINUX := https://github.com/BtbN/FFmpeg-Builds/releases/latest/download/ffmpeg-n7.1-latest-linux64-lgpl-7.1.tar.xz
|
||
|
||
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 LGPL v3 build (n7.1) → vendor/ffmpeg/linux/
|
||
@mkdir -p vendor/ffmpeg/linux
|
||
@if [ -f vendor/ffmpeg/linux/ffmpeg ] && [ -f vendor/ffmpeg/linux/ffprobe ]; then \
|
||
echo "==> ffmpeg + ffprobe (Linux) 已存在,跳過"; \
|
||
else \
|
||
echo "==> 下載 BtbN LGPL ffmpeg (Linux, n7.1)..."; \
|
||
curl -fL -o /tmp/ffmpeg-linux.tar.xz "$(FFMPEG_URL_LINUX)"; \
|
||
rm -rf /tmp/ffmpeg-linux-extract; \
|
||
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/bin/ffmpeg vendor/ffmpeg/linux/; \
|
||
cp /tmp/ffmpeg-linux-extract/bin/ffprobe vendor/ffmpeg/linux/; \
|
||
cp /tmp/ffmpeg-linux-extract/LICENSE.txt vendor/ffmpeg/linux/LICENSE.txt 2>/dev/null || true; \
|
||
chmod +x vendor/ffmpeg/linux/ffmpeg vendor/ffmpeg/linux/ffprobe; \
|
||
rm -rf /tmp/ffmpeg-linux* ; \
|
||
echo "==> ffmpeg (Linux) 大小:$$(du -h vendor/ffmpeg/linux/ffmpeg | cut -f1)"; \
|
||
echo "==> ffprobe (Linux) 大小:$$(du -h vendor/ffmpeg/linux/ffprobe | cut -f1)"; \
|
||
fi
|
||
|
||
payload-linux: build-server-linux vendor-python-linux vendor-wheels-linux vendor-ffmpeg-linux ## 準備 Linux payload → payload/linux/
|
||
@echo "==> 建立 Linux payload (binary + models + scripts + python + wheels + ffmpeg)..."
|
||
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/ffmpeg/linux/ffprobe payload/linux/bin/ 2>/dev/null && chmod +x payload/linux/bin/ffprobe || echo "!! WARN: ffprobe 缺失"
|
||
@cp vendor/ffmpeg/linux/LICENSE.txt payload/linux/bin/ffmpeg-LICENSE.txt 2>/dev/null || true
|
||
@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
|
||
# webkit2gtk-4.0 從 Ubuntu 22.10+ / Debian 12+ 起被 webkit2gtk-4.1 取代。
|
||
# 偵測 pkg-config 哪個存在:優先用 4.1(加 -tags webkit2_41),4.0 則
|
||
# 不加 tag(Wails 預設)。
|
||
@if pkg-config --exists webkit2gtk-4.1 2>/dev/null; then \
|
||
echo "==> webkit2gtk-4.1 detected → wails build with -tags webkit2_41"; \
|
||
cd visiona-local && wails build -platform linux/amd64 -clean -tags webkit2_41; \
|
||
elif pkg-config --exists webkit2gtk-4.0 2>/dev/null; then \
|
||
echo "==> webkit2gtk-4.0 detected → wails build (default)"; \
|
||
cd visiona-local && wails build -platform linux/amd64 -clean; \
|
||
else \
|
||
echo ""; \
|
||
echo "❌ 找不到 webkit2gtk-4.0 或 webkit2gtk-4.1 dev header"; \
|
||
echo " 請執行:sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev"; \
|
||
echo " (舊版 Ubuntu 20.04 可改用 libwebkit2gtk-4.0-dev)"; \
|
||
echo ""; \
|
||
exit 1; \
|
||
fi
|
||
@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-only: ## 只跑 iscc 打包 installer(前置產物必須已存在),不重 build wails/payload
|
||
@if [ ! -f visiona-local/build/bin/visiona-local.exe ]; then \
|
||
echo "❌ visiona-local/build/bin/visiona-local.exe 不存在,請先跑 make wails-windows"; exit 1; \
|
||
fi
|
||
@if [ ! -f payload/windows/bin/visiona-local-server.exe ]; then \
|
||
echo "❌ payload/windows/bin/visiona-local-server.exe 不存在,請先跑 make payload-windows"; exit 1; \
|
||
fi
|
||
@$(MAKE) --no-print-directory _run-iscc
|
||
|
||
exe: wails-windows _run-iscc ## ⚠️ 必須在 Windows 上跑:Inno Setup → dist/visiona-local-*-windows-x64.exe
|
||
|
||
_run-iscc:
|
||
@echo "DEBUG _run-iscc: ISCC='$$ISCC'"
|
||
@echo "DEBUG _run-iscc: PATH first entries: $$(echo $$PATH | tr ':' '\n' | head -5)"
|
||
@ISCC_BIN="$$ISCC"; \
|
||
if [ -z "$$ISCC_BIN" ]; then \
|
||
if command -v iscc > /dev/null 2>&1; then ISCC_BIN=iscc; \
|
||
elif command -v iscc.exe > /dev/null 2>&1; then ISCC_BIN=iscc.exe; \
|
||
else \
|
||
for p in "/c/Program Files (x86)/Inno Setup 6/ISCC.exe" \
|
||
"/c/Program Files/Inno Setup 6/ISCC.exe" \
|
||
"$$LOCALAPPDATA/Programs/Inno Setup 6/ISCC.exe" \
|
||
"$$USERPROFILE/AppData/Local/Programs/Inno Setup 6/ISCC.exe" \
|
||
"/c/Program Files (x86)/Inno Setup 5/ISCC.exe"; do \
|
||
if [ -f "$$p" ]; then ISCC_BIN="$$p"; break; fi; \
|
||
done; \
|
||
fi; \
|
||
fi; \
|
||
ISCC_OK=0; \
|
||
if [ -n "$$ISCC_BIN" ]; then \
|
||
if [ -e "$$ISCC_BIN" ] || command -v "$$ISCC_BIN" > /dev/null 2>&1; then ISCC_OK=1; fi; \
|
||
fi; \
|
||
if [ "$$ISCC_OK" = "0" ]; then \
|
||
echo ""; \
|
||
echo "❌ Inno Setup Compiler (iscc) 未安裝 / 找不到"; \
|
||
echo " 已嘗試偵測的路徑:"; \
|
||
echo " - \$$ISCC 環境變數"; \
|
||
echo " - PATH 上的 iscc / iscc.exe"; \
|
||
echo " - /c/Program Files (x86)/Inno Setup 6/ISCC.exe"; \
|
||
echo " - /c/Program Files/Inno Setup 6/ISCC.exe"; \
|
||
echo " 請從 https://jrsoftware.org/isdl.php 下載並安裝 Inno Setup 6"; \
|
||
echo " 或設定 ISCC 環境變數指向 ISCC.exe 絕對路徑"; \
|
||
echo ""; \
|
||
exit 1; \
|
||
fi; \
|
||
echo "==> 使用 ISCC: $$ISCC_BIN"; \
|
||
mkdir -p $(DIST); \
|
||
echo "==> 執行 iscc(cwd: $$(pwd))..."; \
|
||
"$$ISCC_BIN" installer/windows/visiona-local.iss; \
|
||
ISCC_RC=$$?; \
|
||
echo "==> iscc exit code: $$ISCC_RC"; \
|
||
if [ $$ISCC_RC -ne 0 ]; then exit $$ISCC_RC; fi
|
||
@echo "==> 產出:"
|
||
@ls -lh $(DIST)/ 2>/dev/null || echo "dist 目錄不存在"
|
||
@ls -lh $(DIST)/visiona-local-*-windows-x64.exe 2>/dev/null || echo "未找到 .exe 產出檔"
|
||
|
||
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(開發模式)"
|
||
|
||
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."
|
||
|
||
clean-all: clean ## 完整清除:dist/ payload/ wails build/ frontend build/ server embed
|
||
@echo "==> 清除 Wails build 產物..."
|
||
rm -rf visiona-local/build/bin
|
||
rm -rf visiona-local/build/darwin/Resources
|
||
rm -rf visiona-local/build/windows/Resources
|
||
@echo "==> 清除 frontend build 產物..."
|
||
rm -rf frontend/out
|
||
rm -rf frontend/.next
|
||
@echo "==> 清除 server 內嵌前端..."
|
||
rm -rf server/web/out
|
||
@echo "==> clean-all 完成"
|
||
|
||
clean-build-exe: clean-all exe ## Windows:完整 clean + 從頭 build installer .exe(最乾淨的 build)
|
||
clean-build-dmg: clean-all dmg ## macOS:完整 clean + 從頭 build installer .dmg
|
||
clean-build-appimage: clean-all appimage ## Linux:完整 clean + 從頭 build installer .AppImage
|