vatt'ghern jaskier's ballads

Modular 把 Mojo 標準函式庫交給外部貢獻者是 2024 年的事,8 月 18 日這天,編譯器本體終於也放上了 GitHub,授權 Apache 2.0 加 LLVM exceptions。官方原文卻寫著:「we aren't ready to take contributions to the compiler and tooling.」

編譯器最後一塊也開源了

放原始碼這件事,Modular 過去兩年沒有一次做到位——先是標準函式庫,再是用 Mojo 寫成的 kernel 程式碼,一直到 8 月 18 日,編譯器本體才跟著上桌。三步之間隔了大約兩年(stdlib 開放的確切月份文章未給,這裡是概算),中間還夾著一次語言本身滿 1.0 的里程碑。這篇按時間順序把整段過程攤開,順便看官方自己怎麼劃「原始碼公開」跟「外部貢獻開放」這兩件事之間的界線——這條界線,到今天都還沒完全打開。三個階段各自對應不同的風險層級,讀起來像是一次刻意放慢的釋出計畫,不是臨時起意的公關動作。

2024 年那道小縫——標準函式庫先開了

Modular 開放原始碼真正的起點在 2024 年。當時 Mojo 標準函式庫開始接受外部貢獻,官方部落格用一句話交代這段起點:「The Mojo standard library has been accepting contributions since 2024.」stdlib 是寫 Mojo 程式時最常碰到的一層——collections、字串處理、記憶體管理的介面都在這裡。先開放這一層,風險相對可控:外部貢獻者能改的是「語言之上」的程式碼,碰不到編譯器怎麼把 .mojo 檔轉成機器碼這件事。

這個先後順序背後的理由不難理解。函式庫程式碼出錯,影響範圍是呼叫它的那段程式;編譯器程式碼出錯,影響的是所有用這個編譯器生出來的程式,正確性跟相容性的壓力完全不是同一個量級。一般而言,開放編譯器本體要承擔的審查成本、CI 覆蓋率要求,都比開放一個函式庫高出一截——這不是這篇文章的說法,而是「外部貢獻編譯器」這件事本身常見的特徵。從這個角度看,Modular 把 stdlib 放在最前面,選的是風險最低的起點。

開放原始碼的先後順序,在其他大型編譯器專案裡也看得到類似的影子。LLVM 本身、或者 Rust 的 rustc,在正式對外開放編譯器核心貢獻之前,通常都要先把程式碼審查分工、CI 覆蓋率、RFC 討論流程這些治理機制搭起來——這不是這篇文章討論的內容,是拿同類專案的常見做法做個類比,用來說明「原始碼公開」跟「貢獻開放」之間為什麼常常隔著一段時間,不是 Modular 特有的拖延。

兩年之間,stdlib 的開放狀態沒有變過,一路延續到編譯器開源的這一天。「先開周邊、後開核心」這個節奏,接下來兩步都在重複——差別只在於「周邊」跟「核心」的定義,一次比一次更靠近編譯器本身。下面這張圖把三層原始碼公開的時間點跟貢獻開放的時間點放在一起,點開任一列可以看到該層目前的原文說法。

點選任一列查看該層的官方原文與現況 · 3 層 × 3 個時間點

2024 stdlib 開放貢獻 近期 kernel 程式碼釋出 2026-08-18 編譯器與工具鏈公開 標準函式庫 Kernel 程式碼 編譯器與工具鏈

「The Mojo standard library has been accepting contributions since 2024.」

2024 年起持續接受外部貢獻,是整個開放歷程裡持續時間最長、也是唯一從一開始就同時公開原始碼、開放貢獻的一層。

「released hundreds of thousands of lines of kernel code written in Mojo.」

原始碼公開,但文章沒有提到外部貢獻是否開放。這批程式碼證明的是 Mojo 能寫出什麼規模的東西,不是語言本身怎麼被編譯。

「we aren't ready to take contributions to the compiler and tooling. We aim to accept contributions to the compiler and tooling by the end of this year.」

2026 年 8 月 18 日原始碼公開,但 pull request 目前送不進編譯器本體,官方給的只有一個意向:今年底前開放。

空心虛線圓=原始碼尚未公開;淡色實心圓=原始碼已公開,文章沒有確認外部貢獻是否開放;深綠實心圓=原始碼公開且持續接受外部貢獻。資料整理自 Modular 官方部落格(2026-08-18 發布)。

編譯器亮相前,先攤開的是數十萬行 kernel 程式碼

