1 điểm bởi GN⁺ 3 giờ trước | 1 bình luận | Chia sẻ qua WhatsApp
  • crustc là bản demo đã chuyển toàn bộ rustc 1.98.0-nightly (c712ea946 2026-06-16) thành 46 triệu dòng mã C, và khi build bằng GCC cùng make sẽ tạo ra một trình biên dịch Rust hoạt động được
  • Công cụ nền tảng cillybackend trình biên dịch Rust biên dịch Rust sang C, và kho lưu trữ này là màn trình diễn nổi bật nhất cho việc trình biên dịch tự biên dịch chính nó
  • cilly truy vấn bố cục kiểu, kích thước, căn chỉnh, mã hóa ký tự, định dạng số nguyên của trình biên dịch C và nền tảng đích bằng các witness program, từ đó sinh ra mã C mà trình biên dịch C cụ thể đó có thể chấp nhận
  • Mục tiêu chính là cho phép dùng Rust trên phần cứng cũ hoặc khác thường không có hỗ trợ LLVM/GCC nhưng có trình biên dịch C, đồng thời bao gồm cả tính trong suốt mạng để giao tiếp với trình biên dịch C từ xa qua TCP
  • Mã C hiện được sinh ra đang nhắm tới ARM64 Linux là ISA của máy trạm tác giả, toàn bộ toolchain cilly vẫn chưa sẵn sàng để công khai sử dụng và tác giả vẫn đang theo dõi các lỗi liên quan đến tối ưu hóa

Bản demo chuyển rustc sang C

  • crustc là kho lưu trữ đã chuyển rustc 1.98.0-nightly (c712ea946 2026-06-16) thành 46 triệu dòng mã C
  • Mã C này có thể được build bằng GCCmake, và kết quả build là một trình biên dịch Rust hoạt động được
  • Ví dụ chạy thử là chỉ định đường dẫn thư viện LLVM rồi chạy ./rustc/rustc --version để in ra cùng phiên bản rustc 1.98.0-nightly
  • Trình biên dịch Rust được tạo ra có thể biên dịch mã, build core, alloc, std
  • Ngoài mã C, còn có một số wrapper LLVM viết bằng C++
    • Rust dùng C++ để phơi bày một số chức năng của LLVM
    • Các wrapper này phụ thuộc vào phiên bản LLVM và khá bất tiện nếu build riêng, nên được cung cấp ở dạng đã biên dịch sẵn

Vai trò của cilly

  • crustc là bản demo/teaser của cilly, một toolchain Rust-to-C mới
  • Toàn bộ toolchain cilly hướng tới việc biên dịch mã Rust của người dùng sang C phù hợp với bất kỳ đích nào
  • Kho lưu trữ này được dựng lên để cho thấy cilly biên dịch chính trình biên dịch
  • cilly vừa là thư viện Rust vừa là backend trình biên dịch Rust, tức biên dịch Rust sang C dưới dạng plugin
  • Tác giả cho biết trong 3 năm qua đã làm việc về biên dịch Rust sang C, và sau các nỗ lực công khai như rustc_codegen_clr cùng nhiều thử nghiệm riêng tư khác, cilly là lần thử thứ 14

Cách sinh mã phù hợp với trình biên dịch C

  • Đặc điểm chính của cillythích ứng với trình biên dịch C
  • Nó có thể tạo ra các witness program để kiểm tra một trình biên dịch và nền tảng cụ thể hỗ trợ những gì
    • Ví dụ là _Thread_local int KEYWORD_TLS_SUPPORTED;, chỉ biên dịch được khi trình biên dịch C đó hỗ trợ _Thread_local
  • cilly cố gắng sinh ra mã C mà một trình biên dịch C cụ thể có thể chấp nhận
  • Bố cục kiểu, kích thước, căn chỉnh, mã hóa ký tự, định dạng số nguyên đều là đối tượng được truy vấn
    • Với mã hóa ký tự, nó kiểm tra có phải ASCII hay không
    • Với định dạng số nguyên, nó kiểm tra có phải two's complement hay không
  • Khi có thể, nó dùng các phương án fallback
  • Nó cố tránh các giả định vượt ra ngoài ANSI C, đồng thời có cách lách với các hành vi liên quan đến chuẩn C hiện đại như strict aliasing
  • Trong một số trường hợp hiếm, có thể cần các giả định hợp lý như phép chuyển đổi khứ hồi (void*)(uintptr_t)(ptr)
    • Các giả định này sẽ được ghi lại và nếu có thể sẽ thêm các assert như CHAR_BIT = 8

