feat(build): add FreeBSD x86_64 cross-compile support

方案 A(clang + lld + 本地 sysroot)。rustc 为 freebsd target 链接的系统库
(libc/libexecinfo/libgcc_s/libthr)及 sysinfo 依赖的 freebsd 专有库
(libkvm/libmemstat/libprocstat/libdevstat)需 FreeBSD 运行时,无法纯靠
clang+lld 无 sysroot 完成;故从 FreeBSD 15.1 base.txz 解出 crt 对象 + 系统库
到 .freebsd-sysroot/(gitignored,machine-local)。

- .cargo/config.toml: freebsd target 配置作为注释模板(sysroot 路径机器相关,
  不硬编码进仓库);linker 经 rustflags 的 -C linker=clang 设置,使 Makefile
  能用 CARGO_TARGET_*_RUSTFLAGS 环境变量整体注入。
- Makefile: 新增 freebsd-sysroot(幂等下载+解压 base.txz)与 build-freebsd
  (release server 二进制交叉编译)target。server 用 cargo 直出而非 dx CLI,
  因 dx 对该 target 的支持未经验证。
- .gitignore: 忽略 .freebsd-sysroot/。
- AGENTS.md: 补充构建命令说明。

实测 release 二进制 16MB,stripped ELF for FreeBSD 15.1,动态依赖均为
FreeBSD base 自带库(libc.so.7 libthr.so.3 libkvm.so.7 等)。
This commit is contained in:
xfy 2026-07-01 13:40:00 +08:00
parent 096345d2fe
commit a4331bd813
4 changed files with 70 additions and 1 deletions

View File

@ -7,3 +7,30 @@ rustflags = ["--cfg", "getrandom_backend=\"wasm_js\""]
# Uncomment and adjust after installing a musl C toolchain:
[target.x86_64-unknown-linux-musl]
linker = "x86_64-linux-musl-gcc"
# FreeBSD x86_64 交叉编译(方案 Aclang + lld + 本地 sysroot
#
# rustc 为 freebsd target 链接的系统库libc/libexecinfo/libgcc_s/libthr 等)及 sysinfo
# 依赖的 freebsd 专有库libkvm/libmemstat/libprocstat/libdevstat需 FreeBSD 运行时,
# 因此除 clang + lld 外还需一个本地 sysroot由 base.txz 解出,见 .freebsd-sysroot/)。
# ringC + 预生成 ELF 汇编freebsd 归入 LINUX_ABI与 zstd-sysbundled C用 clang 编译。
#
# sysroot 路径与机器绑定,故此 target 配置默认注释;`make build-freebsd` 会用环境变量
# CARGO_TARGET_X86_64_UNKNOWN_FREEBSD_RUSTFLAGS 注入当前机器的 sysroot 路径。
#
# 准备步骤:
# 1. pacman -S clang lld # 或 apt install clang lld
# 2. rustup target add x86_64-unknown-freebsd
# 3. make freebsd-sysroot # 下载 base.txz 并解压到 .freebsd-sysroot/
# 4. make build-freebsd # 交叉编译 release server 二进制
#
# 手动调用Makefile 之外)时取消注释并把 <SYSROOT> 改成实际路径:
# [target.x86_64-unknown-freebsd]
# linker = "clang"
# rustflags = [
# "-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",
# ]

3
.gitignore vendored
View File

@ -29,3 +29,6 @@ profile.json.gz
# Git worktrees
.worktrees/
# FreeBSD cross-compile sysroot (extracted from base.txz, machine-local)
.freebsd-sysroot/

View File

@ -13,6 +13,8 @@
make dev # tailwindcss watch + dx serve (needs PostgreSQL)
make build # build-editor → highlight-css → tailwindcss → doc → dx build --release
make build-linux # same as build but targets x86_64-unknown-linux-musl
make build-freebsd # cross-compile FreeBSD x86_64 server binary (clang + lld + sysroot)
make freebsd-sysroot # download/extract FreeBSD base.txz → .freebsd-sysroot/ (idempotent)
make css # one-shot CSS
make css-watch # watch mode
make test # cargo test + vitest (tiptap-editor + lightbox + yggdrasil-core libs)

View File

@ -1,4 +1,4 @@
.PHONY: dev build build-linux docker css css-watch clean build-editor build-editor-incremental build-lightbox build-lightbox-incremental build-core build-core-incremental build-codemirror build-codemirror-incremental highlight-css test doc doc-open start clippy fix
.PHONY: dev build build-linux build-freebsd freebsd-sysroot docker css css-watch clean build-editor build-editor-incremental build-lightbox build-lightbox-incremental build-core build-core-incremental build-codemirror build-codemirror-incremental highlight-css test doc doc-open start clippy fix
build:
@$(MAKE) build-editor
@ -24,6 +24,43 @@ build-linux:
@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."
highlight-css:
@cargo run --bin generate_highlight_css