Index


把 rust 编译到 c

Tue Sep 23 15:25:23 CST 2025

https://github.com/rust-lang/rustc_codegen_c

今天玩一下 `rustc_codegen_c`

感觉不如 mrustc……画质

    0 ./y rustc examples/basic_math.rs
    [BUILD] build system
    error: -Zbuild-std requires --target

出现了怪报错。总之是和 build-std 有关,把 build-std 关掉看看。

    7     fn codegen_allocator(
    6         &self,
    5         _tcx: TyCtxt<'_>,
    4         _module_name: &str,
    3         _kind: AllocatorKind,
    2         _alloc_error_handler_kind: AllocatorKind,
    1     ) -> Self::Module {
    113         todo!()
    1     }

byd 这玩个鸡毛啊,内存分配器都做不出来

还是去玩 mrustc 好了。

Sat Oct 25 17:19:36 CST 2025

mrustc 已经有过使用经验了。

经过一番大调查,大概有 rust to c、mir to c 和 llvm-ir to c 三种方案

rust to c 就是经典的 mrustc。感觉因为是从头开始另造一套,不是很阳间……不知道标准库测试结果如何。

mir to c 有完全不能用的 rustc-codegen-c

https://www.reddit.com/r/rust/comments/1bhajzp/rust_to_c_compiler/:

    This means that, instead of having to maintain 2 separate projects, I can maintain one project. Bug fixes to the .NET side of things also fix C bugs. Because of that, the support for C in the project is almost as good as support for .NET.

无意间发现 rustc-codegen-clr 也是支持生成 c 的!

    Most components of std are about 95% working in .NET, and 80% working in C. So, you can compile a lot of existing Rust code, but it may not necessarily work.

而且支持 std,画质看起来比 rustc-codegen-c 高好多。

试吃一下。

    Q: Is Rust's memory management useless in .NET?
    A: Rust code typically uses the stack more than the heap, which can speed up code running within the CLR runtime. Heap-allocated objects are allocated from unmanaged (non-GC) memory and are allocated and freed in the same way as in Rust.

这么强?

也不对啊,80% working 不是说明每五个测试就会挂一个,感觉也不是很能用……

    Enidianess problems mostly come from const data - currently, it is stored as binary blobs. When I refactor that, enidianess issues will only remain in stdlib. That could be patched around by adding a new intrinsic and leaving enidianess to the compiler backend to deal with.

const data 会有端序的问题?没懂到底是只有 rustc-codegen-clr 有还是 mir 就有,需要注意一手

llvm ir to c 就是 llvm-cbe

https://github.com/JuliaHubOSS/llvm-cbe

感觉这个能最大程度复用既有的基础设施,是最阳间的一个。

但是需要自己编译 llvm……?也不用,安装正确版本的 llvm 就行了。

https://github.com/rust-lang/rust/commits/master/src/llvm-project

需要先从这里选出和 llvm-cbe 用相同版本 llvm 的 rust。现在的 llvm-cbe 版本是 llvm 19,对应的 rust 版本是 1.86.0。最好能搞个 nightly 版本的出来。

https://ianwwagner.com/the-rust-toolchain-toml-file.html

写一个 rust-toolchain.toml,限定一下版本。

    [toolchain]
    channel = "nightly-2025-02-13"
    profile = "minimal"
    components = ['rust-src']

https://github.com/louy2/rust2c-llvm-cbe

然后对着这个偷偷抄一下怎么弄……

C 语言的已经跑起来力。

我要是把 c 转换成 llvm ir 再转换成 c 会发生什么……神秘,多次转换的时候代码会逐渐膨胀

    jyi-00-rust-dev 19:24 (master) ~/dev/pixpix
    0 rustc --version --verbose
    rustc 1.86.0-nightly (ef148cd7e 2025-02-12)
    binary: rustc
    commit-hash: ef148cd7eb00a5a973130dc6473da71fd6c487ee
    commit-date: 2025-02-12
    host: x86_64-unknown-linux-gnu
    release: 1.86.0-nightly
    LLVM version: 19.1.7

检查 rustc 使用的 llvm 版本

    jyi-00-rust-dev 19:07 (master) ~/sr/la/llvm-cbe/build
    0 ~/src/lang/llvm-cbe/build/tools/llvm-cbe/llvm-cbe --version
    Debian LLVM version 19.1.7
    Optimized build.

