年關(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 這樣的版本工具,這樣一來,我們就可以去中心化,
其它
嗯,人生苦短,多了解一些有意思的系統吧,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/235514.html
標籤:其他