開放 stdlib 之後的下一步不是編譯器,是 kernel 程式碼。部落格的原話是:「released hundreds of thousands of lines of kernel code written in Mojo.」這批程式碼用 Mojo 寫成,規模是數十萬行等級,比 stdlib 大得多,但性質上仍然是「用這個語言寫出來的東西」,不是「這個語言本身怎麼運作」。

差別在這裡:kernel 程式碼開放,讀者看到的是 Mojo 能寫出什麼;編譯器開放,讀者才能看到 Mojo 怎麼被編譯成能跑的東西。前者證明語言好用,後者才讓外部人真正檢查語言的實作細節。Modular 把這兩件事分成兩步做,沒有一次倒出來。

數十萬行這個量級,擺在同類語言的開源歷程裡不算小。文章沒有說這些 kernel 是否真的跑在 Modular 內部的正式環境裡;合理的推測是,寫得出這個量級的程式碼,通常代表作者已經拿 Mojo 用過一段時間,不是只寫了幾個範例程式就對外公布——但這只是推測,文章本身沒有給出使用場景的細節。

值得記下的是,即使到了編譯器原始碼公開的這一天,kernel 這條線也還沒完全打通。部落格裡有一句提醒:「Note that a prebuilt Mojo compiler is still necessary today if you are customizing MAX kernels or models.」也就是說,如果要客製化 MAX 的 kernel 或 model,目前仍然得靠官方預先建置好的編譯器,自己從原始碼編出來的那份還不夠用。原始碼公開跟「原始碼公開到可以完全取代官方 build」之間,還有一段距離沒有填平。

MAX 是 Modular 的推論平台(文章本身未定義這個名詞),kernel 通常是跑在 GPU 或加速器上、對效能最敏感的那一小段程式碼。文章沒有進一步說明 MAX kernel 跟這次公開的編譯器原始碼之間的關係,只給了一句現況提醒——這代表要判斷這次開源對正在用 MAX 的人有多大實際幫助,目前能依賴的材料還很有限。

上週先讓語言站穩,這週交出整個編譯器

8 月 18 日公告的前一週,Mojo 剛滿 1.0。官方原文寫的是:「Last week Mojo hit 1.0 (with source stability).」文章只用「source stability」這五個字帶過,沒有進一步定義;合理的推測是,這代表語言的語法與相容性承諾從那一刻開始固定下來,不會再因為版本更新讓既有程式碼失去相容性。順著這個推測往下想,開放編譯器原始碼之前先把「這個語言長什麼樣」釘死,順序也就不像是巧合——如果編譯器先開放而語言規格還在變動,外部貢獻者要追的目標會一直移動,PR 才剛送出,語法可能已經變了。

對已經在用 Mojo 的團隊來說,source stability 具體的意思是:現有程式碼不會因為官方升級語言版本而突然編譯失敗,這是團隊敢把 Mojo 用進正式環境的前提之一。反過來說,這個承諾也限制了語言本身接下來能做的改動幅度——語法一旦公開承諾穩定,往後想動的空間就變窄了,這是穩定性換來的代價,文章沒有明講,但屬於「source stability」這個詞本身帶的含義。

8 月 18 日這天,Modular 在部落格開頭就把話講白:「We are happy to announce that the Mojo🔥 language is now fully open source under the Apache 2.0 license (with LLVM exceptions)!」緊接著把範圍講清楚:編譯器、工具鏈跟建置這個語言需要的所有東西,全部放進同一個 GitHub repository。授權選的是 Apache 2.0 加 LLVM exceptions——這個附加條款通常只出現在跟 LLVM 綁定的專案上,合理的推測是 Mojo 編譯器本身建立在 LLVM 之上,文章沒有直接寫明這一點,但授權名稱本身就是線索。下面這個詞條把授權跟 repo 的原文說法放在一起。

這篇公告掛名是 Modular Team,不是某一位工程師的個人網誌,用詞上也偏正式公告,不是工程部落格常見的第一人稱敘事。這個細節不影響內容本身,但說明這是一則經過團隊審過的正式聲明,不是某人自己在部落格上先講了再說。

hover 或點選底線詞查看官方原文 · 2 個詞

Modular 把授權選在 Apache 2.0 加 LLVM exceptions,原始碼統一放進 modular 這個 GitHub repository——同一個 repo 裡同時裝著編譯器、工具鏈,跟建置整個語言所需要的其他東西。

「the gold standard for programming languages and compilers, because it provides great flexibility to be used in all sorts of applications.」——Modular 對這個授權組合的形容。 「The source code for the Mojo compiler, tooling, and everything else you need to build the language are now available in our modular GitHub repository.」

