不一樣的go語言-構建系統與構件系統


前言

  代碼的最后一步是構建成計算機可識別的二進制數據,然后才得以在計算機上運行。如果你曾經寫過有點規模(至少數十個以上獨立的源文件,且需要依賴第三方包)C語言項目,必定對C語言項目的構建過程印象深刻。或者當你曾經在linux系統中使用rpm命令安裝程序 時,系統一遍又一遍不厭其煩地提醒你缺少依賴時,不知那時的心情如何?前一個問題可歸屬於構建系統(Build Systems, Build Automation),后一個問題則屬於構件系統(artifact repository manager or binary repository manager)的范疇。而平常我們所說的“構建系統”往往代指構建系統與構件系統。也可以簡略地認為,構建系統是由程序與配置組成的,而構件系統是由軟件包與軟件元數據組成。

構建系統

  go語言的程序構建,基於go build命令,內置於官方發行版中。其天生正統,而不像java有ant、maven、gradle,python有pip。它的構建體系經歷過幾個階段,最早是依賴於GOPATH,其次是vendor(dep),再到后來就是go module(早期也叫vgo)。在具體介紹構建系統之前,按慣例先上示例代碼。

  示例代碼是一個mini的java項目結構(非maven、gradle結構),主要演示如果完全依賴於javac,如何做java項目構建。


├── com
|   └── eventer
|       ├── a
|           └── Person.java
|       └── Test.java
└── build
|       ├── com
|           └── eventer
|               ├── a
|                   └── Person.class
|               └── Test.class
package com.eventer;

import com.eventer.a.Person;

public class Test {
    public static void main(String[] args) {
        System.out.println(new Person());
    }
}
package com.eventer.a;

public clss Person() {
    
}

  以下是構建過程。

[eventer@localhost]# ls -a
total 0
drwxr-xr-x   4 eventer  eventer   128 Mar 26 22:34 .
drwxr-xr-x  38 eventer  eventer  1216 Mar 26 22:22 ..
drwxr-xr-x   3 eventer  eventer    96 Mar 26 22:34 build
drwxr-xr-x   3 eventer  eventer    96 Mar 26 22:23 com
[eventer@localhost]# javac -d build com/rfchina/test/*.java com/rfchina/test/a/*.java
[eventer@localhost]# cd build
[eventer@localhost]# java com/rfchina/test/Test

  從上述代碼可以看出,這僅僅是構建一個只有兩個類,且沒有第三方依賴的微型項目,javac命令的參數已經挺長。可想而知,當項目中有成千上百個類,幾十個依賴,再加上編譯選項、注解處理等等,javac的參數長度會有多長。而構建是隨時發生的,這樣的任務毫無疑問應該有一個工具來完成。我相信最早的時候這樣的工具非批處理腳本莫屬。在后來的日子里,隨着越來越多的需求加入到構建的各個階段,如編譯前、編譯時、構建前、構建后、測試階段、打包、發布等,甚至在開發階段也有很多需求產生,如代碼生成。所有這些后來都被構建系統所實現,從最早的ant,到后來一統天下的maven,到現在的gradle,越來越強大。

  再比如GNU構建系統經典的configure, make, make install三部曲,已經成為linux系統構建軟件的標准與習慣(即使不是GNU構建系統,很多軟件的構建也使用這三個過程)。

  現代的編程語言大多給出了自己專用的構建系統與構件系統,它們兩者已成為軟件開發團隊必不可少的工具。go語言自然也不能例外。

wikipedia對構建的定義

Build automation is the process of automating the creation

of a software build and the associated processes

including: compiling computer source code into binary code,

packaging binary code, and running automated tests.

  在《不一樣的go語言-gopher》一文中,“依賴管理”與“構建方式”兩節中已經講述過go語言關於構建的種種,在此不再贅述。也曾提到了當前go的構建系統在國內的種種不便及對策。正所謂合久必分,分久必合,在官方的支持下,go的構建系統日趨成熟,但目前獨獨一個好的構件系統,一個可以在本地搭建的構件系統。關於這一點,將在下一節中詳述。

  一個好的構建系統,應該具有以下特征。

  1. 自動解決依賴關系:包括直接依賴與間接依賴,如A依賴B,B依賴D,C依賴D,構建系統應自動引入A、B、C、D依賴,並去重。
  2. 增量&並行構建:增量構建是只對變更構建而跳過沒有變更的文件或任務;並行構建指各自獨立的任務可以並行執行。
  3. 測試:如單元測試、並行測試、性能測試、測試報告等。
  4. 錯誤提示:友好詳細的構建錯誤提示,豐富的調試或錯誤輸出參數控制。
  5. 自定義構建目標:比如自定義打包格式, exe, zip, etc。
  6. 基於配置&約定:約定優於配置,構建輸入輸出易配置。
  7. 可擴展:可自定義擴展,如maven與gradle的plugin機制
  8. 跨平台:構建系統本身需要具備跨平台的特性,或者能在交叉構建(在某個目標系統構建另一個目標系統的程序)
  9. 發布:支持發布程序包至私庫及各類不同協議的第三方倉庫。
  10. IDE集成:支持與各大主流IDE集成。

  顯然go的構建系統還不夠強大,開發人員還無法定制構建過程與結果。只有go build命令而沒有輔助go build命令的工具,在這一方面go依然任得道遠。

