2 điểm bởi GN⁺ 2023-12-19 | 1 bình luận | Chia sẻ qua WhatsApp
  • gccrs là dự án bắt đầu từ năm 2014 nhằm hiện thực một trình biên dịch Rust bên trong GCC; tuy vẫn còn lâu mới hoàn thiện, dự án đã có tiến triển hướng tới việc biên dịch thư viện chuẩn và được đưa vào GCC 14
  • Dự án chọn mục tiêu là Rust 1.49 thay vì các phiên bản Rust mới nhất thay đổi nhanh chóng, nhưng do các phụ thuộc nội bộ trong thư viện chuẩn nên cuối cùng vẫn phải hiện thực các tính năng như const generics
  • Việc biên dịch corealloc vẫn đang bị chặn bởi vấn đề phân giải tên macro, macro decorator, các compiler intrinsic của LLVM không có trong GCC, và việc thiếu borrow checker
  • rustc_codegen_gcc là một hướng tiếp cận trưởng thành hơn, tận dụng một phần của rustc và dùng GCC ở backend sinh mã; tính đến tháng 10/2023, nó có thể biên dịch Rust for Linux mà không cần thêm bản vá nào
  • gccrs có động lực rõ ràng như plugin bảo mật của GCC, phân tích tĩnh, các kiến trúc mà LLVM chưa hỗ trợ, và Rust for Linux, nhưng tính thực dụng hiện vẫn hạn chế hơn rustc_codegen_gcc

Mục tiêu và vị trí hiện tại của gccrs

  • gccrs là dự án nhằm hiện thực một trình biên dịch Rust bên trong GNU Compiler Collection (GCC)
  • Dự án bắt đầu từ năm 2014, và theo báo cáo dự án thì đã có tiến triển kể từ lần LWN đề cập trước đó
  • Năm 2022, mục tiêu là được đưa vào GCC 13 nhưng đã không đạt được; theo báo cáo tháng 11/2023, mục tiêu hiện là GCC 14
    • GCC 14 được xem là phiên bản có khả năng phát hành vào giữa năm 2024
  • Tại EuroRust 2023 vào tháng 10/2023, Arthur Cohen đã trình bày “The road to compiling the standard library with gccrs”, giải thích công việc biên dịch thư viện chuẩn Rust và lý do vì sao vẫn chưa thể biên dịch được

Vì sao chọn mục tiêu Rust 1.49

  • gccrs chọn Rust 1.49 làm mục tiêu thay vì liên tục đuổi theo các phiên bản Rust mới nhất
  • Rust 1.49 được phát hành vào cuối năm 2020 và là phiên bản cuối cùng trước khi hỗ trợ const generics trở nên phổ biến rộng rãi trong Rust 1.50
  • Dự án từng muốn tránh const generics, nhưng ngay cả bên trong thư viện chuẩn của Rust 1.49 thì tính năng này đã được dùng, nên cuối cùng không thể bỏ qua
  • const generics sau đó đã được hiện thực đầy đủ và không còn là chướng ngại nữa
  • gccrs không muốn tạo ra một siêu tập của Rust hay một ngôn ngữ riêng kiểu “GNU Rust”
    • Mục tiêu là tái hiện cả đầu ra, lỗi và các hành vi đặc thù của rustc
    • Vì vậy dự án sử dụng cả bộ test của Rust lẫn bộ test của GCC

Những điểm đang chặn việc biên dịch thư viện chuẩn

  • Thư viện chuẩn Rust được cấu thành từ nhiều crate
  • gccrs đang làm việc để hỗ trợ biên dịch hai crate quan trọng nhất là corealloc
    • core hiện thực các tính năng nền tảng của thư viện chuẩn như kiểu nguyên thủy và macro
    • alloc xử lý cấp phát bộ nhớ heap và nhiều kiểu container khác nhau
  • Hiện tại gccrs chưa thể biên dịch các crate này do thiếu các tính năng sau
    • Hành vi phân giải tên macro chưa đúng
    • Hỗ trợ macro decorator chưa hoàn chỉnh
    • Không có borrow checker nên không thể kiểm tra đầy đủ tính an toàn của mã
    • Cần hiện thực các LLVM compiler intrinsic không có trong GCC
  • Việc thiếu borrow checker không ngăn cản bản thân quá trình biên dịch, nhưng khiến việc kiểm tra an toàn của mã Rust không thể được thực hiện đúng cách