检查 llvm-cbe 使用的 llvm 版本

    jyi-00-rust-dev 19:26 (master) ~/dev/pixpix
    0 cargo rustc --release --target-dir ./packed-llvm-ir -- --emit=llvm-ir

使用 cargo rustc 构建项目,并且生成 llvm-ir

    >1m 6s< jyi-00-rust-dev 19:27 (master) ~/dev/pixpix
    0 f packed-llvm-ir/ -iname '*.ll'
    packed-llvm-ir/release/build/num-traits-5ed0581bb5df252b/out/autocfg_691fac96cb4b949d_0.ll
    packed-llvm-ir/release/build/num-traits-5ed0581bb5df252b/out/autocfg_691fac96cb4b949d_1.ll
    packed-llvm-ir/release/build/lock_api-66145dcd3bee64ab/out/autocfg_377041ae42a1d975_0.ll
    packed-llvm-ir/release/deps/pixpix-30f5a8383400f414.ll

这对吗,为啥就这么几个 .ll 文件,依赖也没有……哦但是它一个 .ll 有 20 MB。吓哭了。

    jyi-00-rust-dev 19:29 (master) ~/dev/pixpix
    0 ~/src/lang/llvm-cbe/build/tools/llvm-cbe/llvm-cbe ./packed-llvm-ir/release/deps/pixpix-30f5a8383400f414.ll
    LLVM ERROR: Code generator does not support intrinsic function 'llvm.minnum.f64'!
    Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it):

坏,你怎么死了。

https://github.com/JuliaHubOSS/llvm-cbe/issues/111

真坏啊,看起来是 llvm-cbe 本身的问题

换个项目试试。

    jyi-00-rust-dev 19:33 (master) ~/dev/lead-to-rome
    0 ~/src/lang/llvm-cbe/build/tools/llvm-cbe/llvm-cbe packed-llvm-ir/release/deps/lead_to_rome-f8468ec2cf92376a.ll
    LLVM ERROR: Code generator does not support intrinsic function 'llvm.x86.sse2.pause'!
    Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it):

byd,怎么 sse2 都不支持,我操死你的马

https://github.com/JuliaHubOSS/llvm-cbe/issues/217

有个类似的,但是疑似不是同一个问题。

把 sse 关掉试试。我最好找一个足够老的 cpu 它不支持 sse2 的这种。

奔腾 3 好像是,但是它是 32 位的,烦内。

https://github.com/HenrikBengtsson/x86-64-level

哈哈,没有 sse2 连 x86-64 v1 都算不上。

好像没有这样的 cpu。支持 x64 的 cpu 必支持 sse2 ……算了,手动把 sse2 关掉好了。

https://github.com/rust-lang/rust/issues/133611

    on all x86 targets, we could pass SIMD vectors of up to 128 bits in registers rather than indirectly

太坏了!不让关。sse2 的寄存器会被用来传递 float

https://os.phil-opp.com/disable-simd/

不过那样的话我们只能用 soft float 了,和写操作系统一样。

哦坏,用 RUSTFLAGS 设置 target feature 的时候会导致 build.rs 出 illegal instruction 的错误。

https://users.rust-lang.org/t/different-rustflags-for-build-rs-and-main-rs/67080

这里说手动指定 --target 就好了。

    warning: target feature `sse2` must be enabled to ensure that the ABI of the current target can be implemented correctly
      |
      = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
      = note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>

    warning: target feature `soft-float` must be disabled to ensure that the ABI of the current target can be implemented correctly
      |
      = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
      = note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>

哎,急。

https://github.com/rust-lang/rust/issues/116344

    In other words, setting -Ctarget-feature=-x87 or -Ctarget-feature=+soft-float can introduce UB unless the standard library is rebuilt with the same flags.