把編譯器、工具鏈、stdlib、kernel 全部收進同一個 repo,也代表以後追蹤一個 issue 或一次改動的影響範圍,不用再跨好幾個獨立倉庫拼湊上下文——這對外部貢獻者理解一個改動牽動了什麼,是實際的方便,不是形式上的整併。

編譯器在整個 Mojo 技術棧裡的位置,也可以直接畫出來看。下面這疊由上而下分別是使用者程式碼、標準函式庫、編譯器與工具鏈、還有底層的 LLVM——編譯器這一層剛好卡在兩塊早就開放的東西中間,是最後被打開的一塊。

應用程式碼你寫的 .mojo 檔
標準函式庫 stdlib2024 年起開放貢獻
編譯器與工具鏈2026-08-18 原始碼公開,貢獻尚未開放
LLVM 後端授權含 LLVM exceptions,推測建立於其上
由上而下:使用者寫的 .mojo 程式碼、標準函式庫(2024 年起開放貢獻)、編譯器與工具鏈(2026-08-18 原始碼公開,強調框標示,貢獻尚未開放)、LLVM 後端。最後一層的定位是推論——文章沒有直接說明編譯器建立在 LLVM 之上,這個推測來自授權名稱裡的「LLVM exceptions」字樣,不是官方明講的架構描述。

Bazel 把編譯器、stdlib、kernel 綁進同一張建置圖

建置路徑走 Bazel,而且區分了兩種用法。只是想用 Mojo、不打算碰編譯器本身的人,官方建議直接吃 prebuilt 二進位:「If you aren't working on the compiler itself, you can use the flag --config=prebuilt-mojo and the build system will download the latest nightly binary distribution of the compiler, saving you some compilation time.」真正要動編譯器或函式庫程式碼的人,才需要從原始碼整套編出來:

./bazelw run --config=build-mojo KGEN:mojo -- run hello.mojo

改完程式碼要驗證有沒有破壞既有行為,同一套工具鏈也能跑測試:

./bazelw test --config=build-mojo mojo/stdlib/test/...

選 Bazel 的理由文章沒有明講,這裡是合理的推測:編譯器、stdlib、kernel 程式碼放在同一個 repo 裡,語言是混合的——編譯器本體多半是 C++/MLIR,stdlib 跟 kernel 是 Mojo,測試腳本可能還牽涉 Python。這種多語言、多元件互相依賴的建置圖,正是 Bazel 這類 hermetic build 系統設計來處理的問題:每個 target 的依賴顯式宣告,同一份原始碼在任何一台機器上編出來的結果理論上位元組對位元組相同,重新編譯只需要重跑真正變動過的那一小塊。對一個今天才第一次讓外部人自己編的編譯器 repo 來說,這個特性比什麼都重要——沒有 hermetic 建置,外部貢獻者自己編出來的東西,跟 Modular 內部 CI 編出來的東西未必一致,「這個改動有沒有效」這第一步就會失去意義。

對一個剛開放原始碼的編譯器來說,「其他人在自己機器上編不出來」是最常見、也最傷士氣的第一手經驗。Bazel 的 hermetic 特性把這個風險降到最低——只要跟官方用同一個 bazelw 版本、同一份鎖定的依賴清單,理論上每個人編出來的東西都該長得一樣,不會出現「我這邊過了,你那邊過不了」這種各自環境不同造成的爭議。Bazel 另一個常被提到的特性是遠端快取:同一個 target 只要輸入沒變,編譯結果可以直接從快取裡拿,不用重編。對一個從今天才開始有外部貢獻者的 repo 來說,這代表大部分人日常改動只會牽動整個建置圖裡很小一塊,不必每次都從零開始等一顆完整的編譯器編完,這也是為什麼官方特別把 prebuilt-mojo 這個選項獨立講一遍——不是每個人都需要,也不是每個人都負擔得起,從零建置一整顆編譯器的時間成本。

測試套件本身也是一種文件。外部貢獻者不需要另外去問「這個函式應該長什麼行為」,跑一次 mojo/stdlib/test 底下的既有測試,多半就能看出邊界案例官方在意哪些。對一個原始碼剛公開、還沒看到完整貢獻指南的 repo 來說,這是目前少數可以直接拿來當參考的材料。對貢獻窗口還沒開的現況來說,這套建置系統反而先幫外部人練好手——等年底貢獻真的開放,大家已經很熟悉怎麼從原始碼編、怎麼跑測試,不用在流程本身上重新摸索。