常見構建系統列表

語言 構建系統 說明
c/c++ gnu make, automake, nmake, cmake, qmake 各個make對應於不同時期,不同架構體系下的構建工具
java ant, maven, gradle 目前maven與gradle是主流, ant已經退出歷史舞台
python distribute, setuptools, easy_install, eggs, pip python的構建系統百家齊放,世界大戰般。不過pip最終贏得王座
nodejs npm -
javasript grunt, gulp, webpack 誰是王者?
go go build 嫡系
rust cargo 號稱最強大的構建系統, 超級大殺器。
ruby rubygem -
.net visual studio之nuget 最牛逼的IDE, 包羅萬有
swift&object-c xcode 最霸道的IDE

  除了上述列表的構建系統,現在已經有不少雲構建系統存在。比如google的Bazel,滴滴的建木。

  上面提到的大殺器cargo,它與其他語言的構建系統不同,其既是構建系統又是構件系統。cargo口號叫得那么響,除了其是官方出品之外,恐怕也只是為了與go一較高下。rust可能為程序 員考慮得更多,極力地想討好程序員。而在構建系統方面,對比一下go module與cargo,只怕go也是借鑒了不少cargo的東西。但與當代成熟的構建系統,比如gradle,並沒有高下立判之感。不同之處在於cargo在配置中使用rust語言本身來做擴展,而gradle則是使用自身的DSL語言來實現。相比這下,go在這一方面還需要快馬加鞭,總比在屁顛屁顛地跟在別人后面追好。

構件系統

  go語言的構件系統,官方默認是github。此外也可以是支持vgo下載協議的倉庫(如athens, goproxy.io),然后通過設置GOPROXY環境變量來設置構件系統代理,此舉可以完美解決國內下載依賴不暢的問題。而對於私庫,目前免費開源的只有athens,但是仍不夠完善。除此之外,jfrog的artifactory也支持go私庫,只不過要收費。

  私庫對於一個成熟、專業的開發團隊來說,是極其重要的一個工具。團隊內部會產生大量的公共程序包,對於go語言來說,如果沒有一個類似於maven的nexus倉庫,那么項目如何構建?如何持續集成?雖然必然會有各種巧妙地方案來解決或避開這些問題,但無疑是不得已而為之。現代編程體系發展至今天,沒有理由讓歷史倒退,走回批處理或者基礎設施(網絡)的老路來解決問題。有時候我真覺得王垠大俠對go的批判有道理,不吸取前人在編程語言設計上的經驗教訓,而一意孤行到底。盡管我不否認,寫go確實會比java舒服很多,java嚴謹地啰嗦,所以它只適合用來做大項目。

  鑒於此,go的官方團隊應該鼓勵社區去達成構件系統這事。而不應該像go module那樣,將社區招之即來,揮之即去,利用完了,就沒社區什么事了。

  那么構件系統,應該具有以下特征。

  1. 構件存儲:包括二進制包、源碼包、文檔
  2. 版本:支持release、snapshot,
  3. 元數據:設計良好的元數據的存儲機制
  4. 緩存:支持本地緩存
  5. 安全&權限:支持用戶、角色、權限模型;支持常用的用戶體系集成,如LDAP
  6. 倉庫管理:多語言,多倉庫,支持代理倉庫,遠程倉庫。

常見構件系統列表

構件系統 支持語言/系統 支持構建系統 說明
nexus java maven, gradle, npm 歷史悠久,流行的構件系統
jfrog java, go maven, gradle, go 后起之秀,有選擇的收費
proget .net vistual studio -
cargo rust cargo -
Cocoapods swift&object-c xcode -
Carthage swift&object-c xcode -
dpkg&apt Debian, Ubuntu - -
yum CentOS - -
homebrew Mac OS - -

請關注公眾號

不一樣的go語言


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM