yggdrasil/Makefile
xfy 856eeb758c fix(build): Docker 构建透传 git 信息,修复 x-yggdrasil-git 恒为 unknown
.dockerignore 排除 .git/,容器内 build.rs 跑不了 git 命令,导致
x-yggdrasil-git / git_hash / commit_date 响应头和启动日志全是 "unknown"
(version 来自 CARGO_PKG_VERSION 不受影响)。

三级取值链(build.rs env_or_git):
  YGG_BUILD_* 环境变量 → 本地 git 命令 → "unknown"
第一级 std::env::var 优先读 docker --build-arg 注入的值,第二级保留
本地 cargo build 的既有行为,兜底不变。

- Dockerfile: 主应用 server build 前加 ARG+ENV 块(ARG 仅 RUN 可见,
  build.rs 由 cargo 调用非 RUN,故需 export 成 ENV 让 cargo build 继承)
- Makefile: GIT_DESCRIBE/HASH/DATE 在宿主采集,GIT_BUILD_ARGS 复用块
  注入 docker/docker-amd64/docker-multiarch 三个 target
- deploy-to-linux skill: 两处 docker buildx build 命令(首装 + 更新)
  加同名 --build-arg,附说明
2026-07-22 16:05:49 +08:00

225 lines
11 KiB
Makefile
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

