Bei Cargo-Raze handelt es sich derzeit um ein nicht gewartetes und nicht unterstütztes Produkt .
crate_universe
in rules_rust
ist ein unterstütztes und gepflegtes Produkt mit ähnlichen Zielen.
Wir glauben, dass crate_universe
alle Funktionen unterstützt, die auch von cargo-raze unterstützt wurden. Wir empfehlen Ihnen, zu versuchen, dorthin zu migrieren. Wenn Sie fehlende Unterstützung oder Fehler finden, reichen Sie bitte ein Problem oder eine PR bei rules_rust
ein.
cargo-raze
wurde archiviert, um der Tatsache Rechnung zu tragen, dass gegen das Unternehmen eingereichte PRs und Probleme wahrscheinlich nicht bearbeitet werden.
Bitte wenden Sie sich an #rust in the Bazel Slack, wenn Sie daran interessiert sind, die Wartung dieses Projekts zu übernehmen.
Ein experimentelles Unterstützungs-Cargo-Plugin zum Destillieren einer Cargo.toml auf Arbeitsbereichsebene in BUILD-Ziele, von denen Code mithilfe von Rules_rust direkt abhängen kann.
Dies ist kein offizielles Google-Produkt (experimentell oder anderweitig), es handelt sich lediglich um Code, der zufällig Eigentum von Google ist.
Dieses Projekt synthetisiert die Abhängigkeitsauflösungslogik und einige der Funktionen von Cargo, wie z. B. Features und Build-Skripte, zu ausführbaren Regeln, die Bazel ausführen kann, um Rust-Crates zu kompilieren. Obwohl die Standardregeln „rules_rust“ verwendet werden können, um Rust-Code von Grund auf zu kompilieren, macht die feine Granularität des Abhängigkeitsökosystems die Transformation von Abhängigkeitsbäumen basierend auf diesem Ökosystem mühsam, selbst für Code mit wenigen Abhängigkeiten.
Cargo-Raze kann baubare Ziele in einem von zwei Modi generieren: Verkauf oder Nicht-Verkauf. Im Vendoring-Modus verwenden Entwickler den allgemeinen Unterbefehl cargo vendor
, um die von ihrem Arbeitsbereich „Cargo.toml“ angegebenen Abhängigkeiten in Verzeichnisse abzurufen, die „cargo-raze“ dann mit BUILD-Dateien füllt. Im Nicht-Vendoring-Modus generiert cargo-raze eine flache Liste von BUILD-Dateien und ein Makro auf Arbeitsbereichsebene, das in der WORKSPACE-Datei aufgerufen werden kann, um die Abhängigkeiten automatisch herunterzuziehen, ähnlich wie bei Cargo selbst.
In beiden Fällen besteht der erste Schritt darin, zu entscheiden, wo die Cargo-Abhängigkeiten im Arbeitsbereich platziert werden sollen. Diese Bibliothek wurde im Hinblick auf Monorepos entwickelt, bei denen eine Organisation über eine Reihe von Abhängigkeiten entscheidet, auf die jeder verweist. Es ist beabsichtigt, dass die Beteiligten in den Abhängigkeiten zusammenarbeiten, um Abhängigkeiten atomar zu aktualisieren und gleichzeitig Fehler in ihrer Codebasis zu beheben. Für den Fall, dass dies nicht möglich ist, ist es immer noch möglich, Cargo-Raze in einem dezentralen Szenario zu verwenden, aber es ist unwahrscheinlich, dass solche entkoppelten Repositories gut mit der aktuellen Implementierung interagieren würden.
Unabhängig vom gewählten Ansatz sollten die rust_rules in den WORKSPACE übernommen werden. Hier ist ein Beispiel:
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" )
Für reine Bazel-Projekte sollten Benutzer zunächst eine Standard-Cargo.toml mit den gewünschten Abhängigkeiten generieren. Achten Sie darauf, eine [lib]
-Direktive einzubinden, damit sich Cargo nicht über fehlende Quelldateien für diese Scheinkiste beschwert. Hier ist ein Beispiel:
[ 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 "
Sobald die Standard-Cargo.toml vorhanden ist, fügen Sie die [package.metadata.raze]
-Anweisungen gemäß dem nächsten Abschnitt hinzu.
Fast alle kanonischen Frachtkonfigurationen sollten in der Lage sein, mit cargo-raze
zu funktionieren. Vorausgesetzt, der Cargo-Arbeitsbereich ist jetzt unter einem Bazel-Arbeitsbereich verschachtelt, können Benutzer einfach RazeSettings zu ihren Cargo.toml-Dateien hinzufügen, um sie zum Generieren von Bazel-Dateien zu verwenden
# 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 "
In Projekten, die Cargo-Arbeitsbereiche verwenden, sollten Benutzer alle ihre raze
-Einstellungen im Feld [workspace.metadata.raze]
in der Cargo.toml
Datei der obersten Ebene organisieren, die die [workspace]
-Definition enthält. Diese Einstellungen sollten mit denen in [package.metadata.raze]
im vorherigen Abschnitt identisch sein. Allerdings können Kisteneinstellungen weiterhin in den Cargo.toml
Dateien der Arbeitsbereichsmitglieder platziert werden:
# 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 " ,
]
Im Remote-Modus wird ein Verzeichnis ähnlich dem Vendoring-Modus ausgewählt. In diesem Fall enthält es jedoch nur BUILD-Dateien, eine Verkaufsanweisung für den WORKSPACE und Aliase für die expliziten Abhängigkeiten. Es sind etwas andere Sanitärinstallationen erforderlich.
Dies weist Raze an, nicht zu erwarten, dass die Abhängigkeiten bereitgestellt werden, und unterschiedliche Dateien zu generieren.
Installieren Sie zunächst Cargo-Raze.
$ cargo install cargo-raze
Führen Sie als Nächstes „Cargo Raze“ aus dem Cargo-Verzeichnis aus
$ cargo raze
Rufen Sie abschließend die Funktion zum Abrufen der Remote-Bibliothek in Ihrem ARBEITSBEREICH auf:
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 ()
Dadurch wird Bazel mitgeteilt, woher die Abhängigkeiten stammen und wie sie erstellt werden: mithilfe der in //cargo
generierten Dateien.
Sie können sich auf alle expliziten Abhängigkeiten in jeder Rust-Regel verlassen, indem Sie von //cargo:your_dependency_name
abhängig sind.
Im Vendoring-Modus wird direkt ein Root ausgewählt, der die bereitgestellten Abhängigkeiten beherbergt und zum Gateway zu diesen Build-Regeln wird. //cargo
ist konventionell, aber //third_party/cargo
kann wünschenswert sein, um organisatorische Anforderungen zu erfüllen. Der direkte Vertrieb in Root wird aufgrund implementierter spezifischer Besonderheiten nicht gut unterstützt, wird aber möglicherweise in Zukunft unterstützt. Von hier an wird //cargo
das angenommene Verzeichnis sein.
Installieren Sie zunächst die erforderlichen Tools zum Verkaufen und Generieren von BUILDable-Zielen.
$ cargo install cargo-raze
Anschließend stellen Sie Ihre Abhängigkeiten im Verzeichnis „cargo/“ bereit. Dadurch wird auch Ihre Cargo.lock
Datei aktualisiert.
$ cargo vendor --versioned-dirs
Generieren Sie abschließend Ihre BUILD-Dateien, wiederum aus dem Verzeichnis cargo/
“.
$ cargo raze
Sie können sich jetzt auf alle expliziten Abhängigkeiten in jeder Rust-Regel verlassen, indem Sie von //cargo:your_dependency_name
abhängig sind.
Cargo-raze kann vollständig in Bazel erstellt und verwendet werden, ohne dass Cargo auf der Host-Maschine eingerichtet werden muss. Fügen Sie dazu einfach Folgendes zur WORKSPACE-Datei in Ihrem Projekt hinzu:
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 ()
Wenn dies eingerichtet ist, können Benutzer das Ziel @cargo_raze//:raze
ausführen, um neue BUILD-Dateien zu generieren. z.B:
bazel run @cargo_raze//:raze -- --manifest-path= $( realpath /Cargo.toml )
Beachten Sie, dass Benutzer, die den vendored
Genmodus verwenden, ihre Abhängigkeiten trotzdem irgendwie bereitstellen müssen, da cargo-raze
dies derzeit nicht für Sie erledigt.
Einige Crates führen ein „Build-Skript“ aus, das zwar technisch gesehen keine Einschränkungen in seinen Möglichkeiten hat, aber normalerweise eine der wenigen üblichen Aufgaben ausführt.
Alle unten aufgeführten Optionen sind in der Datei src/settings.rs aufgeführt.
In einigen Fällen verwendet eine Kiste nur grundlegende Informationen, um eine Rust-Quelldatei zu generieren. Diese Build-Skript-Regeln können tatsächlich in Bazel ausgeführt und verwendet werden, indem Sie vor der Generierung eine Anweisung in Ihre Cargo.toml einfügen:
[ package . metadata . raze . crates . clang-sys . '0 . 21 . 1' ]
gen_buildrs = true
Diese Einstellung weist Cargo-raze an, ein rust_binary-Ziel für das Build-Skript zu generieren und seine generierten Ausgaben (im OUT_DIR-Stil) an die übergeordnete Kiste weiterzuleiten.
Einige Build-Skripte geben bedingt Anweisungen an stdout aus, die Cargo weitergeben kann. Leider ist es nicht so einfach, zur Erstellungszeit generierte Abhängigkeitsinformationen zu verwalten. Wenn die Flags also statisch bekannt sind (vielleicht, weil das Kompilierungsziel statisch bekannt ist), können sie auf folgende Weise aus Cargo.toml bereitgestellt werden
[ 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 " ,
]
Auf diese Weise bereitgestellte Flaggen werden direkt an rustc übergeben. Es kann hilfreich sein, auf den Build-Script-Abschnitt der Dokumentation zu verweisen, um die angetroffenen Build-Skripte und stdout-Anweisungen zu interpretieren, verfügbar hier: https://doc.rust-lang.org/cargo/reference/build-scripts.html
Es gibt zwei Möglichkeiten, Systembibliotheken bereitzustellen, die eine Kiste zum Kompilieren benötigt. Die erste besteht darin, die Systembibliothek direkt bereitzustellen, eine BUILD-Regel dafür zu erstellen und die Abhängigkeit zur entsprechenden -sys
Kiste hinzuzufügen. Für OpenSSL könnte dies teilweise so aussehen:
[ 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 " ,
]
In manchen Fällen kann die direkte Verkabelung einer lokalen Systemabhängigkeit vorzuziehen sein. Lesen Sie dazu den Abschnitt new_local_repository
der Bazel-Dokumentation. Für eine vorkompilierte Version von llvm in einem WORKSPACE könnte dies etwa so aussehen:
new_local_repository (
name = "llvm" ,
build_file = "BUILD.llvm.bazel" ,
path = "/usr/lib/llvm-3.9" ,
)
In einigen Fällen muss die Systemkiste möglicherweise vollständig überschrieben werden. Dies kann erleichtert werden, indem Abhängigkeiten in der Cargo.toml vor der Generierung entfernt und ergänzt werden:
[ package . metadata . raze . crates . sdl2 . '0 . 31 . 0' ]
skipped_deps = [
" sdl2-sys-0.31.0 "
]
additional_deps = [
" @//cargo/overrides/sdl2-sys:sdl2_sys "
]
Einige Kisten stellen nützliche Binärdateien bereit, die selbst als Teil eines Kompilierungsprozesses verwendet werden können: Bindgen ist ein großartiges Beispiel. Bindgen erzeugt Rust-Quelldateien durch die Verarbeitung von C- oder C++-Dateien. Der Cargo.toml kann eine Anweisung hinzugefügt werden, um Bazel anzuweisen, solche Binärdateien für Sie verfügbar zu machen:
[ package . metadata . raze . crates . bindgen . '0 . 32 . 2' ]
gen_buildrs = true # needed to build bindgen
extra_aliased_targets = [
" cargo_bin_bindgen "
]
Cargo-raze stellt binären Zielen das cargo_bin_
voran, denn obwohl Cargo zulässt, dass Binärdateien und Bibliotheken denselben Zielnamen verwenden, erlaubt Bazel dies nicht.
Derzeit erfasst Cargo keine Metadaten zu Kisten, die keine Bibliotheken bereitstellen. Das bedeutet, dass die Angabe im Abschnitt [dependencies]
Ihrer Cargo.toml
Datei nicht zu generierten Bazel-Zielen führt. Cargo-raze verfügt über ein spezielles Feld zur Handhabung dieser Kisten, wenn genmode = "Remote"
verwendet wird:
[ package . metadata . raze . binary_deps ]
wasm-bindgen-cli = " 0.2.68 "
Im obigen Snippet ist die Kiste wasm-bindgen-cli
als binäre Abhängigkeit definiert und Cargo-raze stellt sicher, dass Metadaten für diese und jede andere hier definierte Kiste im resultierenden Ausgabeverzeichnis enthalten sind. Sperrdateien für unter [package.metadata.raze.binary_deps]
angegebene Ziele werden in einem lockfiles
innerhalb des durch workspace_path
angegebenen Pfads generiert.
Beachten Sie, dass das Feld binary_deps
in Arbeitsbereichs- und Paketmetadaten enthalten sein kann, jedoch jeweils nur eine Definition einer binären Abhängigkeit vorhanden sein kann. Wenn Sie über mehrere Pakete verfügen, die von einer einzigen binären Abhängigkeit abhängen, muss diese Definition in die Metadaten des Arbeitsbereichs verschoben werden.
Wenn Sie „default_gen_buildrs“ auf „true“ setzen, generiert „cargo-raze“ Build-Skripte für alle Crates, die diese benötigen:
[ package . metadata . raze ]
workspace_path = " //cargo "
genmode = " Remote "
default_gen_buildrs = true
Diese Einstellung ist ein Kompromiss zwischen Bequemlichkeit und Korrektheit. Wenn Sie es aktivieren, sollten Sie feststellen, dass viele Crates funktionieren, ohne dass Flags explizit angegeben werden müssen und ohne dass einzelne Build-Skripte manuell aktiviert werden müssen. Wenn Sie es jedoch aktivieren, erlauben Sie allen von Ihnen verwendeten Crates, zur Erstellungszeit beliebigen Code auszuführen, und die von ihnen ausgeführten Aktionen sind möglicherweise nicht hermetisch.
Auch wenn diese Einstellung aktiviert ist, müssen Sie möglicherweise noch zusätzliche Einstellungen für einige Crates vornehmen. Beispielsweise benötigt die Ringkiste zur Erstellungszeit Zugriff auf den Quellbaum:
[ package . metadata . raze . crates . ring . '*' ]
compile_data_attr = " glob([ " **/*.der " ]) "
Wenn Sie das Build-Skript für eine einzelne Kiste deaktivieren möchten, können Sie dies wie folgt tun:
[ package . metadata . raze . crates . some_dependency . '*' ]
gen_buildrs = false
Bazel („schnell“, „richtig“, zwei auswählen) ist ein kampferprobtes Build-System, mit dem Google unglaublich große, mehrsprachige Projekte ohne Doppelaufwand und ohne Kompromisse bei der Korrektheit kompilieren kann. Dies wird zum Teil dadurch erreicht, dass die Mechanismen, die ein bestimmtes Kompilierungsobjekt zum Erkennen von Abhängigkeiten verwenden kann, eingeschränkt werden und dass baubare Einheiten gezwungen werden, den vollständigen Satz ihrer Abhängigkeiten auszudrücken. Es wird erwartet, dass zwei identische Sätze von Build-Zieleingaben ein byteweise äquivalentes Endergebnis erzeugen.
Im Gegenzug werden Benutzer mit einem anpassbaren und erweiterbaren Build-System belohnt, das jede Art von kompilierbarem Ziel kompiliert und es ermöglicht, „unkonventionelle Abhängigkeiten“ wie Protobuf-Objekte, vorkompilierte Grafik-Shader oder generierten Code auszudrücken, und dabei schnell und korrekt bleibt.
Es ist auch wahrscheinlich (obwohl dies noch nicht durch Benchmarks nachgewiesen wurde), dass große Anwendungen, die mit Bazels Stärken im Hinterkopf erstellt wurden: hochgranulare Build-Einheiten, deutlich schneller kompiliert werden, da sie aggressiver zwischenspeichern können und die Neukompilierung von ebenso viel Code während der Iteration vermeiden können.
Im Guten wie im Schlechten ist das Rust-Ökosystem stark von Cargo-Kisten abhängig, um Funktionen bereitzustellen, die häufig in Standardbibliotheken vorhanden sind. Das ist eigentlich eine fantastische Sache für die Entwicklung der Sprache, da es einen strukturierten Prozess zur Stabilisierung beschreibt (experimentelle Kiste -> 1.0 Kiste -> RFC -> Aufnahme in stdlib), aber es bedeutet, dass Menschen, die keinen Zugang zu diesem Ökosystem haben, dies tun müssen viele Räder neu erfinden.
Abgesehen davon gibt es auch fantastische Crates, die Rust-Entwicklern dabei helfen, mit branchenüblichen Systemen und Bibliotheken zu interagieren, was die Entwicklung in der Sprache erheblich beschleunigen kann.
Obwohl die Belastung durch die Emulation der Funktionalität von Cargo (wo überhaupt möglich!) hoch ist, scheint dies die einzige Möglichkeit zu sein, die Garantien (Korrektheit, Reproduzierbarkeit) aufrechtzuerhalten, auf die Bazel angewiesen ist, um leistungsfähig zu bleiben. Es ist möglich und wahrscheinlich, dass Cargo mit Inflight-RFCs so flexibel wird, dass es direkt für die Kompilierung verwendet werden kann, aber zum jetzigen Zeitpunkt scheint es tatsächlich einfacher zu sein, einen Anschein von Feature-Parität aufrechtzuerhalten, als alle durch eingeführten scharfen Kanten zu vermeiden Cargo wie den Rust-Compiler behandeln.
Mit ein wenig Fingerspitzengefühl ist es möglich, fast alles zu erstellen, auch Projekte, die von openssl-sys abhängen. Bei vielen Systemen müssen Sie die Systembibliothek identifizieren, die sie umschließen, und sie entweder in das Projekt einbinden oder Bazel mitteilen, wo sie sich auf Ihrem System befindet. Einige erfordern möglicherweise geringfügige Quelloptimierungen, z. B. die Beseitigung fest codierter Anforderungen an Frachtumgebungsvariablen. Korrekturen können in einigen Fällen nicht trivial sein, aber eine ganze Reihe der beliebtesten Kisten wurden in einem Beispiel-Repo erstellt, verfügbar unter https://github.com/acmcarther/cargo-raze-crater
Sehen Sie sich diese Beispiele für die Bereitstellung der Crate-Konfiguration an:
Verwendung des Vendored-Modus :
Verwendung des Remote-Modus :
Kompilieren von OpenSSL :
Der Abschnitt [package.metadata.raze]
wird von einer in impl/src/settings.rs deklarierten Struktur abgeleitet.