這幾行指令合起來的意思是:編譯器不再是一個下載安裝的黑盒。任何人都能拿到跟 Modular 內部一樣的原始碼、用一樣的工具鏈編出同一顆編譯器,改完也能用官方自己在用的測試套件驗證,只是改完的東西目前還沒有地方可以送。

原始碼在,貢獻權還沒開

原始碼放出來,不代表外部人可以把 pull request 送進編譯器本體。Modular 把這條線劃得很清楚:「we aren't ready to take contributions to the compiler and tooling.」緊接著給的是承諾,不是保證:「We aim to accept contributions to the compiler and tooling by the end of this year.」用詞是「aim to」,是意向,不是寫死的截止日期——文章沒有給具體月份,讀者能確定的只有兩件事同時成立:原始碼公開,貢獻窗口還沒打開。

一般來說,開放編譯器貢獻窗口,除了審查流程,還需要處理法律層面的東西,例如貢獻者授權合約(CLA)確認外部提交的程式碼版權沒有爭議,以及決定哪些人有權限直接合併程式碼(code owners)。這些機制文章完全沒有提到,是不是已經在準備,讀者只能等年底前的下一則公告才知道。

這個限制本身合理。一套編譯器要接受外部 PR,得先有審查流程、有人力去看每一個改動會不會影響既有程式碼的產出結果、還得決定哪些改動屬於可以合併的範圍——這些機制通常不是原始碼公開那一刻就自動存在,是之後要另外搭建的。stdlib 花了兩年時間磨這套流程,編譯器要走完同樣的路,時間表本來就不會跟原始碼公開同一天。

文章沒有解釋為什麼選在這個時間點開放編譯器——是競爭壓力、社群要求,還是單純內部準備好了,官方沒有交代動機,只交代了時間軸跟做法。這篇報導能確定的只有「發生了什麼」跟「官方自己怎麼形容範圍」,動機留白。如果真要找對照,比較合理的參考點是同類語言過去怎麼走這條路,而不是去猜 Modular 內部的決策過程。

部落格本身沒有提到 CUDA 或任何競爭生態系統的字眼,接下來這段對照是額外的推論。合理的推測是:AI 基礎設施這幾年真正稀缺的不是「能寫 kernel 的語言」,而是「能被外部檢查、甚至修改的編譯器」——長期以來,主流 GPU 生態的核心工具鏈不對外開放原始碼,開發者只能對著黑盒寫程式、對著黑盒除錯。Mojo 編譯器原始碼公開,即使貢獻權還沒打開,至少讓「這段程式碼為什麼被這樣編譯」這件事變得可以檢查、可以自己編出來驗證。這個意義能不能真正兌現,要看貢獻窗口是不是真的在年底前打開。

對寫 kernel 的人來說,最直接的改變是可以真的翻開編譯器,看某段 Mojo 語法最後被轉譯成什麼樣的中間表示,而不是靠猜或靠試錯反推。過去這一步只能透過觀察編譯結果、看效能數字去反推編譯器在做什麼;現在可以直接讀最佳化 pass 的原始碼,省下的是一整輪嘗試錯誤的時間。

對已經在貢獻 stdlib 的人來說,這次公開也有實際好處:以前寫一個型別或一個方法,只能從行為推測編譯器怎麼處理它,現在可以直接對照編譯器原始碼,搞懂自己寫的 API 最後被編譯器怎麼展開、有沒有踩到隱藏的效能陷阱。這種「寫東西的人也能看懂底層」的狀態,兩年前 stdlib 剛開放貢獻的時候還不存在。

把三層的「原始碼公開」跟「外部貢獻開放」分開列出來,才看得出來這條界線目前實際劃在哪裡:

原始碼公開 外部貢獻
標準函式庫 stdlib 2024 年起 開放,自 2024 年起持續至今
Kernel 程式碼 已公開(原文未給確切月份) 文章未提及外部貢獻是否開放
編譯器本體 2026-08-18 尚未開放,官方目標「今年底前」
三層各自的「原始碼公開」與「外部貢獻開放」現況,取自公告原文與官方部落格用詞。

後續觀察:Modular 給的時間點是「今年底前」開放編譯器貢獻,沒有月份、沒有里程碑清單,只有這一句話。stdlib 用兩年時間證明「先開周邊、再開核心」這個節奏走得通,編譯器這一步能不能在年底前真正打開貢獻窗口,是接下來唯一還沒兌現的承諾。在那之前,這個 repo 對外部工程師來說,性質更接近一份可以逐行讀的參考實作,而不是一個真正開放的協作專案。