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

推荐订阅源

P
Privacy & Cybersecurity Law Blog
SecWiki News
SecWiki News
T
Troy Hunt's Blog
Y
Y Combinator Blog
V
V2EX
美团技术团队
Last Week in AI
Last Week in AI
S
Security @ Cisco Blogs
IT之家
IT之家
博客园_首页
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
阮一峰的网络日志
阮一峰的网络日志
AI
AI
罗磊的独立博客
人人都是产品经理
人人都是产品经理
H
Hacker News: Front Page
N
News and Events Feed by Topic
P
Privacy International News Feed
V2EX - 技术
V2EX - 技术
Recent Commits to openclaw:main
Recent Commits to openclaw:main
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
GbyAI
GbyAI
L
LINUX DO - 热门话题
C
Cybersecurity and Infrastructure Security Agency CISA
Microsoft Azure Blog
Microsoft Azure Blog
Martin Fowler
Martin Fowler
月光博客
月光博客
WordPress大学
WordPress大学
Latest news
Latest news
Google DeepMind News
Google DeepMind News
S
Schneier on Security
N
Netflix TechBlog - Medium
腾讯CDC
T
Tailwind CSS Blog
TaoSecurity Blog
TaoSecurity Blog
S
Secure Thoughts
L
LINUX DO - 最新话题
Project Zero
Project Zero
Cyberwarzone
Cyberwarzone
D
DataBreaches.Net
Webroot Blog
Webroot Blog
B
Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
S
SegmentFault 最新的问题
The GitHub Blog
The GitHub Blog
H
Help Net Security
L
LangChain Blog
A
Arctic Wolf
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻

/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(其实之前已经被折磨过一次了)