- ภาษา Zig กำลังเปลี่ยนทิศทางไปสู่การนำความสามารถของ libc มาสร้างโดยตรงในไลบรารีมาตรฐานของ Zig และค่อย ๆ ลบซอร์สโค้ด C เดิมออก
- จนถึงตอนนี้มีการลบไฟล์ซอร์ส C ไปแล้วประมาณ 250 ไฟล์ และยังเหลืออีก 2032 ไฟล์
- การเปลี่ยนผ่านนี้ส่งผลให้คอมไพล์ได้เร็วขึ้น, ขนาดการติดตั้งลดลง, และขนาดไบนารีเล็กลงเมื่อทำ static linking
- การปรับปรุงล่าสุดทำให้ zig libc ถูกปรับแต่งร่วมกับโค้ดอื่นภายใน Zig Compilation Unit (ZCU) แทนที่จะเป็น static archive แยกต่างหาก จึงสามารถกำจัดโค้ดซ้ำและทำ optimization ระดับ LTO ได้
- เมื่อ Zig เปลี่ยนไปเป็นผู้ให้บริการ static libc ด้วยตัวเอง หากเกิดปัญหาที่เกี่ยวข้อง ผู้ใช้จำเป็นต้องส่ง bug report ไปยังโปรเจ็กต์ Zig โดยตรง
ภาพรวมของโปรเจ็กต์ Zig libc
- ผู้มีส่วนร่วมหลายคนกำลังเข้าร่วมในซับโปรเจ็กต์ zig libc เพื่อแทนที่ libc ที่เดิมอิง C ด้วย wrapper ของไลบรารีมาตรฐาน Zig
- เป้าหมายคือกำจัดโค้ด C ที่ซ้ำซ้อน และให้ฟังก์ชันอย่าง
memcpy, atan2 เป็นการแมปแบบตรงไปตรงมา หรืออยู่ในรูปการห่อฟังก์ชันทั่วไปอย่าง strnlen
- ตัวอย่างเช่น ฟังก์ชัน
strnlen ถูกเขียนโดยใช้ std.mem.findScalar ของ Zig
- จนถึงตอนนี้มีการลบไฟล์ซอร์ส C ไปแล้วประมาณ 250 ไฟล์ และยังเหลืออีก 2032 ไฟล์
การปรับปรุงด้านประสิทธิภาพและโครงสร้าง
- ยิ่งแต่ละฟังก์ชันถูกย้ายมาเป็น Zig มากขึ้นเท่าใด ก็ยิ่งลดการพึ่งพาโปรเจ็กต์ภายนอกและภาษา C
- ส่งผลให้ความเร็วในการคอมไพล์ดีขึ้น, โครงสร้างและขนาดการติดตั้งเรียบง่ายและเล็กลง, และขนาดไบนารีของแอปพลิเคชันผู้ใช้ที่ลิงก์แบบสแตติกเล็กลง
- การเปลี่ยนแปลงล่าสุดทำให้ zig libc คอมไพล์ร่วมกับโค้ด Zig อื่นภายใน Zig Compilation Unit (ZCU)
- ไม่ได้ลิงก์เป็น static archive แยกต่างหาก แต่ใช้โครงสร้างที่คอมไพเลอร์และลิงเกอร์ทำงานร่วมกันแบบบูรณาการ
- ด้วยเหตุนี้จึงสามารถกำจัดโค้ดซ้ำและทำ optimization ข้ามฟังก์ชันได้
- แนวทางนี้คล้ายกับlink-time optimization (LTO) แต่เกิดขึ้นในขั้น frontend ไม่ใช่ขั้น linker
ความเป็นไปได้ในการขยายต่อในอนาคต
- หากนำไปใช้ร่วมกับการเปลี่ยนแปลงล่าสุดของ
std.Io ก็มีความเป็นไปได้ที่ผู้ใช้จะควบคุมพฤติกรรม I/O ของ libc ได้
- ตัวอย่างเช่น รวมการเรียก
read, write เข้ากับลูปอีเวนต์ io_uring
- สามารถนำความสามารถในการตรวจจับ resource leak ไปใช้กับโค้ด C ของบุคคลที่สามได้ด้วย
- อย่างไรก็ตาม ตอนนี้ยังเป็นเพียงแนวคิดที่ยังไม่ได้ทดลอง
การทดสอบและการประกันคุณภาพ
- โปรเจ็กต์ libc-test ของ Szabolcs Nagy ช่วยอย่างมากในการป้องกัน regression ของฟังก์ชันคณิตศาสตร์
- Zig libc ใช้ชุดทดสอบนี้เพื่อตรวจสอบความถูกต้อง
คำแนะนำสำหรับผู้ใช้
- Zig กำลังเปลี่ยนผ่านไปสู่ขั้นที่ให้ความสามารถของ musl, mingw-w64, wasi-libc ได้ด้วยตัวเอง
- หากเกิดปัญหาที่เกี่ยวข้อง ผู้ใช้จำเป็นต้องส่ง bug report ไปยังโปรเจ็กต์ Zig โดยตรง
- เพื่อป้องกันไม่ให้มีการส่ง issue ผิดไปยังผู้ดูแลโปรเจ็กต์ libc อิสระเดิม
สรุปท้ายเรื่อง
- ประโยคสุดท้ายของบทความจบด้วยคำว่า “Abolish ICE” (ไม่มีคำอธิบายเพิ่มเติม)
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
ไฟล์ C ถูกลบไป 250 ไฟล์ และตอนนี้เหลือ 2032 ไฟล์
การได้เฝ้าดู Zig ค่อย ๆ แทนที่ libc จากภายใน เป็นโปรเจ็กต์ระยะยาวที่น่าตื่นเต้นมาก
หลายภาษาบอกว่าจะมาแทนที่ C แต่แทบมีแค่ Zig ที่ ผสาน C ABI และระบบบิลด์ได้อย่างเป็นธรรมชาติ จริง ๆ
ฟีเจอร์ translate-c ก็ทำงานได้ดีอย่างน่าทึ่ง
ผมคิดว่าการไม่พยายามรักษาความเข้ากันได้ 99% แบบ C++ แต่เลือกคงความเรียบง่ายของ C พร้อมหลีกเลี่ยงกับดักของภาษา เป็นการตัดสินใจที่ฉลาดกว่า
สงสัยว่านี่จะหมายความว่าในระยะยาว Zig จะไม่สามารถรันบน OpenBSD ได้หรือเปล่า
เพราะ OpenBSD บล็อกการเรียก syscall โดยตรงและบังคับให้เรียกผ่าน libc เท่านั้น
ดูรายละเอียดได้ในเธรดนี้
ถ้าใส่ตัวเลือก
-dynamic -lcก็จะใช้ฟังก์ชัน libc ของระบบเป้าหมายมีระบบอย่าง macOS ที่รองรับเฉพาะ dynamic libc และเท่าที่ทราบ OpenBSD ก็รองรับ static libc ด้วย
นี่เป็นการเปลี่ยนแปลงที่น่าสนใจมากเวลาโปรเจ็กต์ Zig ลิงก์กับไลบรารี C
แต่ผมสงสัยว่าเวลาครอสคอมไพล์โปรแกรม C สำหรับ Windows ที่ใช้ MinGW ด้วย Zig ยังจะลิงก์ libc ของ MinGW แบบสแตติกได้อยู่ไหม
ถ้าระบุ
-target x86_64-windows-gnu -lcฟังก์ชัน libc บางส่วนจะมาจาก Zig และอีกบางส่วนมาจาก vendored mingw-w64Zig จัดเตรียมทุกอย่างให้ครบโดยไม่ต้องติดตั้ง mingw-w64 แยก
ถ้าต้องการก็ระบุ libc ภายนอกเองได้ด้วย
--libc libc.txtเป็นไอเดียที่เจ๋ง แต่ก็กังวลว่าจะต้องคอยตาม ช่องโหว่ CVE ของ glibc หรือ musl ต่อไปสำหรับโค้ดที่พอร์ตมาหรือไม่
สำหรับ เส้นทางโค้ดที่ใช้ร่วมกัน อย่างส่วนคณิตศาสตร์ กลับอาจช่วยลดบั๊กที่เป็นไปได้ด้วยซ้ำ
มีคำอธิบายว่า “มันคล้ายกับการเปิดใช้ LTO ข้ามขอบเขต libc แต่ทำอย่างถูกต้องที่ฝั่งฟรอนต์เอนด์แทนที่จะเป็นลิงเกอร์”
เลยสงสัยว่าทำไมในขั้นลิงเกอร์ถึงช้าเกินไป และ Zig จะทำ optimization ได้มากกว่าลิงเกอร์ระดับ LLVM IR หรือไม่
เพราะในไลบรารีสแตติกที่ถูก optimize มาแล้ว การทำ optimization แบบนี้ตอนลิงก์ทำได้ยาก
เมื่อรวมกับการเปลี่ยนแปลงล่าสุดของ std.Io ก็ทำให้น่าสนใจว่าผู้ใช้จะควบคุมพฤติกรรม I/O ของ libc ได้เอง
เช่น ทำให้การเรียก read/write ทั้งหมดเข้าร่วมกับ อีเวนต์ลูป io_uring
ส่วนตัวผมสนใจฝั่ง kqueue มากกว่า แต่คิดว่าข้อความที่ยกมานี้ก็น่าจะใช้กับฝั่งนั้นได้เหมือนกัน
ใน libc มีส่วนที่น่ากลัวอยู่เยอะ แต่โปรเจ็กต์นี้น่าสนใจจริง ๆ
อย่างเช่น "memfrob" หรือ "strfry" แต่ก็พูดขำ ๆ เพราะพวกนี้มีอยู่แค่ใน glibc :)
สงสัยว่า Rust มีอะไรแบบนี้ไหม
ไม่ได้อยากเปิดประเด็น Zig vs Rust แต่อยากสร้าง สภาพแวดล้อมที่เป็นอิสระมากขึ้น ในโปรเจ็กต์ Rust ด้วย
สงสัยว่ามีใครรู้ไหมว่า Zig จะไปถึง เวอร์ชัน 1.0 เมื่อไหร่
ผมสนใจภาษานี้มาก แต่ตอนนี้มันยังเปลี่ยนเยอะ เลยยังลังเลที่จะเอาไปใช้กับโปรเจ็กต์สำคัญ
แต่ก็มี โปรเจ็กต์โปรดักชันขนาดใหญ่ อย่าง Bun, Ghostty, Tigerbeetle ที่ตามการเปลี่ยนแปลงได้ดี
semantics ของ Zig ค่อนข้างเรียบง่าย ดังนั้นเวลาอัปเวอร์ชันก็มักแค่อัปเดตคอมไพเลอร์แล้วแก้แบบเชิงกลไม่กี่จุด
สิ่งที่ขวางผมอยู่มีแค่ความพร้อมของเพื่อนร่วมงานในการนำมาใช้ เลยตอนนี้ทำโปรเจ็กต์ที่ทำคนเดียวได้ไปก่อน
อ้างอิงเพิ่มเติมอาจดูวิดีโอนี้