Cargo-raze 目前是一個未維護且不受支援的產品。
rules_rust
中的crate_universe
是一個具有類似目標的支援和維護的產品。
我們相信crate_universe
支援cargo-raze支援的所有功能。我們鼓勵您嘗試遷移到它。如果您發現缺少支援或錯誤,請針對rules_rust
提出問題或 PR。
cargo-raze
已被存檔,以反映針對其提交的 PR 和問題不太可能解決的現實。
如果您有興趣接管該專案的維護,請聯絡 Bazel Slack 中的#rust。
一個實驗性的支援 Cargo 插件,用於將工作區層級的 Cargo.toml 提煉為使用 Rules_rust 的程式碼可以直接依賴的 BUILD 目標。
這不是谷歌的官方產品(實驗性的或其他的),它只是碰巧歸谷歌所有的程式碼。
該專案綜合了 Cargo 的依賴解析邏輯和一些功能(例如特性)並將腳本建置為可執行規則,Bazel 可以執行這些規則來編譯 Rust 箱。儘管標準的rules_rust規則可用於從頭開始編譯Rust程式碼,但依賴關係生態系統的細粒度使得基於該生態系統轉換依賴關係樹變得繁重,即使對於依賴關係很少的程式碼也是如此。
Cargo-raze 可以透過以下兩種模式之一產生可建構的目標:Vendoring 或 Non-Vendoring。在供應模式下,開發人員使用通用的cargo vendor
子命令將其工作區Cargo.toml指示的依賴項檢索到cargo-raze然後用BUILD檔案填充的目錄中。在非供應模式下,cargo-raze 會產生 BUILD 檔案的平面列表,以及可以在 WORKSPACE 檔案中呼叫的工作區級宏,以與 Cargo 本身類似的方式自動拉取依賴項。
在這兩種情況下,第一步都是決定將 Cargo 依賴項放置在工作區中的位置。這個函式庫的設計考慮到了 monorepos,組織決定每個人都指向的一組依賴項。其目的是讓依賴項中的利害關係人協作以原子方式升級依賴項,並同時修復其程式碼庫中的損壞。如果這不可行,仍然可以在去中心化場景中使用cargo-raze,但這種解耦的儲存庫不太可能與目前的實作很好地互動。
無論選擇哪種方法,都應將 rust_rules 引入工作空間。這是一個例子:
load ( "@bazel_tools//tools/build_defs/repo:http.bzl" , "http_archive" )
http_archive (
name = "rules_rust" ,
sha256 = "accb5a89cbe63d55dcdae85938e56ff3aa56f21eb847ed826a28a83db8500ae6" ,
strip_prefix = "rules_rust-9aa49569b2b0dacecc51c05cee52708b7255bd98" ,
urls = [
# Main branch as of 2021-02-19
"https://github.com/bazelbuild/rules_rust/archive/9aa49569b2b0dacecc51c05cee52708b7255bd98.tar.gz" ,
],
)
load ( "@rules_rust//rust:repositories.bzl" , "rust_repositories" )
rust_repositories ( edition = "2018" )
對於僅限 Bazel 的項目,使用者應先產生包含感興趣的依賴項的標準 Cargo.toml。請注意包含[lib]
指令,以便 Cargo 不會抱怨缺少此模擬板條箱的來源檔案。這是一個例子:
[ package ]
name = " compile_with_bazel "
version = " 0.0.0 "
# Mandatory (or Cargo tooling is unhappy)
[ lib ]
path = " fake_lib.rs "
[ dependencies ]
log = " =0.3.6 "
標準 Cargo.toml 就位後,請在下一節中加入[package.metadata.raze]
指令。
幾乎所有規範的貨物設定都應該能夠在cargo-raze
中正常運作。假設 Cargo 工作區現在嵌套在 Bazel 工作區下,使用者只需將 RazeSettings 新增至 Cargo.toml 檔案即可用於產生 Bazel 文件
# Above this line should be the contents of your Cargo.toml file
[ package . metadata . raze ]
# The path at which to write output files.
#
# `cargo raze` will generate Bazel-compatible BUILD files into this path.
# This can either be a relative path (e.g. "foo/bar"), relative to this
# Cargo.toml file; or relative to the Bazel workspace root (e.g. "//foo/bar").
workspace_path = " //cargo "
# This causes aliases for dependencies to be rendered in the BUILD
# file located next to this `Cargo.toml` file.
package_aliases_dir = " . "
# The set of targets to generate BUILD rules for.
targets = [
" x86_64-apple-darwin " ,
" x86_64-pc-windows-msvc " ,
" x86_64-unknown-linux-gnu " ,
]
# The two acceptable options are "Remote" and "Vendored" which
# is used to indicate whether the user is using a non-vendored or
# vendored set of dependencies.
genmode = " Remote "
在使用 Cargo 工作區的專案中,使用者應將所有raze
設定組織到包含[workspace]
定義的頂級Cargo.toml
檔案中的 [ [workspace.metadata.raze]
欄位中。這些設定應該與上一節中的[package.metadata.raze]
中看到的設定相同。但是,板條箱設定仍可以放置在工作區成員的Cargo.toml
檔案中:
# Above this line should be the contents of your package's Cargo.toml file
# Note that `some-dependency` is the name of an example dependency and
# `<0.3.0` is a semver version for the dependency crate's version. This
# should always be compaitble in some way with the dependency version
# specified in the `[dependencies]` section of the package defined in
# this file
[ package . metadata . raze . crates . some-dependency . '<0 . 3 . 0' ]
additional_flags = [
" --cfg=optional_feature_a " ,
" --cfg=optional_feature_b " ,
]
# This demonstrates that multiple crate settings may be defined.
[ package . metadata . raze . crates . some-other-dependency . '*' ]
additional_flags = [
" --cfg=special_feature " ,
]
在遠端模式下,選擇與供應商模式類似的目錄。但在這種情況下,它僅包含建置檔案、工作空間的供應商指令以及明確依賴項的別名。需要稍微不同的管道。
這告訴 Raze 不要期望提供依賴項並產生不同的檔案。
首先,安裝cargo-raze。
$ cargo install cargo-raze
接下來,從cargo目錄中執行cargo raze
$ cargo raze
最後,在您的工作空間中呼叫遠端庫取得功能:
load ( "//cargo:crates.bzl" , "raze_fetch_remote_crates" )
# Note that this method's name depends on your gen_workspace_prefix setting.
# `raze` is the default prefix.
raze_fetch_remote_crates ()
這告訴 Bazel 從哪裡獲取依賴項,以及如何建構它們:使用//cargo
中產生的檔案。
您可以透過依賴//cargo:your_dependency_name
來依賴任何 Rust 規則中的任何明確依賴項。
在供應模式下,直接選擇一個根來容納供應的依賴項並成為這些建置規則的網關。 //cargo
是常規的,但//third_party/cargo
可能更適合滿足組織需求。由於特定於實現的特性,直接供應到 root 並沒有得到很好的支持,但將來可能會得到支持。從這裡開始, //cargo
將是假定的目錄。
首先,安裝供應商和產生可建置目標所需的工具。
$ cargo install cargo-raze
接下來,從 Cargo/ 目錄中提供您的依賴項。這也將更新您的Cargo.lock
檔案。
$ cargo vendor --versioned-dirs
最後,再次從cargo/
目錄中產生 BUILD 文件
$ cargo raze
現在,您可以透過依賴//cargo:your_dependency_name
來依賴任何 Rust 規則中的任何明確依賴項。
Cargo-raze 可以完全在 Bazel 中建置並使用,無需在主機上設定 Cargo。為此,只需將以下內容新增至專案中的 WORKSPACE 檔案中:
load ( "@bazel_tools//tools/build_defs/repo:http.bzl" , "http_archive" )
http_archive (
name = "cargo_raze" ,
sha256 = "c664e258ea79e7e4ec2f2b57bca8b1c37f11c8d5748e02b8224810da969eb681" ,
strip_prefix = "cargo-raze-0.11.0" ,
url = "https://github.com/google/cargo-raze/archive/v0.11.0.tar.gz" ,
)
load ( "@cargo_raze//:repositories.bzl" , "cargo_raze_repositories" )
cargo_raze_repositories ()
load ( "@cargo_raze//:transitive_deps.bzl" , "cargo_raze_transitive_deps" )
cargo_raze_transitive_deps ()
完成此操作後,使用者可以執行@cargo_raze//:raze
目標來產生新的 BUILD 檔案。例如:
bazel run @cargo_raze//:raze -- --manifest-path= $( realpath /Cargo.toml )
請注意,使用vendored
genmode 的使用者仍然必須以某種方式供應其依賴項,因為cargo-raze
目前無法為您執行此操作。
一些板條箱執行“建置腳本”,雖然在技術上它的功能不受限制,但通常會執行一些常見的操作之一。
下面提到的所有選項都在 src/settings.rs 檔案中列舉。
在某些情況下,crate 僅使用基本資訊來產生 Rust 原始檔。這些建置腳本規則實際上可以在 Bazel 中執行和使用,方法是在生成之前在 Cargo.toml 中包含指令:
[ package . metadata . raze . crates . clang-sys . '0 . 21 . 1' ]
gen_buildrs = true
此設定告訴 Cargo-raze 為建置腳本產生 rust_binary 目標,並將其產生的(OUT_DIR 樣式)輸出定向到父包。
一些建置腳本有條件地向標準輸出發出 Cargo 知道如何傳播的指令。不幸的是,管理建置時產生的依賴資訊並不那麼簡單,因此如果標誌是靜態已知的(也許,因為編譯目標是靜態已知的),則可以透過以下方式從 Cargo.toml 中提供它們
[ package . metadata . raze . crates . unicase . '2 . 1 . 0' ]
additional_flags = [
# Rustc is 1.15, enable all optional settings
" --cfg=__unicase__iter_cmp " ,
" --cfg=__unicase__defauler_hasher " ,
]
以這種方式提供的標誌直接交給 rustc。參考文件的建置腳本部分來解釋遇到的建置腳本和標準輸出指令可能會有所幫助,可在此處找到:https://doc.rust-lang.org/cargo/reference/build-scripts.html
有兩種方法可以提供 crate 編譯所需的系統函式庫。第一種是直接供應系統函式庫,為其製定 BUILD 規則,並將相依性新增至對應的-sys
crate。對於 openssl,這可能部分類似於:
[ package . metadata . raze . crates . openssl-sys . '0 . 9 . 24' ]
additional_flags = [
# Vendored openssl is 1.0.2m
" --cfg=ossl102 " ,
" --cfg=version=102 " ,
]
additional_deps = [
" @//third_party/openssl:crypto " ,
" @//third_party/openssl:ssl " ,
]
[ package . metadata . raze . crates . openssl . '0 . 10 . 2' ]
additional_flags = [
# Vendored openssl is 1.0.2m
" --cfg=ossl102 " ,
" --cfg=version=102 " ,
" --cfg=ossl10x " ,
]
在某些情況下,直接連接本機系統相依性可能會更好。為此,請參閱 Bazel 文件的new_local_repository
部分。對於工作空間中 llvm 的預編譯版本,這可能類似於:
new_local_repository (
name = "llvm" ,
build_file = "BUILD.llvm.bazel" ,
path = "/usr/lib/llvm-3.9" ,
)
在某些情況下,可能需要完全覆蓋 sys crate。這可以透過刪除和補充預生成 Cargo.toml 中的依賴項來實現:
[ package . metadata . raze . crates . sdl2 . '0 . 31 . 0' ]
skipped_deps = [
" sdl2-sys-0.31.0 "
]
additional_deps = [
" @//cargo/overrides/sdl2-sys:sdl2_sys "
]
有些板條箱提供了有用的二進位文件,它們本身可以用作編譯過程的一部分:Bindgen 就是一個很好的例子。 Bindgen 透過處理 C 或 C++ 檔案來產生 Rust 原始檔。可以將指令新增至 Cargo.toml 中,告訴 Bazel 為您公開此類二進位檔案:
[ package . metadata . raze . crates . bindgen . '0 . 32 . 2' ]
gen_buildrs = true # needed to build bindgen
extra_aliased_targets = [
" cargo_bin_bindgen "
]
Cargo-raze 在二進位目標上添加了cargo_bin_
前綴,雖然 Cargo 允許二進位和庫共享相同的目標名稱,但 Bazel 不允許這樣做。
目前,cargo 不會收集有關不提供任何函式庫的 crate 的元資料。這意味著在Cargo.toml
檔案的[dependencies]
部分中指定它們不會導致產生 Bazel 目標。當使用genmode = "Remote"
時,Cargo-raze 有一個特殊的字段來處理這些箱子:
[ package . metadata . raze . binary_deps ]
wasm-bindgen-cli = " 0.2.68 "
在上面的程式碼片段中, wasm-bindgen-cli
套件被定義為二進位依賴項,Cargo-raze 將確保此套件的元資料以及此處定義的任何其他套件都包含在結果輸出目錄中。 [package.metadata.raze.binary_deps]
下指定的目標的鎖定檔案將產生到workspace_path
指定的路徑內的lockfiles
目錄中。
請注意, binary_deps
欄位可以進入工作區和包元數據,但是,一次只能存在一個二進位依賴項的定義。如果您有多個依賴單一二進位依賴項的套件,則需要將該定義移至工作區元資料中。
將default_gen_buildrs設為true將導致cargo-raze為所有需要它們的板條箱產生建置腳本:
[ package . metadata . raze ]
workspace_path = " //cargo "
genmode = " Remote "
default_gen_buildrs = true
這個設定是方便性和正確性之間的權衡。透過啟用它,您應該會發現許多套件可以工作,而無需明確指定任何標誌,也無需手動啟用單獨的建置腳本。但是透過開啟它,您將允許您使用的所有 crate 在建置時執行任意程式碼,並且它們執行的操作可能不是封閉的。
即使啟用此設置,您可能仍然需要為一些 crate 提供額外的設定。例如,ring crate 需要在建置時存取來源樹:
[ package . metadata . raze . crates . ring . '*' ]
compile_data_attr = " glob([ " **/*.der " ]) "
如果您希望停用單一 crate 上的建置腳本,可以如下操作:
[ package . metadata . raze . crates . some_dependency . '*' ]
gen_buildrs = false
Bazel(“快速”、“正確”,選擇兩個)是一個經過實戰考驗的構建系統,Google 使用它來編譯令人難以置信的大型多語言項目,無需重複工作,也不會影響正確性。它透過限制給定編譯物件可以使用什麼機制來發現依賴關係並強制可建構單元表達其依賴關係的完整集合來部分地實現這一點。它期望兩組相同的構建目標輸入產生逐字節等效的最終結果。
作為交換,用戶將獲得可自訂和可擴展的建置系統,該系統可以編譯任何類型的可編譯目標,並允許表達“非常規依賴項”,例如Protobuf 物件、預編譯圖形著色器或生成的程式碼,同時保持快速和正確。
考慮到Bazel 的優勢(高度粒度的構建單元)構建的大型應用程式也有可能(儘管尚未通過基準測試證明)編譯速度會顯著加快,因為它們能夠更積極地緩存並避免在迭代時重新編譯盡可能多的代碼。
無論好壞,Rust 生態系統都嚴重依賴 Cargo crate 來提供標準函式庫中常見的功能。這對語言的發展來說實際上是一件奇妙的事情,因為它描述了一個穩定的結構化過程(實驗板條箱-> 1.0 板條箱-> RFC -> 包含在stdlib 中),但這意味著無法訪問這個生態系統的人必須重新發明許多輪子。
除此之外,還有一些很棒的套件可以幫助 Rust 開發人員與行業標準系統和函式庫進行交互,從而大大加快該語言的開發速度。
儘管模擬 Cargo 功能(如果可能的話!)的負擔很高,但這似乎是維持 Bazel 賴以保持性能的保證(正確性、可重複性)的唯一方法。對於正在運行的 RFC,Cargo 可能會變得足夠靈活,可以直接用於編譯,但目前看來,保持功能奇偶性的外觀實際上比避免像 Rust 編譯器一樣對待 Cargo。
只需一點點努力,就可以建立幾乎所有內容,包括依賴 openssl-sys 的專案。許多 sys crate 需要識別它們所包裝的系統庫,並將其供應到專案中,或告訴 Bazel 它位於系統上的位置。有些可能需要小的源調整,例如消除硬編碼的貨物環境變數要求。在某些情況下,修復可能並不簡單,但範例儲存庫中已建置了大量最受歡迎的板條箱,可在 https://github.com/acmcarther/cargo-raze-crater 上找到
請參閱以下提供 crate 配置的範例:
使用供應商模式:
使用遠端模式:
編譯 OpenSSL :
[package.metadata.raze]
部分衍生自 impl/src/settings.rs 所宣告的結構。