構建系統 IDE 和依賴管理
年關(annual review)將近,這一段時間,我在梳理 2020 年做的一些事情,並試著制定下一年的計劃。過程中,我發現我做的一些事情,或是工作相關,或是興趣上的探索,還都可以繼續總結出一些文章。在工作上,很多一部分做的事情就是程式語言的支撐體系。外加業餘時間裡,和同事一起花了一些時間在研究程式語言。在這幾部分的結合之下,我對於整個體系的端到端實現有一個整體的認識。
作為一個職業的程式設計師,在我們的職業生涯裡,不可避免地要學習一個又一個的程式語言。雖然多數情況下,我們對於使用什麼語言並沒有太多的選擇權。但是,當我們選擇一門語言時,都要考慮一系列的要素,比如:
-
構建系統
-
IDE/Editor 支撐
-
依賴管理
-
……
PS:當然了,對於那些使用 C/C++ 的人來說,這些可能都是例外:他/她覺得自己不需要這些工具,需要的時候可以自己創造一個。所以,這些語言在很長的一段時間裡,都缺乏良好的依賴管理工具。
故事開始之前,讓我們讓 Android 使用的開發和構建來講述這個過程。
從 Android 應用的開發與構建說起
在移動端開發上,雖比不上這個行業的諸多大佬,但我也算是頗有經驗的。而恰好一年中有一半的時間,都在相關的專案上。所以,我從巨集觀上了解了整體的體系。
當我們開始一個新的移動應用時,會從 IDE 裡通過模板創造一個嶄新的應用,又或者是從某個地方(如 GitHub)尋找合適的模板。而後,為驗證模板的有效性,我們通過執行 Gradle 的相關命令,完成一個應用的過程,執行這個 Demo。(PS:這一點與我們使用 Java 開發應用時,並沒有太大區別)。
這個過程中,發生了這麼一些事情:
-
IDE 通過某種通訊機制,與 Gradle 進行通訊,以執行對應的命令,如 build。
-
Gradle 接收到 IDE 的指令後,解析 build.gradle 相關的內容,尋找是否存在對應的 Task,如這裡的 build。
-
執行 build 時,首先要去解決依賴關係,如從對應的 Maven 倉庫中下載依賴。
-
隨後,真正地執行對應的構建任務,如呼叫 javac。
這個過程看上去非常簡單,但是背後還藏著諸多的細節問題。
構建與依賴管理
當我用 CLOC 工具統計了一下 Gradle 工具的原始碼時,我才發現這個工具並不簡單。而進一步地,在半深入原始碼之後,我發現構建系統還是頗為複雜的。一個簡單的 Java 應用就分為這麼一些步驟:
- :compileJava UP-TO-DATE
- :processResources UP-TO-DATE
- :classes UP-TO-DATE
- :run
而當我們有依賴的時候,需要新增上classpath
,即將依賴新增到編譯的路徑中。而對於一些非.jar
型別的依賴而言,如.war
,構建工具還要支援對他們的解析。因此,整體的過程就是:
-
判斷是否存在本地的依賴,如果沒有的話,從遠端獲取。如果有依賴衝突的話,解決這些衝突,或者報錯。
-
獲取依賴後,根據需要對依賴進行處理。如 Android 中的 aar 包的解壓等。
-
結合依賴,對原始碼進行編譯
-
將所需要的 Java Resources 從依賴的 Jar 拷貝到指定目錄
-
打包構建後的產物到一個新的 jar 包中
這些只是表面上的一些工作。而為了更好地表述這個過程,需要抽象出一個task
的概念,在這個概念裡,一個 task 有輸入和輸出。如
-
解析依賴裡。它的輸出是 build.gradle 檔案,輸出是處理完的依賴路徑。
-
編譯任務裡。它的輸入是原始碼,輸出是 .class 檔案。
-
打包任務裡。它的輸入是一堆資料夾或者檔案,輸出是一個 .jar 包。
-
……
於是,在有了這些基礎之後,為了加快構建,還需要快取的機制。它對輸入和輸出進行計算,當兩者發生變化的時候,再進行編譯。否則就跳過這個任務。
而這些只是核心功能,在非核心的功能區裡,還有諸如於 SDK 版本、多輸入多輸出的變體等等。
IDE 與構建系統
在那篇《程式語言的 IDE 支援》中,我們已經介紹了程式語言所需要的 IDE 功能,諸如於:
-
語法高亮
-
子系統關聯與整合
-
跳轉與引用分析
-
智慧感知
-
重構
-
快速修復
-
結構化檢視
-
……
在這篇文章中,大概再回顧一下它與構建系統之間的關係。IDE 與構建系統一般會存在這種關聯:
-
解析構建系統中的任務。如 Gradle 提供的 task,又或者是 package.json 中的 scripts,並將它們顯式地展示出來,如 IDEA 中的 line marker,又或者是獨立的 Gradle pannel。
-
執行構建任務。即在 IDE 中的 UI 與構建命令相繫結,典型的如 IDEA 中的 Android 應用的構建。
-
動態修改構建系統(可選)。如 IDEA 中的更新依賴版本,它依賴於解析構建系統的 DSL,並更新對應的 DSL。
對應的有兩種機制可以與構建系統通訊:
-
由構建系統提供構建 API。如 Gradle Tooling API,在那篇《Gradle IDEA 的專案模型》中,我們實際上介紹了由構建系統主動向 IDE 提供模型的方式。
-
由 IDE 構造一遍構建系統。如 IDEA 對於 Node.js 的處理方式。
簡單來說,就是複雜的系統應該由構建系統提供機制,而簡單的構建系統則就不會有這樣的問題。
依賴管理的基礎設施
不同語言對於依賴的管理機制都有所不同,但是它們的原理都是相似的:
-
原始碼包。即將原始碼打包,並以特定的格式釋出,適用於指令碼語言
-
倉庫源。方式類似於原始碼包,唯一不同的地方是藉助於版本管理工具,如 Golang。
-
類二進位制包。典型的是 Java
-
其它包。如 Maven 可以支援其它自制的包
最有意思的是Maven 的機制,我可以自制依賴,並上傳上去。而整個倉庫並不關心這個包的內容,我們只需要依賴於它定義的格式即可。如果我們考慮圍繞語言來設計依賴管理體系,那麼可以考慮的是類似的方式,並藉助於 Git 這樣的版本工具。這樣一來,我們就可以去中心化。
其它
嗯,人生苦短,多瞭解一些有意思的系統吧。
參考連線:
http://groups.tianya.cn/post-1452-e8a86c47f6734e2cbf18c0c9d5ab7ba0-1.shtml
http://groups.tianya.cn/post-1452-55df39a7b2da49508919eee3aa17b2c3-1.shtml
http://groups.tianya.cn/post-1452-3590ccc9f4f34bfd94a184e94388f48e-1.shtml
http://groups.tianya.cn/post-1452-82364f4c5ba9411dbc50dfc4c6c66d18-1.shtml
http://groups.tianya.cn/post-1452-62c52c538d4e413a971fccbd65e3a171-1.shtml
http://groups.tianya.cn/post-1452-062e3e435b9c4ec99b6bd4782697c653-1.shtml
http://groups.tianya.cn/post-1452-9d18a6d6583f4beda48ad7b1691c90d9-1.shtml
http://groups.tianya.cn/post-1452-8e8b18d0537d4209b092c21d3b0ac4d2-1.shtml
http://groups.tianya.cn/post-1452-990e089b07ae4204a3d56214196bc65f-1.shtml
http://groups.tianya.cn/post-1452-8d5fa8ebed3b485798779c1bb07d0a55-1.shtml
http://groups.tianya.cn/post-1452-e0fe751d08494d658484b73607a41a98-1.shtml
http://groups.tianya.cn/post-1452-8bc5ad1dc7c844fa884f4c380b4e32e7-1.shtml
http://groups.tianya.cn/post-1452-dfda1cbf117649269dcfb2862b9ae3c3-1.shtml
http://groups.tianya.cn/post-1452-747dc5304f6d43d3a10333e635beeed6-1.shtml
http://groups.tianya.cn/post-1452-55fd6ae183fa4c9b991f66c28af6f355-1.shtml
http://groups.tianya.cn/post-1452-454dfbfedfb145949aa77f2bf77b867b-1.shtml
http://groups.tianya.cn/post-1452-0a2487fb2f554b2e857f066e1feb4df1-1.shtml
http://groups.tianya.cn/post-1452-daa851ddfff44dfaaac340d3b57dbf7f-1.shtml
http://groups.tianya.cn/post-1452-27f927c6f0f442b1b0ef866bdf5db945-1.shtml
http://groups.tianya.cn/post-1452-41ce5c4814f948e197c8e49ac7bd96eb-1.shtml
http://groups.tianya.cn/post-1452-095cab01910b4081afe72a72d6d3b8c5-1.shtml
http://groups.tianya.cn/post-1452-32d4e873336246058237f2c7aac94155-1.shtml
http://groups.tianya.cn/post-1452-471991c47cc5407da364300d0e021ba1-1.shtml
http://groups.tianya.cn/post-1452-9b0fef382e4842c9b52ba3a6ae889778-1.shtml