
Golang 的交叉编译简直太容易了,只需设置 GOOS=linux 和 GOARCH=amd64 这两个环境变量,然后运行 go build。如果你的代码没有使用 CGO ,基本上都能顺利编译成功。
像 reqwest 这样的 HTTP 库,TLS 实现默认依赖 OpenSSL ,这会让交叉编译变得复杂起来,因为需要用到 C/C++ 的工具链,还要考虑不同的 libc 是 GNU 还是 MUSL 。虽然 Rust 也有一个纯 Rust 实现的 TLS 库 rustls,但它依赖 ring 库,而 ring 又使用了一些 C 代码,据说是为了实现加密算法的硬件加速。这些问题使得使用 TLS 的 Rust 程序交叉编译变得异常困难。
即使是在架构、系统、libc 都一致的环境下,想要静态链接编译 Rust 程序也非常麻烦。Rust 团队提供了一个工具 cross,但遇到 OpenSSL 时也可能会束手无策。
Rust 发展了这么久,为什么不能提供一个原生的、零依赖的 TLS 实现呢?
Rust 完败
1 pursuer 2024-11-18 16:14:21 +08:00 C/C++的静态交叉编译,glibc 是个坑我得承认,感觉上 musl 静态编译的话应该还好吧?当然 C++动态库 ABI 那就是另一个天坑暂且不提了。 |
2 mxT52CRuqR6o5 2024-11-18 16:19:47 +08:00 听说把 linker 换成 zig 能解决很多交叉编译中的问题 |
3 sunny352787 2024-11-18 16:26:40 +08:00 golang 的交叉编译有坑的,你能编译通过并不意味着你运行正常,之前我用 golang1.22.6 在 macos 上编译一个 windows 版本的程序,时区相关的库各种报错,在 windows 上编译就没问题 |
4 PTLin 2024-11-18 16:29:25 +08:00 请问你是没了解过 rustls 吗,reqwest 也有 rustls 的 feature 呀??? |
5 PTLin 2024-11-18 16:30:31 +08:00 一看 id ,原来又是哥们你呀。。。 |
6 bli22ard OP @a href="/member/pursuer">pursuer aarch64-musl openssl 太难搞。 |
7 PTLin 2024-11-18 16:34:14 +08:00 下次在得出 rust 发展这么久为什么还没有 rust 实现的 tls 的结论之前能不能拜托你去搜一搜,rustls 好歹 crates 上一亿的下载量。 |
8 bli22ard OP @mxT52CRuqR6o5 zig 貌似也有一些问题 @sunny352787 没用 cgo 情况下,golang ,linux 、mac 、windows 互相交叉编译没遇到过问题 @PTLin ,reqwest = {version = "0.12",default-features = false,features = ["rustls-tls"]} 加了这个, 但是编译时候,需要 gcc 来编译 ring |
9 bli22ard OP @PTLin (base) PS C:\Users\3\RustroverProjects\rs-certbot> cargo tree --target=x86_64-unknown-linux-musl -i ring ring v0.17.8 |-- instant-acme v0.7.2 | `-- rs-certbot v0.1.0 (C:\Users\3\RustroverProjects\rs-certbot) |-- rcgen v0.13.1 | `-- rs-certbot v0.1.0 (C:\Users\3\RustroverProjects\rs-certbot) |-- rustls v0.23.16 | |-- hyper-rustls v0.27.3 | | |-- instant-acme v0.7.2 (*) | | `-- reqwest v0.12.9 | | `-- rs-certbot v0.1.0 (C:\Users\3\RustroverProjects\rs-certbot) | |-- reqwest v0.12.9 (*) | `-- tokio-rustls v0.26.0 | |-- hyper-rustls v0.27.3 (*) | `-- reqwest v0.12.9 (*) |-- rustls-webpki v0.102.8 | `-- rustls v0.23.16 (*) `-- x509-parser v0.16.0 `-- rs-certbot v0.1.0 (C:\Users\3\RustroverProjects\rs-certbot) (base) PS C:\Users\3\RustroverProjects\rs-certbot> (base) PS C:\Users\3\RustroverProjects\rs-certbot> cargo tree --target=x86_64-unknown-linux-musl -i openssl-sys error: package ID specification `openssl-sys` did not match any packages (base) PS C:\Users\3\RustroverProjects\rs-certbot> |
10 Felldeadbird 2024-11-18 16:52:26 +08:00 @sunny352787 体会过这个现象。不过我的项目用到一些私有库,所以不同平台结果不一样。解决办法就是对应平台编译对应版本。 |
11 zengxs 2024-11-18 18:00:11 +08:00 因为 rust 一直试图去兼容 c/c++ 那一套生态,他生态里面很多 lib 都是直接调用了 c/c++ 的代码,所以把 c/c++ 糟粕的一部分也全盘接收了 不像 go 完全另起炉灶,生态基本上不依赖 c/c++,所以就没有这些问题 |
12 undeflife 2024-11-18 18:16:22 +08:00 > 如果你的代码没有使用 CGO ,基本上都能顺利编译成功 你用这一句话就在 go 里把 rust 里碰到的问题跳过了,至于解决方案楼上已经说了。 至于你的疑问,但凡搜一下就能知道答案。 结论,楼主很擅长钓鱼。 |
13 seers 2024-11-18 19:04:30 +08:00 via iPhone go 这点还不错,一些基础设施做了实现,cgo is not go |
14 Donaldo 2024-11-18 19:18:29 +08:00 可以试试这个 > rustls-rustcrypto - an experimental provider that uses the crypto primitives from RustCrypto for cryptography. |
15 MrKrabs 2024-11-18 20:20:00 +08:00 结果就是性能稀烂 |
16 yplam 2024-11-18 21:02:52 +08:00 via Android @undeflife 你动手试试就知道楼主说的是事实,Golang tls 不需要 cgo ,tls 这种基础库 rust 官方一直没有实现实在说不过去 |
17 ihciah 2024-11-18 21:05:13 +08:00 via iPhone 要用 openssl ,开 vendored 这个 feature 就静态链接了。 |
18 ninjashixuan 2024-11-18 21:24:07 +08:00 cgo 不是 go ,所以 go 交叉编译还是挺好使的。 |
19 bli22ard OP |
20 doraemonki 2024-11-18 21:48:31 +08:00 go 的交叉编译确实是最简单好用的 |
21 reeco 2024-11-18 23:26:08 +08:00 |
22 c0t 2024-11-19 00:45:10 +08:00 为什么呢,因为维护者少,必须承认的事情是,就你提到的 ring crate 里有相当多需要 c 编译器的部分都来自 OpenSSL 的汇编代码,不考虑性能问题,用纯 rust 来实现可以吗?当然可以。但是它(大多数时候)只有一个维护者,作为一个每月千万下载量的 crate ,就算不用 unsafe ,保证正确性也是 "i promise" 的问题,包括 tls 实现本身,本来就很大概率会是攻击发生地,密码学可不简单,作者不想做,这个保证转嫁给了 OpenSSL ,仅此而已。事实上,rustls 的性能改进还是花钱委托 ferrous-systems 来完成的。 事实上,rustls 本身过没过国外各大公司的审计呢?我没关注这个问题。 而 go 本身,微软为了给美国政府的软件,不是也 fork 了,https://github.com/microsoft/go ,并且,很明显,这些 patch 很多都和 tls 有关,https://github.com/microsoft/go/tree/microsoft/main/patches 。 |
23 c0t 2024-11-19 01:00:54 +08:00 @c0t 话说回来,交叉编译对于 rust 的现在很多 大 客户(或者说金主)来说几乎是 0 吸引力的特性,它们现在的基础设施太完善,所以可以预见的未来几年都不会有改善。 |
25 Trim21 2024-11-19 02:12:24 +08:00 via Android rustls 能算得上活跃的开发者加起来三位… |
26 Trim21 2024-11-19 02:28:55 +08:00 via Android @zengxs 还有一个原因是 go 调用 cgo 有很大的性能损失,这些东西不自己重写会导致运行效率低下… |
27 yplam 2024-11-19 08:49:47 +08:00 via Android @Donaldo 只有真正遇到过的才知道有多麻烦,譬如你可以试试找个 MIPS 架构,或者非 glibc 的 SDK ,编译个简单的 quic 客户端 |
28 map1e 2024-11-19 09:31:00 +08:00 交叉编译确实有点痛苦了,折腾半天最后还是找对应环境直接编译方便快捷 |
29 justdoit123 2024-11-19 09:56:02 +08:00 @c0t “基础设施太完善”。感觉很有道理。没有推进的动力。 |
30 InkStone 2024-11-19 09:56:47 +08:00 TLS 这块,很多核心代码是汇编的。都不是 C 不 C 的问题了,换个少见点的目标架构,神仙也没法凭空给你变出汇编代码来。 但这又确实是个性能要求很高的场景,做深度优化并没什么问题 |
31 realpg PRO @ninjashixuan #18 go 交叉编译不好使的地方还是很多 但是这些不好使的大多是冷门方向 比如吧,用 windows 的工作站开发,在 linux 的服务器下运行,这是最主流的场景 在 Mac 下开发,在 linux 的服务器下运行,也是最主流的场景 这两种场景,编译器几乎毫无 bug ,因为有 bug 也会很快修复 但是你总会遇到一些标新立异的 geek ,他们非得用 arch linux 开发,开发出来的程序还得跨平台要在 windows 下运行 这种场景,其实坑是很多的,修复也不及时,之所以说这帮人是 geek 不是大佬,是大佬早就自己提 pr 把这些修复了 类似这种东西,golang 的坑超级多 |
32 zengxs 2024-11-19 10:23:50 +08:00 @yplam #16 如果你站在应用层开发的角度的话 TLS 确实是基础库 但是如果站在系统层开发的角度,那么 TLS 就只是一个应用库了 这个其实也就是 Go / Rust 的主要区别了,它们设计出来完全就是针对不同场景的 所以我一直没搞懂为什么网上老是有人喜欢把这两个语言拿出来对比 哈哈 |
33 AItsuki 2024-11-19 10:30:29 +08:00 Rust 项目几乎就不可能没依赖 C 库的,之前我也是使用 cargo-zigbuild 工具编译,反正这语言我用起来就感觉很奇怪。 |
34 sampeng 2024-11-19 10:38:53 +08:00 其实现阶段的基础设施,交叉编译没啥太大含义了。可能对一些 arm ,交叉编译还是要的。但是 linux ,windows ,mac 这些常见的。。其实无所谓。github 有 action 。自己可以虚拟机。这样反而是最干净的。 |
35 zengxs 2024-11-19 10:49:30 +08:00 |
36 KagurazakaNyaa 2024-11-19 11:01:00 +08:00 交叉编译不如直接起个 qemu |
37 githmb 2024-11-19 11:38:38 +08:00 我编译成安卓库的时候也遇到这个 ring 的问题,降低版本就行了 |
39 c0t 2024-11-19 15:52:41 +08:00 via iPhone |
40 c0t 2024-11-19 16:01:49 +08:00 via iPhone @Donaldo mips 在 llvm 侧都烂成什么样了,rust 这边也是 tier3 ,这对 rust 目前来说是伪命题 |
42 AItsuki 2024-11-19 16:13:36 +08:00 @c0t 确实看错了问题,不过也没差吧,不管需不需要静态链接,rust 交叉编译确实困难…… 当时 windows 交叉编译 linux 一直失败就是因为没有对应的工具链的问题,所以才找的 zigbuild |
43 c0t 2024-11-19 17:05:18 +08:00 via iPhone @AItsuki 你用 musl 在纯 rust 下就不困难了啊…gnu 下不行的原因就是 rustup 默认下载的标准库是动态链接到 glibc |
44 zhwguest 2024-11-19 17:15:53 +08:00 说一千道一万,rust 不把基础的标准库问题解决,始终就是让人忐忑不安。但是按照社区这种搞法,估计够呛。都是泪。 |
45 c0t 2024-11-19 17:16:57 +08:00 via iPhone @Donaldo 不知道,所以我才说是伪命题,longarch 都是 tier2 ,那些陈年的东西压根就不会用 rust 来写 |
46 c0t 2024-11-19 17:21:14 +08:00 via iPhone @AItsuki 其实看一遍龙芯给 rustc 写的文档,你就知道该怎么做了 https://doc.rust-lang.org/rustc/platform-support/loongarch-linux.html |
47 hejw19970413 2024-11-19 17:23:58 +08:00 我这几天搞 CGO 的静态编译同样的遇到 C 库不兼容或者 GCC 编译问题。最后是用 chroot 搞定的,也是比较蛋疼 |
49 bli22ard OP @c0t 看得出来经验丰富啊。有个疑问,openssl-sys 为什么不直接映射 openssl 版本号发布,然后提供对应 rustup target list 所有编译后的版本,在 rust 层屏蔽各个平台的差异性,使用这个 crate 的人员就不用关心平台差异性。不然现在的 cargo build 看起来提供了 --target 支持交叉编译,但是大多数项目都会编译失败,tls 依赖的可能性太高了。现在这样--target ,这个参数太鸡肋了。 很多文章上用系统 openssl 编译 ,apt install libssl-dev 类似这种包管理器直接安装,这种编译使用系统 openssl 链接的,编译稳定性大大降低,因为系统各个版本安装的 openssl 版本不尽相同,难道 openssl 兼容性就这么好 |
50 openmynet 2024-11-20 11:18:15 +08:00 明显是在钓答案的。 |
52 CodeCodeStudy 2024-11-21 13:24:59 +08:00 我做的笔记 在 x86_64 的 windows 编译 aarch64 的 linux 的可执行文件 rustup target add aarch64-unknown-linux-gnu 在这个命令前可以设定环境变量 RUSTUP_DIST_SERVER=https://mirrors.tuna.tsinghua.edu.cn/rustup 需要下载相对应的平台架构的链接器 https://releases.linaro.org/components/toolchain/binaries/latest-7/aarch64-linux-gnu/ 在项目的 .cargo/config.toml 或者家目录的 .cargo/config [target.aarch64-unknown-linux-gnu] linker = "D:/lib/gcc-linaro-7.5.0-2019.12-i686-mingw32_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc.exe" 参考 https://kkua.github.io/post/cross-compile-rust-to-aarch64/ |