Macro thủ tục và công việc tích hợp với GCC

  • Tại GNU Tools Cauldron tháng 9/2023, Pierre-Emmanuel Patry đã trình bày về tiến độ đưa vào GCC 14, tập trung vào công việc liên quan đến macro
  • Cách hiện thực procedural macro đòi hỏi phải thay đổi hệ thống build của GCC
  • Procedural macro là các macro dạng hàm xuất ra token stream, chứ không chỉ đơn giản sinh ra văn bản mã nguồn như macro trong C hay C++
  • Trong Rust, chúng được hiện thực qua crate tích hợp sẵn proc_macro
  • Procedural macro khó hiện thực nhưng cho phép những tính năng rất mạnh
    • Decorator #[attribute]
    • Decorator #[derive()]
    • Tạo ngôn ngữ đặc thù miền dựa trên đánh giá tại thời điểm biên dịch
  • Theo bài trình bày tại GNU Cauldron, gccrs khi đó có hơn 800 commit cần được upstream vào GCC

Vì sao muốn tận dụng hệ sinh thái GCC cho Rust

  • Một trong những động lực chính của gccrs là tận dụng plugin bảo mật của GCC cho cả mã Rust
  • GCC có nhiều plugin hỗ trợ debug, phân tích tĩnh và hardening, và chúng hoạt động trên biểu diễn trung gian của GCC
  • gccrs muốn hỗ trợ workflow cho phép lập trình viên Rust tái sử dụng các plugin GCC hiện có
  • Cohen lấy ví dụ rằng lập trình viên C từ lâu đã thường xuyên mắc lỗi quên đóng file descriptor, nên đã có rất nhiều plugin để phát hiện kiểu lỗi này
  • Mục tiêu là cho phép tận dụng các plugin GCC và công cụ phân tích tĩnh hiện có để bắt lỗi trong mã Rust unsafe

Những lĩnh vực đã được sử dụng phần nào

  • Theo Cohen, cộng đồng homebrew Sega Dreamcast đang dùng gccrs để tạo game mới cho máy chơi game Dreamcast
  • Lý do cộng đồng Dreamcast quan tâm là vì backend LLVM của rustc không hỗ trợ kiến trúc Hitachi SH-4 của máy, trong khi GCC thì có
  • gccrs vẫn chưa hoàn thiện, nhưng vẫn hữu ích trong các trường hợp sử dụng nhúng như vậy
  • Việc phân tích tĩnh mã Rust unsafe bằng plugin GCC cũng đã có thể thực hiện
  • Trong quá trình phát triển gccrs, các tính năng ngôn ngữ như Deref và phân giải tên macro — vốn chưa được đặc tả đầy đủ — đã lộ rõ hơn, và dự án cũng có thể đóng góp cho việc bổ sung đặc tả Rust
    • Hiện Rust chưa có đặc tả chính thức, nhưng công việc đặc tả đang được tiến hành theo RFC 3355

Các tính năng cốt lõi vẫn đang được phát triển

  • gccrs vẫn còn thiếu nhiều tính năng cốt lõi của một trình biên dịch Rust
  • Các tính năng chính chưa được hiện thực hoặc vẫn đang phát triển gồm
    • async/await
    • Các LLVM intrinsic không có trong GCC
    • Macro format_args!() được dùng bởi các macro xuất như println!()
    • borrow checker dùng để cưỡng chế các quy tắc tham chiếu của Rust
  • Giải pháp nhiều triển vọng cho borrow checker là dự án riêng Polonius
  • Cohen cho biết khả năng cao gccrs sẽ tích hợp Polonius trong vài tháng tới
  • Jakub Dupak đã có tiến triển trong công việc này trong vài tháng gần đây
  • Polonius hiện là một thư viện hiện thực borrow checker tương đương về mặt ngữ nghĩa với borrow checker của rustc
    • Nó dùng một thuật toán khác để tính toán vòng đời tham chiếu
    • Về lâu dài, mục tiêu là giải quyết những thiếu sót và các corner case của borrow checker hiện tại trong rustc
    • Khi đủ trưởng thành, rustc trong tương lai cũng có thể áp dụng Polonius

