1. 程式人生 > 實用技巧 >構建系統 IDE 和依賴管理

構建系統 IDE 和依賴管理

年關(annual review)將近,這一段時間,我在梳理 2020 年做的一些事情,並試著制定下一年的計劃。過程中,我發現我做的一些事情,或是工作相關,或是興趣上的探索,還都可以繼續總結出一些文章。在工作上,很多一部分做的事情就是程式語言的支撐體系。外加業餘時間裡,和同事一起花了一些時間在研究程式語言。在這幾部分的結合之下,我對於整個體系的端到端實現有一個整體的認識。

作為一個職業的程式設計師,在我們的職業生涯裡,不可避免地要學習一個又一個的程式語言。雖然多數情況下,我們對於使用什麼語言並沒有太多的選擇權。但是,當我們選擇一門語言時,都要考慮一系列的要素,比如:

  1. 構建系統

  2. IDE/Editor 支撐

  3. 依賴管理

  4. ……

PS:當然了,對於那些使用 C/C++ 的人來說,這些可能都是例外:他/她覺得自己不需要這些工具,需要的時候可以自己創造一個。所以,這些語言在很長的一段時間裡,都缺乏良好的依賴管理工具。

故事開始之前,讓我們讓 Android 使用的開發和構建來講述這個過程。

從 Android 應用的開發與構建說起

在移動端開發上,雖比不上這個行業的諸多大佬,但我也算是頗有經驗的。而恰好一年中有一半的時間,都在相關的專案上。所以,我從巨集觀上了解了整體的體系。

當我們開始一個新的移動應用時,會從 IDE 裡通過模板創造一個嶄新的應用,又或者是從某個地方(如 GitHub)尋找合適的模板。而後,為驗證模板的有效性,我們通過執行 Gradle 的相關命令,完成一個應用的過程,執行這個 Demo。(PS:這一點與我們使用 Java 開發應用時,並沒有太大區別)。

這個過程中,發生了這麼一些事情:

  1. IDE 通過某種通訊機制,與 Gradle 進行通訊,以執行對應的命令,如 build。

  2. Gradle 接收到 IDE 的指令後,解析 build.gradle 相關的內容,尋找是否存在對應的 Task,如這裡的 build。

  3. 執行 build 時,首先要去解決依賴關係,如從對應的 Maven 倉庫中下載依賴。

  4. 隨後,真正地執行對應的構建任務,如呼叫 javac。

這個過程看上去非常簡單,但是背後還藏著諸多的細節問題。

構建與依賴管理

當我用 CLOC 工具統計了一下 Gradle 工具的原始碼時,我才發現這個工具並不簡單。而進一步地,在半深入原始碼之後,我發現構建系統還是頗為複雜的。一個簡單的 Java 應用就分為這麼一些步驟:

  1. :compileJava UP-TO-DATE
  2. :processResources UP-TO-DATE
  3. :classes UP-TO-DATE
  4. :run

而當我們有依賴的時候,需要新增上classpath,即將依賴新增到編譯的路徑中。而對於一些非.jar型別的依賴而言,如.war,構建工具還要支援對他們的解析。因此,整體的過程就是:

  1. 判斷是否存在本地的依賴,如果沒有的話,從遠端獲取。如果有依賴衝突的話,解決這些衝突,或者報錯。

  2. 獲取依賴後,根據需要對依賴進行處理。如 Android 中的 aar 包的解壓等。

  3. 結合依賴,對原始碼進行編譯

  4. 將所需要的 Java Resources 從依賴的 Jar 拷貝到指定目錄

  5. 打包構建後的產物到一個新的 jar 包中

這些只是表面上的一些工作。而為了更好地表述這個過程,需要抽象出一個task的概念,在這個概念裡,一個 task 有輸入和輸出。如

  1. 解析依賴裡。它的輸出是 build.gradle 檔案,輸出是處理完的依賴路徑。

  2. 編譯任務裡。它的輸入是原始碼,輸出是 .class 檔案。

  3. 打包任務裡。它的輸入是一堆資料夾或者檔案,輸出是一個 .jar 包。

  4. ……

於是,在有了這些基礎之後,為了加快構建,還需要快取的機制。它對輸入和輸出進行計算,當兩者發生變化的時候,再進行編譯。否則就跳過這個任務。

而這些只是核心功能,在非核心的功能區裡,還有諸如於 SDK 版本、多輸入多輸出的變體等等。

IDE 與構建系統

在那篇《程式語言的 IDE 支援》中,我們已經介紹了程式語言所需要的 IDE 功能,諸如於:

  1. 語法高亮

  2. 子系統關聯與整合

  3. 跳轉與引用分析

  4. 智慧感知

  5. 重構

  6. 快速修復

  7. 結構化檢視

  8. ……

在這篇文章中,大概再回顧一下它與構建系統之間的關係。IDE 與構建系統一般會存在這種關聯:

  1. 解析構建系統中的任務。如 Gradle 提供的 task,又或者是 package.json 中的 scripts,並將它們顯式地展示出來,如 IDEA 中的 line marker,又或者是獨立的 Gradle pannel。

  2. 執行構建任務。即在 IDE 中的 UI 與構建命令相繫結,典型的如 IDEA 中的 Android 應用的構建。

  3. 動態修改構建系統(可選)。如 IDEA 中的更新依賴版本,它依賴於解析構建系統的 DSL,並更新對應的 DSL。

對應的有兩種機制可以與構建系統通訊:

  1. 由構建系統提供構建 API。如 Gradle Tooling API,在那篇《Gradle IDEA 的專案模型》中,我們實際上介紹了由構建系統主動向 IDE 提供模型的方式。

  2. 由 IDE 構造一遍構建系統。如 IDEA 對於 Node.js 的處理方式。

簡單來說,就是複雜的系統應該由構建系統提供機制,而簡單的構建系統則就不會有這樣的問題。

依賴管理的基礎設施

不同語言對於依賴的管理機制都有所不同,但是它們的原理都是相似的:

  1. 原始碼包。即將原始碼打包,並以特定的格式釋出,適用於指令碼語言

  2. 倉庫源。方式類似於原始碼包,唯一不同的地方是藉助於版本管理工具,如 Golang。

  3. 類二進位制包。典型的是 Java

  4. 其它包。如 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