這個問題在C/C++ 上不嚴重,主因C/C++的跟底層黏著度高,演化速度也慢,都是透過作業系統的套件更新。相對的我們可以看到無論python 的pip、Ruby的RubyGems、Golang 支援從github 取得project、NodeJS的npm,都是要建立一個統一的套件佈署管道,方便設計師開發。
今天要提的,就是Rust 的解決方案: Cargo,用來管理rust project,當然如果不用cargo,就算像之前的嵌入式系統一樣,直接寫一個rust檔案並用Makefile + rustc 編譯也是沒有問題的。
安裝好cargo使用cargo new即可生成一個新的rust project資料;跟先前提到的一樣,Cargo new 時即會生成一個git repository和它的.gitignore,方便套件版本控制。
project的資料會使用Cargo.toml這個檔案來管理,toml 是一款極簡的設定格式,相關文件格式可見:
https://github.com/toml-lang/toml
Cargo.toml 裡面會定義這個package 的資料:
[package]
name = "package name"
version = "0.1.0"
authors = ["author <author@xxxxx.com>"]
name = "package name"
version = "0.1.0"
authors = ["author <author@xxxxx.com>"]
Cargo 有一系列可用的指令,用cargo --help 就可以看到
build Compile the current project
clean Remove the target directory
doc Build this project's and its dependencies' documentation
new Create a new cargo project
run Build and execute src/main.rs
test Run the tests
bench Run the benchmarks
update Update dependencies listed in Cargo.lock
clean Remove the target directory
doc Build this project's and its dependencies' documentation
new Create a new cargo project
run Build and execute src/main.rs
test Run the tests
bench Run the benchmarks
update Update dependencies listed in Cargo.lock
一般最常用的組合,大概就是new, build, run三個基本指令,用來初始、編譯、執行,預設會用src/main.rs當作預設的編譯目標,並建構在target資料夾內,下面是其他的功能:
相依套件:
如果要用到其他的套件,把相依的套件名字填入Cargo.toml裡面:
[dependencies]
package “package version”
或package “package version”
[dependencies.package]
git = “url”
或git = “url”
[dependencies.package]
path = “path”
path = “path”
並在原始碼用extern指定它即可:
//main.rs
extern package
use package::{};
extern package
use package::{};
Cargo build 的時候會自動去檢查相依性套件,從它的git repository裡面簽出最新的master版本放到家目錄的.cargo 中,並用它進行建構;簽出的版本會寫進Cargo.lock,如果把Cargo.lock 傳給別人,他們就只之後就能用這個版本建構,如果要更新Cargo.lock 的話,就要用cargo update 來更新相依的套件,或用cargo update -p package指定更新某套件。
使用本地套件:
如果需要修相依套件裡面的bug,cargo 可以指定用本地的套件,而非簽出在.cargo 裡面的套件,只要在project 往上到根目錄的任一個地方,產生一個.cargo 的目錄,並在裡面建立config 檔,標示local project 的Cargo.toml 所在:paths = ['path to local project']
測試:
cargo test 會執行在src 跟tests 裡面的測試,也就是有#[test] attribute 的,算是一個不錯小工具。如果拿servo 當例子:
https://github.com/servo/servo/blob/master/components/servo/Cargo.toml
一開始先定義package:
[package]
name = "servo"
version = "0.0.1"
authors = ["The Servo Project Developers"]
name = "servo"
version = "0.0.1"
authors = ["The Servo Project Developers"]
servo要編出的library
[lib]
name = "servo"
path = "lib.rs"
crate-type = ["rlib"]
name = "servo"
path = "lib.rs"
crate-type = ["rlib"]
下面有一大排dependency,都是servo project 內的子專案,所以都是用相對路徑的方式來定義,而這些子專案的Cargo.toml內又會定義相依套件,例如外部相依大部分定義在util 裡面,這就會用git 的方式來引用:
[dependencies.azure]
git = "https://github.com/servo/rust-azure"
git = "https://github.com/servo/rust-azure"
有一次有寫到一個issue 就是要更動相依的rust-mozjs的套件,再更新servo 內Cargo.lock 檔,相關的更動可見:
https://github.com/servo/mozjs/pull/29
https://github.com/servo/servo/pull/4998
參考資料:
相關的cargo內容可見:http://doc.crates.io/guide.html
可取用的rust 的套件庫以在這裡找到:
https://crates.io/