Vì sao cần format_args!()

  • Theo báo cáo tháng 11/2023 của gccrs, công việc cho macro format_args!() đã được bắt đầu
  • format_args!() là macro phụ trợ để cấu thành các đối số truyền cho các macro định dạng chuỗi
  • Tính năng này liên quan đến các trait DisplayDebug
  • Nó cần thiết để chuẩn bị các đối số chuyển vào những macro như format!()println!()
  • Nếu không có format_args!(), chương trình Rust sẽ không thể tạo đầu ra có định dạng
  • Vì vậy đây là tính năng cần có ngay cả trước khi gccrs có thể biên dịch chương trình “Hello, World”
  • Phần giải thích chuyên sâu về format_args!() cũng đề cập đến bài blog của Mara Bos

Khác biệt với rustc_codegen_gcc

  • rustc_codegen_gcc là một dự án Rust dựa trên GCC khác với gccrs
  • Nó trưởng thành hơn gccrs nhưng phạm vi hẹp hơn
  • Đây không phải cách hiện thực đầy đủ một trình biên dịch Rust từ đầu
  • Nó dùng thư viện libgccjit để kết nối với API backend LLVM của rustc
  • Phần lớn quá trình biên dịch do rustc đảm nhiệm, rồi GCC được dùng ở các giai đoạn sau
  • Dù tên libgccjit có chữ JIT, rustc_codegen_gcc lại hướng tới biên dịch ahead-of-time
  • Mục tiêu chính là cho phép sinh mã Rust trên các nền tảng mà LLVM không hỗ trợ
  • Tính đến tháng 10/2023, rustc_codegen_gcc có thể biên dịch Rust for Linux mà không cần thêm bản vá nào
  • Trong một năm qua, dự án đã bổ sung hỗ trợ cho SIMD và tối ưu hóa thời gian liên kết
    • Đây là hai tính năng trước đó từng bị xem là nguyên nhân khiến test thất bại
  • Trong bài trình bày tại EuroRust, Cohen nhiều lần khuyên nên dùng rustc_codegen_gcc thay cho gccrs trong thời gian trước mắt
  • rustc_codegen_gcc đã được đưa upstream vào kho mã nguồn Rust

Rust for Linux và khoảng cách phiên bản

  • Rust for Linux là sáng kiến bổ sung hỗ trợ Rust cho nhân Linux
  • Cohen xem nhân Linux là một động lực cốt lõi của dự án gccrs
    • Vì nhiều bên liên quan đến kernel muốn nhân có thể được biên dịch chỉ bằng GNU toolchain
  • Hiện tại dự án Rust for Linux tài liệu hóa việc build mã Rust cho kernel bằng rustc hoặc rustc_codegen_gcc
  • Kernel cũng có tài liệu về các phiên bản tối thiểu được hỗ trợ của nhiều công cụ build
    • rustc không được xem theo kiểu phiên bản tối thiểu, mà phải là phiên bản khớp chính xác
    • Phiên bản rustc hiện được hỗ trợ là 1.73.0, phát hành vào tháng 10/2023
  • Giữa Rust 1.49 mà gccrs nhắm tới và Rust 1.73.0 mà Rust for Linux yêu cầu hiện có khoảng cách rất lớn
  • Hỗ trợ Rust for Linux là một mục tiêu được nêu rõ của gccrs, nhưng với khoảng cách phiên bản này thì vẫn còn khá xa

Đánh giá tổng thể

  • Kho mã nguồn gccrs có hơn 3.000 commit kể từ ngày 1/1/2023
  • Trong một năm qua, dự án đã đạt được tiến triển đáng kể
  • Tuy nhiên, vì phạm vi hiện thực đầy đủ một trình biên dịch Rust từ đầu là cực kỳ lớn, nên với gần như mọi mục đích thực dụng, nó vẫn chưa ở trạng thái có thể sử dụng
  • rustc_codegen_gcc đã được hợp nhất vào kho Rust upstream và đang được dùng thực tế trong Rust for Linux
  • Dù vẫn chưa đến giai đoạn có nhiều hiện thực trình biên dịch Rust độc lập tồn tại rộng rãi, mọi thứ đang tiến gần hơn theo hướng đó

