惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

宝玉的分享
宝玉的分享
AWS News Blog
AWS News Blog
Y
Y Combinator Blog
云风的 BLOG
云风的 BLOG
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
F
Full Disclosure
H
Help Net Security
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
A
About on SuperTechFans
J
Java Code Geeks
Jina AI
Jina AI
GbyAI
GbyAI
酷 壳 – CoolShell
酷 壳 – CoolShell
爱范儿
爱范儿
美团技术团队
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Latest news
Latest news
Vercel News
Vercel News
博客园 - 【当耐特】
P
Privacy & Cybersecurity Law Blog
P
Proofpoint News Feed
阮一峰的网络日志
阮一峰的网络日志
V
Vulnerabilities – Threatpost
Stack Overflow Blog
Stack Overflow Blog
Hugging Face - Blog
Hugging Face - Blog
D
Docker
Microsoft Security Blog
Microsoft Security Blog
博客园_首页
S
Securelist
WordPress大学
WordPress大学
S
Secure Thoughts
博客园 - 聂微东
Cloudbric
Cloudbric
Help Net Security
Help Net Security
腾讯CDC
T
Threat Research - Cisco Blogs
T
Tor Project blog
L
LINUX DO - 热门话题
Project Zero
Project Zero
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - Franky
N
Netflix TechBlog - Medium
小众软件
小众软件
Cyberwarzone
Cyberwarzone
量子位
MyScale Blog
MyScale Blog
W
WeLiveSecurity
MongoDB | Blog
MongoDB | Blog
I
InfoQ
M
MIT News - Artificial intelligence

/home/rook1e

AI 编码小记 1 | /home/rook1e 独立开发备忘录 | /home/rook1e 使用 Cline + Gemini 2.5 Pro 来做 Vibe coding | /home/rook1e RawWeb 更新:SimHash 和 Meilisearch | /home/rook1e Neovim、终端和生产力 | /home/rook1e RawWeb.org 的前三次技术栈迭代 | /home/rook1e 配置轻量级 Linux 远程开发环境(Fedora 38) | /home/rook1e 我的透明代理方案 1.0 | /home/rook1e 深入理解 Linux TProxy | /home/rook1e 我的初代 NAS | /home/rook1e 劫持 Golang 编译 | /home/rook1e 初探 Golang 代码混淆 | /home/rook1e 「SF」子域名搜集工具开发小结 | /home/rook1e Code-Breaking 2020 Bashinj | /home/rook1e 浅谈 HTTP 请求走私 | /home/rook1e 从 Material-T 到 Fluid | /home/rook1e
被 CGO 交叉编译折磨的一个周末 | /home/rook1e
Yuan (rook1e) · 2025-08-17 · via /home/rook1e
目录

TL;DR

使用 zig cc 交叉编译 CGO 项目时,rpath 设置无法生效导致运行时无法加载 .so,最后改用 Docker buildx 绕过交叉编译问题。

背景

RawWeb 是我维护的一个专注于个人网站的搜索引擎,其中为了识别相似内容,需要先将内容分词然后计算 simhash 值。

除了 n-gram 等比较粗暴的分词方式,还用到了 charabia。这是一个 Meilisearch 维护的支持多种语言分词的 Rust 库,目前我主要用它来处理中文分词。

于是需要在 Go 中调用 Rust 代码。考虑到 WASM 和调用二进制文件的方式性能损耗都较大,最终选择了 CGO 的方式。我的开发环境是 ARM 架构的 macOS,服务器是 ARM 架构的 Linux,所以部署前还需要交叉编译。为了省事,之前都是在本地编译出二进制文件然后上传到服务器运行。

项目中交叉编译 CGO 有两点关键点:

  • 如果是目标是 Linux ARM64,通过 LDFLAGS 设置不同的 .so 加载路径:在编译时用开发环境代码库的路径,运行时用二进制文件的同级 lib 目录
  • 使用 zig 提供的交叉编译工具链
// #cgo linux,arm64 LDFLAGS: -L${SRCDIR}/charabia-rs/target/aarch64-unknown-linux-gnu/release -lcharabia_rs -Wl,-rpath,'$$ORIGIN/lib'
// #cgo darwin LDFLAGS: -L${SRCDIR}/charabia-rs/target/release -lcharabia_rs
CGO_ENABLED=1 GOOS=linux GOARCH=arm64 \
    CC="zig cc -target aarch64-linux" CXX="zig c++ -target aarch64-linux" \
    go build -a -o build/server ./cmd/server

问题出现:rpath 无法生效

这套配置在过去几个月中一直运行良好。但在这次升级 charabia 并调整编译脚本后,生产环境下服务启动失败,报告找不到 .so。

通过 ldd 命令检查二进制文件可以发现问题:程序仍然试图从我本地开发环境的绝对路径加载 .so,rpath 的设置并未生效:

debian@debian:~/rawweb/build$ ldd server
    linux-vdso.so.1 (0x0000ffff9ec46000)
    /Users/rook1e/Projects/rawweb/backend/core/pkgs/simhash/tokenizer/charabia/charabia-rs/target/aarch64-unknown-linux-gnu/release/libcharabia_rs.so => not found
    libc.so => not found

带着“为什么前几个月都正常”的疑惑,与 Claude Code 结伴尝试了各种方式,但都未能让 zig 正确设置 rpath。猜测可能与 zig issue #17373 - Issues with how rpaths are handled by the build system 有关。

时间有限,我决定不再继续深究此问题,转而寻找一种能绕过交叉编译的替代方案。

Docker buildx 绕过交叉编译

最后决定绕过交叉编译,用 Docker buildx 在一个 ARM64 的环境里编译。

这就到 CC 擅长的领域了:

# Build stage
FROM --platform=linux/arm64 golang:1.25 AS builder

# Install build dependencies
RUN apt-get update && apt-get install -y \
    build-essential \
    curl \
    && rm -rf /var/lib/apt/lists/*

# Install Rust
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
ENV PATH="/root/.cargo/bin:${PATH}"

WORKDIR /app

# Copy go mod files
COPY go.mod go.sum ./
RUN go mod download

# Copy source code
COPY . .

# Build Rust tokenizer
WORKDIR /app/core/pkgs/simhash/tokenizer/charabia/charabia-rs
RUN cargo build --release
RUN mkdir -p /app/build/lib && cp target/release/libcharabia_rs.so /app/build/lib/

# Build Go application
WORKDIR /app
RUN go run ./cmd/dbgen
ENV CGO_ENABLED=1 CGO_LDFLAGS="-Wl,-rpath,\$ORIGIN/lib"
RUN go build -a -trimpath -ldflags="-extldflags=-Wl,-rpath,\$ORIGIN/lib" -o /app/build/server ./cmd/server

# Runtime stage
FROM --platform=linux/arm64 debian:12-slim
WORKDIR /app
RUN apt-get update && apt-get install -y \
    ca-certificates \
    && rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/build/server ./
COPY --from=builder /app/build/lib ./lib/
EXPOSE 3000
CMD [ "./server" ]
docker buildx build --platform linux/arm64 ...

推送到线上,顺利运行。因为本机也是 ARM64,不需要用 QEMU 模拟目标架构,所以镜像编译速度可以接受。

教训

  • 遇到不重要且超出能力范围的问题时别犟,赶紧想办法绕过
  • 远离 CGO(其实之前已经被折磨过一次了)