Zig 套件管理與建置系統重構
Zig 套件管理與建置系統重構
Zig 已將套件管理邏輯從編譯器執行檔中解耦,移入建置系統(即「maker」程序)。此架構變更讓套件管理任務可以在不重新編譯編譯器的情況下修補,並且能在網路操作時使用 ReleaseSafe 模式,提升整體安全性與效能。
套件管理已移至建置系統
Zig 將套件管理的責任從編譯器轉移到建置系統。這意味著 zig build、zig fetch、zig init、zig libc 等子指令現在由 maker 程序而非編譯器執行檔處理。
因此,先前捆綁在編譯器內的多個元件現在以原始碼形式提供,包括:
- 套件抓取邏輯
- HTTP 客戶端與網路堆疊
- TLS(傳輸層安全)與相關密碼學
- Git 協定實作
- 壓縮函式庫(xz、gzip、zstd、flate、zip)
build.zig.zon解析與驗證
此分離讓建置系統能利用主機特定的 CPU 指令執行密碼學與檔案雜湊,這些指令若直接放入通用編譯器發行版會太少見。同時也將 Zig 可執行檔的大小減少約 4%(在無 LLVM、ReleaseSmall 設定下,從 14.1 MiB 降至 13.5 MiB)。
程序架構演進
為了支援此變更,Zig 演進了其程序樹,確保建置系統在設定重新執行時仍保持為父程序。
先前的架構:
zig build (the zig compiler + package manager)
└─ builder (the user's build.zig logic + build system implementation)
中間的架構:
zig build (the zig compiler + package manager)
├─ configurer (the user's build.zig logic)
└─ maker (build system)
目前的架構:
zig build (the zig compiler)
└─ maker (build system + package manager)
└─ configurer (the user's build.zig logic)
透過讓 maker 成為 configurer 的父程序,maker 即使在 configurer 必須重新執行(例如在 zig build --watch 期間)時也能持續存在,避免伺服器必須退出、客戶端重新連線的情況。這是向外部公開建置伺服器協定、解除 ZLS(Zig Language Server)阻礙的關鍵一步。
建置系統效能與重構
Zig 引入了「configurer」(執行使用者的 build.zig 邏輯)與「maker」(執行建置圖)之間的分離。configurer 以 debug 模式編譯,而 maker 以 release 模式編譯。
此重構帶來三大效能好處:
- 縮短編譯時間: 只有使用者的
build.zig邏輯在變更時會被重新編譯,而不是整個建置系統。 - 快取設定: 若偵測不到變更,建置系統可直接使用序列化的二進位設定檔,完全跳過重新執行
build.zig邏輯。 - 執行最佳化: 執行建置圖的程序現在已以最佳化編譯。
基準測試顯示簡單指令的牆鐘時間大幅下降;例如 zig build -h 從 150ms 降至 14.3ms(約 90% 的提升)。
LLVM 後端與 @bitCast 語意
Zig 更新了 LLVM 後端,以改善非 ABI 整數型別的降階方式。先前,任意位寬的整數會直接降為 LLVM IR 的 bit‑int 類型,常導致最佳化遺失或錯誤編譯。現在 Zig 會在將此類型存入記憶體時,將其零延伸或符號延伸至 ABI 大小的型別,行為與 Clang 處理 _BitInt(N) 的方式相同。
重新定義 @bitCast
為配合記憶體變更,Zig 重新定義了 @bitCast,使其基於型別的邏輯位佈局而非記憶體中的位元組重新解讀。
- 邏輯位佈局: 型別現在被視為有序的位序列(從最低位元到最高位元)。例如,
u5代表 5 個邏輯位;[2]u5代表 10 個邏輯位。 - 與位元序無關: 因為操作是邏輯性的,
@bitCast在所有目標平台上表現相同。將[2]u8轉型為u16時,第一個陣列元素始終成為最低 8 位,無論目標是大端序或小端序。
此變更亦讓編譯器的 Legalize 階段能將複雜的 @bitCast 重寫為更簡單的形式,適用於 LLVM 與 C 後端。
ELF 連結器與增量編譯
Zig 引入了全新的 ELF 連結器(透過 -fnew-linker 啟用),支援在 x86_64 Linux 上的快速增量編譯。此連結器允許在連結外部函式庫與 C 原始碼時進行增量重建,且不會產生額外的效能負擔,使某些重建時間低至 30ms。
SPIR‑V 後端進展
以下重大更新已合併至 SPIR‑V 後端:
- @SpirvType: 新增內建,用以表示 Zig 標準型別系統無法描述的 SPIR‑V 型別(例如 sampler 與 image)。
- 呼叫慣例: 執行模式資訊(工作群組大小等)現在由呼叫慣例攜帶(如
callconv(.spirv_kernel)),不再透過內嵌組合語言傳遞。 - 多執行緒產生碼: 產生碼現在產出
Mir值,並排入編譯器的執行緒池,擺脫單執行緒限制。 - 物件檔連結:
.spv檔案現在被視為物件檔,可將多個.zig檔或外部.spv物件連結成單一模組。
標準函式庫與 OS 整合
偏好 Windows 原生 API
Zig 正朝向優先使用原生 NT API 而非 Win32(kernel32.dll)封裝的方向前進。此舉旨在減少不必要的堆配置、避免冗餘的失敗模式,並消除膨脹。例如,Zig 現在直接使用 NtReadFile/NtWriteFile 取得隨機位元(entropy),繞過 kernel32.dll,從而在取消操作與資源管理上取得更佳整合與效能。
zig libc
Zig 正逐步以 Zig 標準函式庫的包裝器取代 libc 實作中販售的 C 原始碼檔案。此舉降低了對 C 語言的依賴,提升編譯速度與二進位大小。這些 libc 函式現在共享 Zig Compilation Unit(ZCU),允許類似連結時最佳化(LTO)的跨界優化。
事件式 I/O
std.Io.Evented 中已加入 io_uring(Linux)與 Grand Central Dispatch(GCD,macOS)的實驗性實作。這些實作使用使用者空間堆疊切換(fibers/green threads),讓 I/O 實作能在不改變應用程式邏輯的前提下輕鬆切換。
社群觀點
雖然這些架構變更普遍受到技術層面的讚賞,但仍有使用者對使用者體驗(UX)表達顧慮。一位貢獻者指出,將 @cImport 從編譯器移至建置系統是一種「開發理智優先於 UX」的取捨。
"Zig、Go 與 Python 的開發者常會說『我們把散熱器的冷卻液從油箱裡移除』,然後所有支持者都為此歡呼,說這對語言有好處,而我只是在想:他們一開始為什麼會把散熱器的冷卻液倒進油箱裡?"
摘要: Zig 已將所有套件管理功能從編譯器搬移至建置系統,從而加速建置、提升安全性,並為工具整合提供更彈性的架構。
標題: Zig 套件管理與建置系統重構