1 bình luận

 
GN⁺ 2023-12-19
Các ý kiến trên Hacker News
  • Chỉ dựa trên lập luận trong bài thì động cơ của gccrs có vẻ hơi yếu
    Các plugin bảo mật của GCC hay việc phía nhân Linux ưu tiên chuỗi công cụ GNU có thể giải thích lý do muốn dùng GCC làm backend, nhưng không giải thích được vì sao cần một frontend trùng lặp
    Tôi không muốn Rust lặp lại sai lầm như C++, nơi phát triển đa nền tảng trở nên khó khăn vì switch của nhiều trình biên dịch, khác biệt về mức hỗ trợ ngôn ngữ và lỗi theo từng nền tảng
    Vì vậy sẽ tốt hơn nếu giải thích được vì sao gccrs là cách tiếp cận tốt hơn rustc_codegen_gcc; cách sau có vẻ đạt được cùng mục tiêu với ít công sức và rủi ro hơn nhiều

    • Nếu có thêm một triển khai Rust nữa, nó có thể đóng vai trò kiểm toán để kiểm chứng đặc tả Rust và giảm hành vi không xác định
      Khi gặp lỗi trình biên dịch trong MSVC, bạn có thể báo cáo rồi chuyển sang GCC để tiếp tục làm việc, nhưng với Rust hiện chưa có lựa chọn như vậy
    • Rust vốn đã học từ những sai lầm của C++
      Như phần được trích dẫn, việc cẩn trọng để không trở thành siêu tập của Rust là một ví dụ
      Vấn đề của C/C++ nảy sinh khi các hãng trình biên dịch cạnh tranh với nhau rằng mình “tốt hơn”, còn nhiều frontend thường có lợi thế là phơi bày nhiều lỗi và triển khai sai
    • Tôi không hiểu vì sao câu hỏi kiểu này cứ xuất hiện
      Rust đâu có thiêng liêng đến mức cấm viết lại frontend, và việc bootstrap Rust trên kiến trúc mới vẫn rất đau đớn
      Với các kiến trúc mà LLVM không hỗ trợ thì cũng không có trình biên dịch Rust hoạt động được
      codegen_rust_gcc cũng gặp cùng vấn đề bootstrap như trình biên dịch Rust hiện tại, và cần đưa hỗ trợ kiến trúc vào nhiều phần của Rust, điều mà các maintainer Rust lâu nay không mặn mà
      Vì vậy nếu trong tương lai gần có một trình biên dịch Rust dùng được ngay, để ngay cả trên các kiến trúc như Alpha cũng có thể lại build các thư viện đã được Rust hóa mà không quá khổ sở, thì đó là điều rất đáng hoan nghênh
    • Theo logic đó thì cũng phải hỏi vì sao cộng đồng LLVM không tiếp tục dùng DragonEgg mà lại tạo ra Clang, Clang++, libc++ và các thứ khác
      Khi đó đã có GCC, G++, libstdc++, frontend C++ của EDG rồi
      GCC, Clang, MSVC và các trình biên dịch khác bổ sung cho nhau, phục vụ các mục đích và thị trường khác nhau, đồng thời giúp ngôn ngữ trở nên vững chắc theo đặc tả thay vì phụ thuộc vào những đặc tính ngẫu nhiên của một triển khai duy nhất
      GNU Toolchain Project, LLVM Project và dự án Rust đều từng gặp vấn đề, nên tốt hơn là đừng phụ thuộc vào một điểm lỗi duy nhất; tính dư thừa và tính phản mong manh là bạn của chúng ta
    • Nói Rust nên học từ sai lầm của C++ và C, tức là học từ sai lầm của những ngôn ngữ tồn tại lâu nhất, có ảnh hưởng lớn nhất và được triển khai rộng rãi nhất trong lịch sử sao?
      Việc nhìn tiêu chuẩn ngôn ngữ theo hướng tiêu cực và thích nói “đoạn mã này chạy trên binary/source rustc có SHA256 hash e49d560cd008344edf745b8052ef714b07595808898c835f17f962a10012f964” hơn là “đoạn mã này là C99/C++11” thật khó hiểu
  • Rust cần có tiêu chuẩn ngôn ngữ
    https://blog.m-ou.se/rust-standard/
    https://rust-lang.github.io/rfcs/3355-rust-spec.html
    https://github.com/rust-lang/rfcs/pull/3355
    Có nhiều tổ chức và ngành sẽ không áp dụng Rust cho đến khi có tiêu chuẩn
    C, C++, C#, thậm chí JavaScript (ECMAScript) đều có tiêu chuẩn ngôn ngữ, vậy không có lý do gì Rust lại không nên có
    C: https://www.iso.org/standard/74528.html
    C++: https://isocpp.org/std/the-standard
    C#: https://learn.microsoft.com/en-us/dotnet/csharp/language-ref...
    JavaScript / ECMAScript: https://ecma-international.org/publications-and-standards/st...

    • RFC đó đã được chấp thuận và thực tế đã bắt đầu được triển khai
      Tiến độ chậm đến mức đáng thất vọng, nhưng dự án vẫn còn sống và có khả năng sẽ tăng tốc trong năm tới
      https://blog.rust-lang.org/inside-rust/2023/11/15/spec-visio...
    • Bài blog của Mara, tức liên kết đầu tiên, gần với quan điểm rằng Rust về cơ bản không cần tiêu chuẩn, vì Rust đã có cơ chế bổ sung tính năng và duy trì tương thích
    • Nhờ đặc tả Ferrocene, Rust có thể được dùng cả trong những ngành như vậy
    • Go có một đặc tả được làm rất tốt và nhiều triển khai
      https://go.dev/ref/spec
    • Để phản biện ý rằng nhiều tổ chức và ngành sẽ không áp dụng nếu không có tiêu chuẩn: Rust vẫn đang làm tốt dù không có các tổ chức và ngành đó
      Tôi không hiểu vì sao phải thay đổi một cách làm đang hoạt động tốt
  • Thật ngạc nhiên khi có nhiều phản ứng tiêu cực với GCC-RS
    Tôi cho rằng nếu một ngôn ngữ không có nhiều implementation thì đó là một ngôn ngữ khá nghèo nàn

    • Trước đây, đặc biệt vì C/C++, đó từng là quan niệm phổ biến, nhưng ngày nay điều này gây tranh cãi hơn nhiều
      Đồng thuận trong cộng đồng Rust hiện nay là cách làm hiện tại — tức một compiler duy nhất theo định nghĩa là chuẩn, nhiều tài liệu, một đặc tả tối thiểu cho ngành công nghiệp bắt buộc an toàn, và đặc tả cho một số tiểu vùng module — mang lại phần lớn lợi ích của nhiều implementation trong khi tránh được các nhược điểm
    • Về dài hạn, vấn đề là tính ổn định của cú pháp và việc ngăn phình to tính năng do extension/attribute
      C đang thực sự gặp chuyện này, còn C++ thì gần như hết cứu vì độ phức tạp vô lý và kỳ quặc
      Nếu không có điều này, khó có thể xuất hiện implementation thay thế thực tế
    • Cá nhân tôi hiểu giá trị của nhiều implementation, nhưng vấn đề là nó được xây trên GCC
      GNU toolchain là một mớ hỗn độn, và tôi thực sự không biết người ta phát triển trên đó như thế nào
      Đây không phải chuyện ý thức hệ, mà theo đúng nghĩa đen là tôi không hiểu phải thiết lập môi trường phát triển cho chính GCC ra sao
      Tôi từng không may phải bootstrap vài lần, và đó là thứ hoạt động tệ nhất trong số các phần mềm tôi từng thấy
  • Tôi thấy thú vị ở đoạn cộng đồng homebrew Sega Dreamcast có thể tạo game mới bằng gccrs, và có thể phân tích tĩnh code Rust unsafe bằng plugin GCC
    Backend LLVM của rustc không hỗ trợ kiến trúc Hitachi SH-4 của Dreamcast, nhưng GCC thì có, nên ngay cả gccrs chưa hoàn thiện cũng hữu ích cho các ứng dụng nhúng như vậy

    • Điều này hơi dễ gây hiểu lầm
      Để làm việc đó không cần frontend GCC, chỉ cần backend GCC là đủ
  • Giờ có lẽ ta sẽ thấy hỗ trợ Rust cả trên những kiến trúc mà LLVM không hỗ trợ nhưng GCC hỗ trợ, như Alpha, SuperH, VAX

    • mips64 cũng thuộc diện này, sau khi rustc gần đây thất bại trong việc lôi kéo tài trợ/tài nguyên từ Loongson rồi bỏ hỗ trợ
      https://github.com/rust-lang/compiler-team/issues/648
      Vấn đề lớn nhất của tư duy kiểu LLVM là họ dùng việc hỗ trợ kiến trúc như một phương tiện để kéo hỗ trợ từ các công ty phần cứng, tức các vị trí lập trình viên được trả lương
      Với GNU, tiêu chuẩn để merge thay đổi có thể cao đến mức phiền phức, nhưng một khi đã được đưa vào và hỗ trợ thì họ sẽ duy trì lâu dài
      Nó giống như khác biệt giữa mua và thuê; đưa hỗ trợ vào GCC tốn nhiều thời gian phát triển hơn hẳn, nhưng một khi vào rồi thì nó ở lại
    • Có lẽ các kiến trúc đã được hỗ trợ cũng sẽ có thêm tùy chọn cấu hình
      Ví dụ gần đây tôi biết rằng với RISC-V, GCC hỗ trợ target RV32E còn LLVM thì không
    • Tôi rất muốn sớm thấy mã máy PDP-11 sinh ra từ Rust
      Lần cuối tôi kiểm tra, biên dịch C độc lập trên GCC vẫn còn hoạt động
  • Theo kinh nghiệm của tôi, việc gccrs không tạo ra một ngôn ngữ riêng gọi là “GNU Rust” mà cố sao chép output, cả bug lẫn điểm kỳ lạ của rustc, là một sai lầm lớn
    Rust không có đặc tả; có tài liệu tham khảo, nhưng nó được nói rõ là không mang tính quy phạm
    Một ngôn ngữ không được tài liệu hóa ngoài một implementation tham chiếu duy nhất sẽ có điểm yếu dài hạn
    Mục tiêu đảm bảo code hiện có chạy trên cả hai implementation là hợp lý, nhưng nếu hứa cả tương thích bug thì sẽ hóa thạch các quyết định sai và bug
    Microsoft dùng rất nhiều nhân lực để sửa lỗi bảo mật và độ tin cậy trong khi vẫn giữ cho chương trình cũ tiếp tục chạy, nhưng Rust không cần phải gánh gánh nặng đó khi vòng đời còn sớm
    Nếu muốn phát triển ngôn ngữ, phải chấp nhận đảm bảo chất lượng và kiểm soát chất lượng
    Chất lượng không thể được bơm thêm về sau bằng test; nó phải được làm cho vận hành đúng — và nếu thất bại thì thất bại theo hướng đúng — thông qua kiến trúc, thiết kế, quy trình như review thiết kế và code
    Các chuẩn mạnh như Common Lisp, C++, FORTRAN đã chấp nhận niềm tin này; các ngôn ngữ yếu gần như là chuẩn trên thực tế như Python cũng có thể phổ biến, nhưng việc thay đổi khó khăn được thể hiện qua quá trình chuyển đổi dài từ Python 2 sang 3 và số lượng implementation ít

    • Nếu tìm thấy bug lớn thì có lẽ chỉ cần báo lên upstream và thay đổi cả hai implementation là được
  • Tôi tham gia muộn ở phần sau của thread này, nhưng đây không hẳn là chuyện tốt
    Các distro đã không theo kịp những ngôn ngữ ra phiên bản mới vài tháng một lần, nên vốn đã khó dùng rustc hay Go từ package của distro
    Hiện nay, thật đáng ngạc nhiên, có những hệ thống đã loại bỏ GCC vì không còn cần đến, và chỉ duy trì Go cùng Rust từ upstream để cập nhật phần mềm hiện có
    Vài tháng trước khi cập nhật Go vì CVE, tôi thấy các app dựa trên Go lưu riêng tới bốn môi trường Go của chúng, đúng là ác mộng

  • Linux vốn đã có thể được compile bằng Clang nếu muốn, để dùng toàn bộ toolchain dựa trên LLVM
    Nỗ lực trùng lặp để phát triển và duy trì thứ này vì “tính thuần khiết” GNU có vẻ không đáng

    • Đây không phải vấn đề tính thuần khiết, mà là vấn đề lựa chọn
      Cộng đồng ClangBuiltLinux từng lập luận rằng Linux không nên phụ thuộc vào một compiler duy nhất, nhưng khi Rust xuất hiện, khá nhiều người trong chính nhóm đó bỗng bắt đầu cho rằng một compiler duy nhất cũng ổn
    • Có vẻ ở đây có sự hiểu lầm
      Không phải là muốn trói kernel vào riêng GNU, mà chỉ là muốn có thể chọn toolchain GNU thuần túy