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

推荐订阅源

D
Darknet – Hacking Tools, Hacker News & Cyber Security
T
Troy Hunt's Blog
P
Palo Alto Networks Blog
N
News and Events Feed by Topic
Hacker News - Newest:
Hacker News - Newest: "LLM"
T
Threatpost
C
Cyber Attacks, Cyber Crime and Cyber Security
S
Schneier on Security
Google Online Security Blog
Google Online Security Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Spread Privacy
Spread Privacy
NISL@THU
NISL@THU
Cisco Talos Blog
Cisco Talos Blog
The GitHub Blog
The GitHub Blog
S
SegmentFault 最新的问题
量子位
L
Lohrmann on Cybersecurity
酷 壳 – CoolShell
酷 壳 – CoolShell
Attack and Defense Labs
Attack and Defense Labs
Y
Y Combinator Blog
Project Zero
Project Zero
AWS News Blog
AWS News Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Last Week in AI
Last Week in AI
博客园 - 聂微东
MyScale Blog
MyScale Blog
aimingoo的专栏
aimingoo的专栏
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
S
Securelist
Latest news
Latest news
C
CXSECURITY Database RSS Feed - CXSecurity.com
B
Blog RSS Feed
Webroot Blog
Webroot Blog
Blog — PlanetScale
Blog — PlanetScale
Recent Announcements
Recent Announcements
V2EX - 技术
V2EX - 技术
Schneier on Security
Schneier on Security
F
Full Disclosure
Apple Machine Learning Research
Apple Machine Learning Research
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
P
Proofpoint News Feed
Recent Commits to openclaw:main
Recent Commits to openclaw:main
月光博客
月光博客
L
LINUX DO - 最新话题
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
H
Heimdal Security Blog
F
Fortinet All Blogs
博客园_首页
N
News | PayPal Newsroom
P
Proofpoint News Feed

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