Cargo-Raze в настоящее время является необслуживаемым и неподдерживаемым продуктом .
crate_universe
в rules_rust
— это поддерживаемый и поддерживаемый продукт, преследующий аналогичные цели.
Мы считаем, что crate_universe
поддерживает все функциональные возможности, которые поддерживает Cargo-Raze. Мы рекомендуем вам попробовать перейти на него. Если вы обнаружите недостающую поддержку или ошибки, сообщите о проблеме или сообщите о проблеме в rules_rust
.
cargo-raze
был заархивирован, чтобы отразить тот факт, что жалобы и проблемы, выдвинутые против него, вряд ли будут решены.
Если вы хотите взять на себя обслуживание этого проекта, свяжитесь с #rust в Bazel Slack.
Экспериментальный плагин поддержки Cargo для преобразования Cargo.toml уровня рабочей области в цели BUILD, от которых код с использованием Rules_rust может напрямую зависеть.
Это не официальный продукт Google (экспериментальный или какой-либо другой), это просто код, принадлежащий Google.
Этот проект синтезирует логику разрешения зависимостей и некоторые функции Cargo, такие как функции и сценарии сборки, в исполняемые правила, которые Bazel может запускать для компиляции ящиков Rust. Хотя стандартные правила rule_rust можно использовать для компиляции кода Rust с нуля, высокая степень детализации экосистемы зависимостей делает преобразование деревьев зависимостей на основе этой экосистемы обременительным, даже для кода с небольшим количеством зависимостей.
Cargo-Raze может создавать сборные цели в одном из двух режимов: торговый или неторговый. В режиме поставщика разработчики используют подкоманду common cargo vendor
для извлечения зависимостей, указанных в их рабочей области Cargo.toml, в каталоги, которые с помощью Cargo-raze затем заполняются файлами BUILD. В режиме без поставщика Cargo-Raze генерирует плоский список файлов BUILD и макрос уровня рабочей области, который можно вызвать в файле WORKSPACE для автоматического извлечения зависимостей аналогично самому Cargo.
В обоих случаях первым шагом является решение о том, где разместить зависимости Cargo в рабочей области. Эта библиотека была разработана с учетом монорепозиториев, где организация выбирает набор зависимостей, на которые все указывают. Предполагается, что заинтересованные стороны в зависимостях сотрудничают для атомарного обновления зависимостей и одновременного устранения неполадок во всей своей кодовой базе. В случае, если это невозможно, все равно можно использовать Cargo-Raze в децентрализованном сценарии, но маловероятно, что такие разделенные репозитории будут хорошо взаимодействовать с текущей реализацией.
Независимо от выбранного подхода, Rust_rules следует перенести в WORKSPACE. Вот пример:
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 "
В проектах, в которых используются грузовые рабочие области, пользователи должны организовать все свои настройки raze
в поле [workspace.metadata.raze]
в файле Cargo.toml
верхнего уровня, который содержит определение [workspace]
. Эти настройки должны быть идентичны тем, которые указаны в [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 " ,
]
В удаленном режиме выбирается каталог, аналогичный режиму поставщика. Однако в данном случае он содержит только файлы BUILD, инструкцию производителя для WORKSPACE и псевдонимы явных зависимостей. Требуется немного другая сантехника.
Это говорит Raze не ожидать, что зависимости будут предоставлены поставщиками и будут генерировать разные файлы.
Сначала устанавливаем Cargo-Raze.
$ cargo install cargo-raze
Затем выполните команду Cargo Raze из каталога Cargo.
$ 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
.
Вы можете зависеть от любых явных зависимостей в любом правиле Rust, в зависимости от //cargo:your_dependency_name
.
В режиме Vendoring напрямую выбирается корень, в котором будут размещаться зависимости от поставщиков и который станет шлюзом для этих правил сборки. //cargo
является традиционным, но //third_party/cargo
может оказаться желательным для удовлетворения потребностей организации. Поставка непосредственно в root не поддерживается из-за особенностей реализации, но может поддерживаться в будущем. С этого момента предполагаемым каталогом будет //cargo
.
Сначала установите необходимые инструменты для разработки и создания целей BUILDable.
$ cargo install cargo-raze
После этого продайте свои зависимости из каталога Cargo/. Это также обновит ваш файл Cargo.lock
.
$ cargo vendor --versioned-dirs
Наконец, сгенерируйте файлы BUILD, опять же из каталога cargo/
$ cargo raze
Теперь вы можете зависеть от любых явных зависимостей в любом правиле Rust, в зависимости от //cargo:your_dependency_name
.
Cargo-raze можно полностью построить в Bazel и использовать без необходимости установки груза на хост-компьютере. Для этого просто добавьте следующее в файл 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.
В некоторых случаях крейт использует только базовую информацию для создания исходного файла 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. Для интерпретации встречающихся сценариев сборки и директив stdout может оказаться полезным обратиться к разделу документации о сборке, доступному здесь: https://doc.rust-lang.org/cargo/reference/build-scripts.html.
Есть два способа предоставить системные библиотеки, необходимые крейту для компиляции. Первый — напрямую продать системную библиотеку, создать для нее правило BUILD и добавить зависимость в соответствующий крейт -sys
. Для 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 " ,
]
В некоторых случаях предпочтительнее напрямую подключить зависимость от локальной системы. Для этого обратитесь к разделу new_local_repository
документации Bazel. Для предварительно скомпилированной версии llvm в РАБОЧЕЙ ОБЛАСТИ это может выглядеть примерно так:
new_local_repository (
name = "llvm" ,
build_file = "BUILD.llvm.bazel" ,
path = "/usr/lib/llvm-3.9" ,
)
В некоторых случаях может потребоваться полное переопределение системного крейта. Этому можно способствовать, удалив и дополнив зависимости в 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 создает исходные файлы Rust путем обработки файлов C или C++. В файл 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 не собирает метаданные о ящиках, которые не предоставляют никаких библиотек. Это означает, что указание их в разделе [dependencies]
вашего файла Cargo.toml
не приведет к созданию целевых объектов Bazel. В Cargo-raze есть специальное поле для обработки этих ящиков при использовании genmode = "Remote"
:
[ package . metadata . raze . binary_deps ]
wasm-bindgen-cli = " 0.2.68 "
В приведенном выше фрагменте крейт wasm-bindgen-cli
определен как двоичная зависимость, и Cargo-raze гарантирует, что метаданные для этого и любого другого крейта, определенного здесь, будут включены в результирующий выходной каталог. Файлы блокировки для целевых объектов, указанных в параметре [package.metadata.raze.binary_deps]
будут созданы в каталоге lockfiles
внутри пути, указанного в параметре workspace_path
.
Обратите внимание, что binary_deps
может находиться в метаданных рабочей области и пакета, однако одновременно может существовать только одно определение двоичной зависимости. Если у вас есть несколько пакетов, которые зависят от одной двоичной зависимости, это определение необходимо переместить в метаданные рабочей области.
Установка default_gen_buildrs в значение true приведет к тому, что Cargo-Raze будет генерировать сценарии сборки для всех ящиков, которые в них нуждаются:
[ package . metadata . raze ]
workspace_path = " //cargo "
genmode = " Remote "
default_gen_buildrs = true
Эта настройка представляет собой компромисс между удобством и корректностью. Включив его, вы обнаружите, что многие ящики работают без необходимости явного указания каких-либо флагов и без необходимости вручную включать отдельные сценарии сборки. Но включив его, вы разрешаете всем используемым вами ящикам запускать произвольный код во время сборки, и выполняемые ими действия могут не быть герметичными.
Даже если этот параметр включен, вам все равно может потребоваться предоставить дополнительные настройки для нескольких ящиков. Например, контейнеру Ring требуется доступ к дереву исходного кода во время сборки:
[ package . metadata . raze . crates . ring . '*' ]
compile_data_attr = " glob([ " **/*.der " ]) "
Если вы хотите отключить сценарий сборки для отдельного ящика, вы можете сделать это следующим образом:
[ package . metadata . raze . crates . some_dependency . '*' ]
gen_buildrs = false
Bazel («быстрый», «правильный», выберите два) — это проверенная в боях система сборки, используемая Google для компиляции невероятно больших многоязычных проектов без дублирования усилий и без ущерба для корректности. Частично это достигается за счет ограничения механизмов, которые данный объект компиляции может использовать для обнаружения зависимостей, а также за счет того, что сборные модули выражают полный набор своих зависимостей. Он ожидает, что два идентичных набора целевых входных данных сборки дадут конечный результат, эквивалентный побайтно.
Взамен пользователи получают настраиваемую и расширяемую систему сборки, которая компилирует любые компилируемые цели и позволяет выражать «нетрадиционные зависимости», такие как объекты Protobuf, предварительно скомпилированные графические шейдеры или сгенерированный код, оставаясь при этом быстрыми и корректными.
Также вероятно (хотя это еще не продемонстрировано с помощью тестов), что большие приложения, созданные с учетом сильных сторон Bazel: высокодетализированных модулей сборки, будут компилироваться значительно быстрее, поскольку они способны более агрессивно кэшировать и избегать перекомпиляции большого количества кода во время итерации.
К лучшему или худшему, экосистема Rust сильно зависит от контейнеров Cargo, обеспечивающих функциональность, которая часто присутствует в стандартных библиотеках. На самом деле это фантастическая вещь для эволюции языка, поскольку она описывает структурированный процесс стабилизации (экспериментальный крейт -> крейт 1.0 -> RFC -> включение в stdlib), но это означает, что люди, у которых нет доступа к этой экосистеме, должны изобрести множество колес.
Помимо этого, есть также фантастические ящики, которые помогают разработчикам Rust взаимодействовать со стандартными системами и библиотеками, что может значительно ускорить разработку на языке.
Хотя бремя эмуляции функциональности Cargo (там, где это вообще возможно!) велико, похоже, это единственный способ сохранить гарантии (правильность, воспроизводимость), от которых зависит сохранение производительности Bazel. Вполне возможно и вероятно, что с помощью RFC в полете Cargo станет достаточно гибким, чтобы его можно было использовать непосредственно для компиляции, но на данный момент кажется, что поддерживать видимость четности функций на самом деле проще, чем избегать всех острых краев, введенных относиться к Cargo как к компилятору Rust.
Приложив немного усилий, можно построить практически все, включая проекты, зависящие от openssl-sys. Многие системные ящики потребуют идентификации системной библиотеки, которую они оборачивают, и либо включения ее в проект, либо указания Bazel, где она находится в вашей системе. Некоторые могут потребовать незначительных настроек исходного кода, таких как устранение жестко запрограммированных требований к переменным среды груза. В некоторых случаях исправления могут быть нетривиальными, но большое количество наиболее популярных ящиков было создано в репозитории примеров, доступном по адресу https://github.com/acmcarther/cargo-raze-crater.
См. эти примеры предоставления конфигурации ящика:
Использование вендорного режима :
Использование удаленного режима :
Компиляция OpenSSL :
Раздел [package.metadata.raze]
является производным от структуры, объявленной в impl/src/settings.rs.