Ràng buộc mã C theo đích và ABI

  • Mã C do cilly sinh ra là theo từng trình biên dịch
    • Mã C cilly được tạo cho Arm64 không thể chạy nguyên xi trên riscv32
    • Nhưng có thể sinh riêng mã C cilly cho riscv32
  • Mã C rustc được sinh trong kho này nhắm tới ARM64 Linux vì ISA máy trạm của tác giả
  • Mã do cilly sinh ra nhìn chung tương thích ABI với mã do rustc thông thường biên dịch
  • Trên một số nền tảng, rustc chọn ABI mà C không thể biểu diễn nên khó đạt tương thích hoàn toàn
  • Trên Arm64, có ràng buộc do con trỏ trả về cấu trúc sret
    • Trên hầu hết nền tảng, sret được truyền bằng cùng thanh ghi với đối số đầu tiên nên có thể dùng cách đặt đối số đầu tiên làm con trỏ đầu ra
    • Trên Arm64, con trỏ sret được truyền bằng thanh ghi khác
    • Tác giả giải thích rằng trình biên dịch C native cần chọn return-by-sret cho các cấu trúc nhỏ, nhưng thực tế lại không làm vậy với các cấu trúc nhỏ dưới 16 byte

Hỗ trợ các đích cũ hoặc khác thường

  • Mục tiêu chính của dự án là giúp Rust có thể dùng được trên phần cứng cũ hoặc khác thường không có hỗ trợ LLVM/GCC nhưng có hỗ trợ C
  • Khi một dự án chuyển từ Rust sang C hoặc khi xuất hiện bản thay thế bằng Rust cho một dự án C, việc thiếu hỗ trợ cho các đích như vậy có thể bị xem là nhược điểm của Rust
  • cilly bọc quanh rustc và trình biên dịch C, rồi chuyển mã Rust sang C ngay tại chỗ
  • Từ góc nhìn người dùng, cách này gần giống như định nghĩa trình biên dịch C sẽ dùng cho một đích cụ thể
  • Cấu hình ví dụ dùng triple sdcc_z180-unknown-none cùng các đối số /usr/bin/sdcc, -mz180, --std-c89, -c

Tính trong suốt mạng và trình biên dịch C từ xa

  • cillytính trong suốt mạng và có thể giao tiếp với trình biên dịch C qua TCP
  • Nếu cần, có thể mở rộng sang các phương thức giao tiếp khác thường hơn như UART
  • Cách này nhằm giải quyết nghịch lý bootstrap trên các nền tảng không có C cross-compiler
  • Có thể build và chạy một C server nhỏ trên hệ điều hành đích, rồi chạy rustc trên một nền tảng phổ biến như Linux để cilly giao tiếp qua mạng
  • Tác giả đã biên dịch thành công một chương trình Rust nhỏ cho VM x86 Plan 9 trong khi chạy rustc trên Arm64 Linux
    • Đầu ra của môi trường Plan 9 là gnot osversion 2000 cputype 386
    • Kết quả chạy /tmp/hello_plan9Hello, world!
    • Kết quả nm hiển thị symbol rust_begin_unwind

Tính năng tạo makefile

  • cilly có thể tùy chọn chèn marker vào trong object file và lưu IR vào thư mục cache
  • Sau đó có thể đọc marker đó để tách các hàm và biến toàn cục theo vị trí định nghĩa
  • Dựa trên thông tin này, nó có thể tạo ra một thư mục chứa makefile để build Rust chỉ với trình biên dịch C và make

Điều kiện build và chạy

  • Hệ thống được dùng để build demo là ARM64 Linux dựa trên Ubuntu
    • Chuỗi kernel là Linux spark-2773 6.17.0-1021-nvidia ... aarch64
  • Thông tin trình biên dịch C được dùng là GCC 13.3.0Ubuntu LLD 18.1.3
  • Để build cần đúng thư viện LLVM, và cách dễ nhất là cài nightly tương ứng bằng rustup install nightly-2026-06-16
  • Lệnh build là chạy make -j20 với LLVM_LIB_DIR trỏ tới đường dẫn libLLVM.so.22.1-rust-1.98.0-nightly
  • CFLAGS có hoạt động, nhưng một số cờ có thể làm việc biên dịch chậm hơn
  • Không khuyến nghị bật tối ưu hóa
    • Bản demo vẫn còn thô và tối ưu hóa có thể gây ra vấn đề
    • Ở quy mô này, tối ưu hóa tốn rất nhiều thời gian
  • Không bật tối ưu hóa thì trên máy của tác giả có thể build trong vài phút
    • Số đo là 937.98s user, 123.77s system, 1352% cpu, 1:18.48 total
  • Nếu bật tối ưu hóa, phần lớn mã sẽ qua nhanh nhưng có thể bị kẹt ở một số tệp Rust lớn

