前言
最近使用 golang
编写了一个 DNS 解析代理转发的工具,功能类似于 dns2socks
,目标是准备在我 x86_64
的 OpenWRT 软路由系统中运行的;
由于我的开发机系统是 Rock Linux8
使用 golang 编译出来的应用程序默认链接的是 Glibc
库;而 OpenWRT 系统内置的是一套 musl libc 的精简系统库;
musl 是在Linux系统调用 API 之上构建的 C 标准库的实现,包括基础语言标准、POSIX 和广泛认可的扩展中定义的接口。musl轻量 、快速、简单、免费,并力求在标准一致性和安全性方面做到 正确。
musl is an implementation of the C standard library built on top of the Linux system call API, including interfaces defined in the base language standard, POSIX, and widely agreed-upon extensions. musl is lightweight, fast, simple, free, and strives to be correct in the sense of standards-conformance and safety.
因此在我开发机上由 golang 默认编译出来的程序虽然也是 x86_64 架构,但确无法在 x86_64
的 OpenWRT 系统下运行,
会报错:-ash: ./dns2socksgo: not found
如下:
静态编译
好在强大的 go 编译器可以通过指定 CGO_ENABLE=0
选项来进行纯静态的编译,让应用程序不依赖于任何外部共享库,完全独立运行,限制条件是应用程序内必须完全不包含任何 C 的代码以及未引用任何包含 C 代码的go package;
我的程序比较简单,纯静态编译后可正常运行,如下:
musl 交叉编译
但是,作为专门为 OpenWRT 系统开发的程序,我依然还是希望能跟系统原生的工具一样,链接到系统自带的 musl libc
库来运行,这样可以保持应用程序的功能纯粹性,降低程序体积;毕竟动态共享库才Linux系统下程序的正统奥义!~~
开发机安装 musl 编译器
下载 musl 源代码
最新源码在官网查看说明 https://musl.libc.org/
wget https://musl.libc.org/releases/musl-1.2.5.tar.gz
为源代码打安全补丁
在 musl 官网看到目前最新的 1.2.5
版本存在一个 CVE-2025-26519 安全漏洞,需要打两个 patch 来修正;
由于这两个 patch 都是针对 src/locale/iconv.c
源码进行了几行修改,所以我就直接参照 patch 文件内容,手动修改了源代码所设计的几行;
tar zxvf musl-1.2.5.tar.gz
cd musl-1.2.5
# 手动编辑源码文件,修补安全漏洞
vim src/locale/iconv.c
编译安装 musl
编译安装很简单,标准的 Linux 编译三步走
./configure
make
make install
# 默认编译后的安装路径为 /usr/local/musl/;
# 为了能全局使用 musl-gcc 指令,可以在 PATH 环境变量中添加 /usr/local/musl/bin
# 我是直接将 musl-gcc 软连接到了 /usr/local/bin/ 路径下
ln -s /usr/local/musl/bin/musl-gcc /usr/local/bin
现在就能正常使用 musl-gcc
编译器了
使用 musl 重新编译 go 程序
现在可以开始使用 musl 来重新编译我的 golang 程序了,并让其动态链接到 musl libc 库
# 进入golang 项目目录
cd go_proj/dns2socksgo
# 指定 CC 编译器,启用 CGO,重新编译
CC=musl-gcc CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o dns2socksgo .
现在编译出来的程序已经是正确链接到 musl libc 的动态链接程序了,并且在 OpenWRT 系统下也正常运行;