.PHONY: dev build build-linux build-freebsd freebsd-sysroot docker docker-amd64 docker-apple docker-multiarch css css-watch clean build-libs build-editor build-codemirror build-lightbox build-core build-xterm highlight-css katex-css test doc doc-open start lint fix restore-webp
build:
@rm -rf static/
@cd libs && pnpm install --frozen-lockfile
@$(MAKE) build-libs
@$(MAKE) highlight-css
@$(MAKE) katex-css
@tailwindcss -i input.css -o public/style.css --minify
@$(MAKE) doc
@dx build --release --debug-symbols=false
@$(MAKE) restore-webp
build-linux:
@cd libs && pnpm install --frozen-lockfile
@$(MAKE) build-libs
@$(MAKE) highlight-css
@$(MAKE) katex-css
@tailwindcss -i input.css -o public/style.css --minify
@dx build @client --release --debug-symbols=false --wasm-js-cfg false
@dx build @server --release --debug-symbols=false --target x86_64-unknown-linux-musl --wasm-js-cfg false --features server
@$(MAKE) restore-webp
@echo ""
@echo "Linux build complete! The server binary is at target/dx/yggdrasil/release/web/server"
@echo "Remember to deploy it alongside the target/dx/yggdrasil/release/web/public directory."
@echo "When running the server, ensure DIOXUS_ASSET_DIR is set or the public directory is in CWD."
# FreeBSD 15.1 base.txz 版本与下载源。sysroot 仅需 ./lib 与 ./usr/libcrt 对象 + 系统库)。
FREEBSD_VERSION ?= 15.1-RELEASE
FREEBSD_BASE_URL ?= https://download.freebsd.org/ftp/releases/amd64/amd64/$(FREEBSD_VERSION)/base.txz
FREEBSD_SYSROOT := $(CURDIR)/.freebsd-sysroot
# 下载并解压 FreeBSD base.txz 到 .freebsd-sysroot/供交叉链接crt 对象 + 系统库)。
# 幂等:若 sysroot 已存在则跳过下载。
freebsd-sysroot:
@if [ -d "$(FREEBSD_SYSROOT)/usr/lib" ] && [ -d "$(FREEBSD_SYSROOT)/lib" ]; then \
echo "FreeBSD sysroot already present at $(FREEBSD_SYSROOT)"; \
else \
echo "Downloading FreeBSD $(FREEBSD_VERSION) base.txz..."; \
curl -fL --retry 3 -o /tmp/freebsd-base.txz "$(FREEBSD_BASE_URL)"; \
mkdir -p "$(FREEBSD_SYSROOT)"; \
echo "Extracting crt objects and system libs..."; \
tar -xf /tmp/freebsd-base.txz -C "$(FREEBSD_SYSROOT)" ./lib ./usr/lib; \
rm -f /tmp/freebsd-base.txz; \
echo "FreeBSD sysroot ready at $(FREEBSD_SYSROOT)"; \
fi
# 交叉编译 FreeBSD x86_64 release server 二进制。
# 前置clang + lld 已装pacman -S clang lld、rustup target add x86_64-unknown-freebsd、
# `make freebsd-sysroot`。sysroot 路径经 CARGO_TARGET_*_RUSTFLAGS 注入,避免在
# .cargo/config.toml 里硬编码机器相关路径。server 二进制用 cargo 直出dx CLI 对该
# target 未经验证);前端 wasm 与静态资源与 build-linux 相同,不在此重复构建。
build-freebsd:
@$(MAKE) freebsd-sysroot
@SYSROOT="$(FREEBSD_SYSROOT)"; \
RUSTFLAGS_FREEBSD="-C linker=clang -C link-arg=--target=x86_64-unknown-freebsd -C link-arg=-fuse-ld=lld -C link-arg=--sysroot=$$SYSROOT -C link-arg=-L$$SYSROOT/usr/lib -C link-arg=-L$$SYSROOT/lib"; \
echo "Cross-compiling yggdrasil server for FreeBSD x86_64..."; \
CARGO_TARGET_X86_64_UNKNOWN_FREEBSD_RUSTFLAGS="$$RUSTFLAGS_FREEBSD" \
cargo build --release --target x86_64-unknown-freebsd --features server --bin yggdrasil
@echo ""
@echo "FreeBSD build complete! Server binary: target/x86_64-unknown-freebsd/release/yggdrasil"
@echo "Deploy it to FreeBSD 15+ alongside the static public/ directory."
@echo "Runtime needs (bundled in FreeBSD base): libc.so.7 libthr.so.3 libkvm.so.7 etc."
# 兜底dx build 0.7.9 会把 public/ 下的 .webp 重编码成 VP8L 无损静图
# (动画帧被丢弃,静图体积反增 7-8 倍),与文档承诺的"原样拷贝"不符。
# SVG/ICO 等其他格式不受影响,故只需覆盖 .webp。
# 遍历所有 dx 产物目录release/debug用源 public/ 的同名文件覆盖回去。
# 仅覆盖产物中已存在的 .webp不引入源里新增但 dx 未生成的文件。
# 参考https://dioxuslabs.com/learn/0.7/essentials/ui/assets/
# 上游修复后可移除此 target 及 build/build-linux 里的调用。
restore-webp:
@find target/dx -type d -path "*/web/public" 2>/dev/null | while read prod; do \
find "$$prod" -type f -name "*.webp" 2>/dev/null | while read p; do \
rel=$${p#$$prod/}; \
src="public/$$rel"; \
if [ -f "$$src" ]; then \
cp "$$src" "$$p"; \
else \
echo "restore-webp: 源缺失,跳过 $$rel"; \
fi; \
done; \
done
highlight-css:
@cargo run --bin generate_highlight_css
# 把 npm 包 katex 的 dist/ 拷贝到 public/katex/(服务端 katex-rs 不打包 CSS
# KaTeX 的 katex.min.css 用相对 URL 引 fonts/,故 fonts/ 必须与 CSS 同级。
# 只拷 woff2现代浏览器全支持省去 woff/ttf ~70% 字体体积)。
# katex 作为 libs/ workspace 根 devDependencypnpm install 后在 libs/node_modules/katex/。
katex-css:
@echo "Copying KaTeX CSS + woff2 fonts to public/katex/..."
@mkdir -p public/katex/fonts
@cp libs/node_modules/katex/dist/katex.min.css public/katex/katex.min.css
@cp libs/node_modules/katex/dist/fonts/*.woff2 public/katex/fonts/
@echo "KaTeX CSS ready at public/katex/"
# 并行构建全部 libs/ 子项目pnpm -r 拓扑顺序,无相互依赖则并发)。
# 依赖安装由调用方负责build/build-linux 用 pnpm install --frozen-lockfile
# dev 假设 node_modules 已存在)。
build-libs:
@cd libs && pnpm -r run build
# 单库便利 target替代旧的 build-<name>,用 pnpm --filter 精确定位)。
build-editor: ; @cd libs && pnpm --filter @yggdrasil/tiptap-editor run build
build-codemirror: ; @cd libs && pnpm --filter @yggdrasil/codemirror-editor run build
build-lightbox: ; @cd libs && pnpm --filter @yggdrasil/lightbox run build
build-core: ; @cd libs && pnpm --filter @yggdrasil/core run build
build-xterm: ; @cd libs && pnpm --filter @yggdrasil/xterm-terminal run build
build-mermaid: ; @cd libs && pnpm --filter @yggdrasil/mermaid-renderer run build
dev: build-libs highlight-css katex-css
@echo "Cleaning static/..."
@rm -rf static/
@echo "Building CSS..."
@$(MAKE) css
@echo "Starting dx serve..."
@SSR_CACHE_SECS=0 dx serve --addr 0.0.0.0
css:
@tailwindcss -i input.css -o public/style.css
css-watch:
@tailwindcss -i input.css -o public/style.css --watch
test:
@cargo test
@cd libs && pnpm -r run test
# JS + Rust 一次性检查(不改动文件)。
lint:
@echo "==> Biome check (libs)"
@cd libs && pnpm exec biome check . && pnpm typecheck
@echo "==> Cargo clippy (Rust)"
@cargo clippy --all-targets --all-features -- -D warnings
# JS + Rust 自动修复(直接写入文件)。
# 顺序Biome → cargo fix应用编译器建议重写代码→ cargo fmt格式化 Rust
# → dx fmt格式化 RSX 宏)。两道格式化收尾,保证最终文件状态整洁。
fix:
@echo "==> Biome format (libs, 写入文件)"
@cd libs && pnpm exec biome format --write .
@echo "==> Cargo fix (Rust, 应用编译器建议)"
@cargo fix --allow-dirty
@echo "==> Cargo fmt (Rust, 格式化)"
@cargo fmt
@echo "==> Dioxus fmt (RSX 宏, 格式化)"
@dx fmt
# 只编译当前 crate 的文档(--no-deps 跳过依赖,--document-private-items
# 让纯 binary crate 的内部模块/私有项也进文档,否则页面基本是空的)。
# RUSTDOCFLAGS 把 rustdoc 的 --default-theme=ayu 透传过去——cargo doc 本身
# 无主题参数,但会把该环境变量转交给底层 rustdoc。注意它是默认值浏览器
# 若已记住上次的主题选择localStorage则不会被覆盖。
#
# 生成后拷贝到 public/doc/,让文档随 Dioxus 静态目录发布。先清空旧目录再
# 整体拷贝避免删除模块后残留旧文件。rustdoc 内部用相对路径引用资源
# (如 ../../static.files/),原样挂载不会断链。
#
# 额外生成 public/doc/index.html 重定向页Dioxus 在 dev 用
# nest_service("/doc", ServeDir) 托管该目录ServeDir 访问目录根时默认
# 返回 index.html。用 meta refresh + JS 跳转到真正的文档入口
# yggdrasil/index.html这样裸路径 /doc 也能直达文档,且不与 Dioxus 的
# /doc/* 路由冲突(手动注册 /doc 会在 merge 时 panic
doc:
@RUSTDOCFLAGS="--default-theme=ayu" cargo doc --no-deps --document-private-items
@rm -rf public/doc
@cp -r target/doc public/doc
@printf '<!DOCTYPE html><html><head><meta charset="utf-8"><meta http-equiv="refresh" content="0;url=yggdrasil/index.html"><title>Redirecting…</title></head><body><script>location.replace("yggdrasil/index.html")</script></body></html>' > public/doc/index.html
# 同 doc生成完自动用浏览器打开。
doc-open:
@RUSTDOCFLAGS="--default-theme=ayu" cargo doc --no-deps --document-private-items --open
# Multi-arch image build via buildx. The Dockerfile builds each platform leg
# natively (amd64→x86_64 musl, arm64→aarch64 musl), so no cross-compiler or
# QEMU is needed. Docker Desktop ships a buildx builder that handles this.
#
# make docker native arch only, load into local daemon (for testing)
# make docker-amd64 x86_64 only, load into local daemon (buildx + QEMU on Apple Silicon)
# make docker-apple x86_64 only, via Apple Container CLI (macOS 26+, Apple Silicon native; no Docker needed)
# make docker-multiarch build amd64+arm64 and push to a registry
# (multi-arch manifests can't be --load-ed locally)
#
# Push examples:
# make docker-multiarch IMAGE=ghcr.io/owner/yggdrasil:latest
# make docker-multiarch IMAGE=user/yggdrasil:v1 PLATFORMS=linux/amd64
#
# git 信息透传:.dockerignore 排除 .git/,容器内 build.rs 跑不了 git 命令,
# 所以在宿主(本 Makefile 里)采集后用 --build-arg 注入。Dockerfile 把 ARG
# 再 export 成 ENV,build.rs 的 std::env::var 优先读它。三个值在 Make 变量
# 里采集一次,所有 docker target 复用;git 不可用时退化为空串,Dockerfile
# 默认值也是空,build.rs 最终降级为 "unknown",不阻断构建。
IMAGE ?= yggdrasil
PLATFORMS ?= linux/amd64,linux/arm64
GIT_DESCRIBE := $(shell git describe --tags --always --dirty 2>/dev/null)
GIT_HASH := $(shell git rev-parse HEAD 2>/dev/null)
GIT_DATE := $(shell git log -1 --format=%cd --date=iso-strict 2>/dev/null)
# build-arg 复用块:每个 docker target 展开一次。空值也传(让 Dockerfile 默认接管)。
GIT_BUILD_ARGS = --build-arg YGG_BUILD_GIT_DESCRIBE="$(GIT_DESCRIBE)" \
--build-arg YGG_BUILD_GIT_HASH="$(GIT_HASH)" \
--build-arg YGG_BUILD_GIT_COMMIT_DATE="$(GIT_DATE)"
docker:
@docker buildx build --load $(GIT_BUILD_ARGS) -t yggdrasil .
# Cross-build x86_64 into the local daemon. buildx 仿真非原生架构,无需修改 Dockerfile
# (它本就按 dpkg --print-architecture 自适应选 musl target)。Apple Silicon 上走 QEMU,
# 比 native 慢;产物可直接 docker run / docker save 导出。
docker-amd64:
@docker buildx build --platform linux/amd64 --load $(GIT_BUILD_ARGS) -t yggdrasil:amd64 .
docker-multiarch:
@docker buildx build --platform $(PLATFORMS) $(GIT_BUILD_ARGS) -t $(IMAGE) --push .
clean:
@cargo clean
@rm -f public/style.css public/highlight.css
@rm -rf public/katex
@rm -rf public/mermaid
@rm -rf public/doc
@rm -rf static/
@rm -rf uploads/.cache
@rm -rf libs/node_modules libs/*/node_modules