Kiểm thử và vấn đề đã biết

  • Bài kiểm thử build là đặt nightly LLVM library và ./rustc_driver vào LD_LIBRARY_PATH, rồi chạy ./rustc/rustc --version
  • Để build chương trình thông thường thì cần build std
    • Nếu không có std sẽ gặp lỗi error[E0463]: can't find crate for std
    • Việc build thư viện chuẩn cần tham khảo BUILDING_STD.md
  • Một lỗi đã biết là crustc có thể bị crash khi chạy trong chính thư mục đã build nó, tức thư mục gốc của kho lưu trữ, do vấn đề chuẩn hóa đường dẫn kỳ lạ
  • Khi chạy ở vị trí khác thì hoạt động bình thường

Trạng thái công khai của cilly

  • cilly vẫn chưa sẵn sàng để công khai sử dụng
  • Tác giả cho biết sẽ cố công bố sớm nhất có thể
  • Lý do công bố chậm bao gồm công việc, luận văn đại học và chấn thương tay
  • Một trong các lý do toàn bộ toolchain cilly chưa được công khai là vì tác giả vẫn đang theo dõi các lỗi liên quan đến tối ưu hóa

1 bình luận

 
Các ý kiến trên Lobste.rs
  • Điều thú vị là nó tạo ra các chương trình witness để xác nhận một compiler và platform cho trước hỗ trợ những gì
    Việc chuỗi build configure C truyền thống về cơ bản hoạt động theo cách này nghe khá lạ, nhưng cũng dễ hiểu khi compiler, hay transpiler này đi theo mô hình đó
    “Lần thử thứ 14: cilly” — đúng là sự bền bỉ đáng nể, và tôi cũng thấy ngưỡng mộ sự kiên trì đó
  • Để so sánh, Zig có một phiên bản chuyển đổi toàn bộ compiler Zig sang C, và đây là một phần của quy trình thông thường khi build từ source
    Quy mô là 4,6 triệu dòng, gần như nhỏ hơn dự án này đúng một bậc độ lớn. Mã C được tạo ra khác nhau theo từng target, nhưng không khác nhau theo từng compiler
  • Tôi không phải lập trình viên hệ thống, nhưng tò mò liệu một dự án như thế này có thể ảnh hưởng đến việc chọn dùng Rust hay Zig hay không
    Các điểm mạnh của Zig gồm hỗ trợ nhiều target cross-compile, toolchain tự host, và LLVM là phụ thuộc tùy chọn; vì vậy lời hứa có thể compile Rust thành C cho các platform hiếm cũng có vẻ như một tín hiệu nhắm về phía Zig
    • Chỉ dùng crustc thì không phải vậy. Vì compiler đã được chuyển đổi cũng chỉ hỗ trợ cùng các target compile như compiler gốc
      Tuy nhiên, có thể chuyển đổi các dự án Rust khác sang C rồi chạy và compile chúng trên những target chỉ hỗ trợ C
      Dù vậy, không nên đánh giá quá cao tác động. Đây giống một giải pháp hơi rườm rà cho một vấn đề rất ngách. rustc vốn đã hỗ trợ rất nhiều target, và dự kiến còn mở rộng thêm thông qua backend gcc
      Công cụ cross-compile của Zig rất hay, nhưng chủ yếu là tăng tính tiện lợi, đặc biệt ở phần C vốn khó xử lý hơn Zig hay Rust; ý nghĩa về việc hỗ trợ nhiều target hơn thì tương đối nhỏ
      Cuối cùng, hỗ trợ target của Zig và Rust vốn đã khá tương đồng, nên khó trở thành yếu tố quyết định; giữa hai ngôn ngữ còn có nhiều khác biệt quan trọng hơn nhiều
  • Hay thật, nhưng rốt cuộc chẳng phải vẫn bị giới hạn bởi năng lực của LLVM sao?
    • Tôi không hiểu vì sao lại phải như vậy. crustc chỉ là một ví dụ cho thấy cilly, toolchain chuyển Rust sang C, có thể làm được gì
      Toàn bộ toolchain cilly compile mã Rust của người dùng thành C cho target bất kỳ. Repository này chỉ cho thấy compiler tự compile chính nó, vì họ nghĩ đây là màn demo ấn tượng nhất
  • mrustc(https://github.com/thepowersgang/mrustc) cũng đáng xem. Đây là một compiler Rust viết bằng C++, chuyển đổi sang C rồi đưa cho GCC, nên cũng có thể chuyển rustc sang C