对啊,我确实在 build-std 啊……所以没问题。至于之后 hard error 的时候,那肯定会有之后的解决方法(

    [134] jyi-00-rust-dev 20:17 (master) ~/dev/lead-to-rome
    0 RUSTFLAGS='-Ctarget-feature=-sse2,+soft-float' cargo rustc --release --target x86_64-unknown-linux-gnu --target-dir ./packed-llvm-ir -- --emit=llvm-ir

神秘小抄。

    jyi-00-rust-dev 20:18 (master) ~/dev/lead-to-rome
    0 ~/src/lang/llvm-cbe/build/tools/llvm-cbe/llvm-cbe packed-llvm-ir/x86_64-unknown-linux-gnu/release/deps/lead_to_rome-47d99845349acce0.ll
    LLVM ERROR: Code generator does not support intrinsic function 'llvm.x86.sse2.pause'!

不中嘞,为什么还是有 sse2 啊。

搞不懂了。

哦我是不是不应该用 x86_64-unknown-linux-gnu。我得用一点不那么 feature rich 的东西。

https://stackoverflow.com/questions/70738522/is-llvm-ir-a-machine-independent-language

它说 llvm ir 是个 platform independent 的东西,那我只要找个垃圾 target 过来就好了吗。

https://users.rust-lang.org/t/is-it-possible-to-cross-compile-to-a-host-platform-in-which-rust-codebase-has-no-support-for/94087/3

    LLVM's IR is not portable. It's not like JVM bytecode. It's more like assembly. It encodes a lot of specific and implicit assumptions about the target platform.

hmm,也并非 platform independent

哦我草,也不对啊,我要用 soft float,我的 libc 不用 soft float 啊,那我想调 libc 的时候不还是炸了吗。

哦,原来 llvm.x86.sse2.pause 是暗示 cpu 自己在自旋的指令,可以看作是 nop?

原来是锁相关的啊,我还以为是数学呢。

https://github.com/zlfn/rust-gb/issues/10

有人和我遇到了一样的问题,用 llvm cbe 写 rust。

感觉不太搞的定这一坨……

    jyi-00-rust-dev 21:18 (master) ~/dev/rust-hello
    0 ~/src/lang/llvm-cbe/build/tools/llvm-cbe/llvm-cbe a.ll
    Segmentation fault

它自杀了。

还是试试 rustc_codegen_clr 好了。

https://github.com/FractalFir/rustc_codegen_clr/blob/main/BROKEN_TESTS.md

怎么挂的测试这么多。好像也不是很阳间的样子。

https://github.com/thepowersgang/mrustc/issues/355

    Nothing in rustc/cargo needs async blocks, so they are not supported currently

嘛的,卧龙凤雏,这位不支持 async ……

!又试了一下 llvm-cbe,发现把优化全关了就不会生成 sse2.pause 的代码了!

    jyi-00-rust-dev 22:10 (master) ~/dev/rust-hello
    0 cargo rustc --target-dir ./packed-llvm-ir -- -C opt-level=0 -C no-prepopulate-passes -C passes="" -C link-dead-code=yes --emit=llvm-ir

https://github.com/JuliaHubOSS/llvm-cbe/issues/111

    There was also llvm.x86.sse2.pause, which is an x86-specific intrinsic. While we could add support for that, I assume you probably want to use C for portability reasons, and therefore you would want to get Rust to avoid that intrinsic by specifying a different target. Maybe something very generic like WebAssembly?

哎,又没认真读 issue,原来是已经有人遇到过的问题……

保存一下开发出来的 cargo config

    [build]
    rustflags = [
        "--cfg=has_std",
        "--emit=llvm-ir"
    ]
    target-dir = './packed-llvm-ir'
    target = 'wasm32-unknown-unknown'

    [unstable]
    build-std = ['std', 'panic_abort']
    build-std-features = [
        'compiler-builtins-no-f16-f128',
        'optimize_for_size',
    ]

编译流程:

    build:
            cargo clean
            cargo rustc --release --target-dir ./packed-llvm-ir

toolchain:

    0 cat rust-toolchain.toml
    [toolchain]
    channel = "nightly-2025-02-13"
    # channel = "1.86"
    profile = "minimal"
    components = ['rust-src']
    targets = ['wasm32-unknown-unknown']

先用 wasm32,可以开优化。x86 开优化的时候会生成 sse2 pause 指令,llvm-cbe 搞不动。

哦,wasm32 是错的!它会生成 llvm.wasm.memory.grow 指令在 dlmalloc 里面。不要用 wasm。

太坏了

那还是整没优化的 x86 好了

坏了,虽然主函数里没有 sse2 pause 了,但是但是 std 里又有了!wtf

这玩毛线啊……

这么看难道 rustc-codegen-clr 反而比较拟人吗。

https://github.com/FractalFir/rustc_codegen_clr:

    The project currently supports most Rust features (except proc macros), but it is not bug-free. It can compile a mostly working version of Rust std, but there are many minor bugs that make such std not 100% functional.

……except proc macros。

哎,没一个是人

目前来看希望最大的应该是 llvm-cbe!watch 一下好了。

rustc-codegen-clr 不知道长期来看怎么样,但是应该是最适合临时使用一下的。

……试了下发现 rustc 内部的 codegen api 改掉了,现在 master 分支已经通不过编译了,坏。

Mon Oct 27 19:15:23 CST 2025

试着改改 llvm-cbe,看看能不能跑通。感觉 cxx 好难写……

rustc 会对 bool 生成 i1 类型的 llvm ir,这个类型在 c 里没有直接的映射,很坏。

它还会生成一些不能直接映射到 c 的指令,比如一些移位什么的。需要手工写函数处理。太坏了。

我能不能从 mrustc 里面偷一些函数出来……

还有一些浮点数相关的指令,头疼。

哎,太难了。不弄了。

Mon Nov 24 12:02:35 CST 2025

前几天把 rs 编译到 js 了,启发我可能可以先把 rs 编译到 wasm,再编译到 c!

不过这样的话文件之类的库就不好用了。有点坏。可能需要 wasi,或者自己定制的一套 IO 东西?

https://www.wingolog.org/archives/2025/10/30/wastrel-a-profligate-implementation-of-webassembly

    So on coremark, Wastrel is some 2-5% percent slower than native, and w2c2 is some 2-5% slower than that. Wasmtime is 30-40% slower than GCC. Voilà.

性能也不错。

这个 wastrel 是用 c 写的啊,感觉有点不妙。

    >23s< jyi-00-rust-dev 12:14 (main) ~/sr/lang/wastrel
    0 ./pre-inst-env bin/wastrel compile -S -o test-out.c test.wasm
    ;;; note: auto-compilation is enabled, set GUILE_AUTO_COMPILE=0
    ;;;       or pass the --no-auto-compile argument to disable.
    ;;; compiling /home/jyi/src/lang/wastrel/bin/wastrel
    ;;; compiling /home/jyi/src/lang/wastrel/module/wastrel/resource.scm
    ;;; compiled /home/jyi/.cache/guile/ccache/3.0-LE-8-4.7/home/jyi/src/lang/wastrel/module/wastrel/resource.scm.go
    ;;; compiled /home/jyi/.cache/guile/ccache/3.0-LE-8-4.7/home/jyi/src/lang/wastrel/bin/wastrel.go
    LICENSE.txt  README.md     autom4te.cache/  config.log      guix.scm         resource/   whippet/
    Makefile     acinclude.m4  bin/             config.status*  module/          test-out.c
    Makefile.am  aclocal.m4    bootstrap.sh*    configure*      pre-inst-env*    test.c
    Makefile.in  apt.snapshot  build-aux/       configure.ac    pre-inst-env.in  test.wasm*

命令行接口不太好用,没啥提示信息。跟着 readme 走倒是可以。

    >28s< jyi-00-rust-dev 12:18 (main) ~/sr/lang/wastrel
    0 gcc test-out.c
    /usr/bin/ld: /tmp/ccNSKTkk.o: in function `func_52':
    test-out.c:(.text+0x6f2ab): undefined reference to `trunc'
    /usr/bin/ld: test-out.c:(.text+0x7d622): undefined reference to `trunc'
    collect2: error: ld returned 1 exit status

呃。看来需要数学库。加个 -lm 就好了。

rust 会依赖 libm 吗。

感觉这个还行。至少特性支持还算完整。

https://doc.rust-lang.org/nightly/rustc/platform-support.html

wasi 是个 T2 platform,好像也不错。

Fri Dec 12 21:20:35 CST 2025

https://jonathan.protzenko.fr/2025/10/28/eurydice.html

https://github.com/AeneasVerif/eurydice

一个把 rust 编译到 c 的编译器。看起来不用借助 wasm,而且完成度也挺高?

试吃一下。

    In terms of software architecture, Eurydice consumes Rust programs via the Charon infrastructure, then extracts Rust to KaRaMeL's internal AST via a type-driven translation. Once in the KaRaMeL AST, 30+ nano-passes allow going from Rust down to C code. About half of these passes were already implemented for KaRaMeL, the rest of the passes reuse the KaRaMeL infrastructure but were freshly written for Eurydice.