cargo-raze es actualmente un producto sin mantenimiento ni soporte .
crate_universe
en rules_rust
es un producto respaldado y mantenido con objetivos similares.
Creemos que crate_universe
admite todas las funciones admitidas por cargo-raze. Le recomendamos que intente migrar a él. Si encuentra que falta soporte o hay errores, presente un problema o un PR contra rules_rust
.
cargo-raze
se ha archivado para reflejar la realidad de que es poco probable que se aborden las relaciones públicas y los problemas presentados en su contra.
Comuníquese con #rust en Bazel Slack si está interesado en hacerse cargo del mantenimiento de este proyecto.
Un complemento de Cargo de soporte experimental para destilar un Cargo.toml a nivel de espacio de trabajo en objetivos BUILD en los que el código que usa reglas_rust puede depender directamente.
Este no es un producto oficial de Google (experimental o no), es solo un código que resulta ser propiedad de Google.
Este proyecto sintetiza la lógica de resolución de dependencias y algunas de las funciones de Cargo, como características y creación de scripts en reglas ejecutables que Bazel puede ejecutar para compilar cajas de Rust. Aunque las reglas estándar de marks_rust se pueden usar para compilar código Rust desde cero, la fina granularidad del ecosistema de dependencia hace que la transformación de los árboles de dependencia basados en ese ecosistema sea onerosa, incluso para código con pocas dependencias.
cargo-raze puede generar objetivos construibles en uno de dos modos: vendedor o no vendedor. En el modo de venta, los desarrolladores utilizan el subcomando común cargo vendor
para recuperar las dependencias indicadas por su espacio de trabajo Cargo.toml en directorios que cargo-raze luego llena con archivos BUILD. En el modo no vendedor, cargo-raze genera una lista plana de archivos BUILD y una macro a nivel de espacio de trabajo que se puede invocar en el archivo WORKSPACE para desplegar las dependencias automáticamente de manera similar al propio Cargo.
En ambos casos, el primer paso es decidir dónde ubicar las dependencias de Cargo en el espacio de trabajo. Esta biblioteca fue diseñada teniendo en mente monorepos, donde una organización decide sobre un conjunto de dependencias a las que todos apuntan. La intención es que las partes interesadas en las dependencias colaboren para actualizar las dependencias de forma atómica y corregir fallas en su base de código simultáneamente. En el caso de que esto no sea factible, aún es posible utilizar cargo-raze en un escenario descentralizado, pero es poco probable que dichos repositorios desacoplados interactúen bien con la implementación actual.
Independientemente del enfoque elegido, las Rust_rules deben incorporarse al ESPACIO DE TRABAJO. Aquí hay un ejemplo:
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" )
Para proyectos exclusivos de Bazel, los usuarios primero deben generar un Cargo.toml estándar con las dependencias de interés. Tenga cuidado de incluir una directiva [lib]
para que Cargo no se queje de que faltan archivos fuente para esta caja simulada. Aquí hay un ejemplo:
[ 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 "
Una vez que el Cargo.toml estándar esté implementado, agregue las directivas [package.metadata.raze]
según la siguiente sección.
Casi todas las configuraciones de carga canónicas deberían poder funcionar in situ con cargo-raze
. Suponiendo que el espacio de trabajo de Cargo ahora esté anidado en un espacio de trabajo de Bazel, los usuarios pueden simplemente agregar RazeSettings a sus archivos Cargo.toml para usarlos para generar archivos de 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 "
En proyectos que utilizan espacios de trabajo de carga, los usuarios deben organizar todas sus configuraciones raze
en el campo [workspace.metadata.raze]
en el archivo Cargo.toml
de nivel superior que contiene la definición de [workspace]
. Estas configuraciones deben ser idénticas a las que se ven en [package.metadata.raze]
en la sección anterior. Sin embargo, es posible que la configuración de la caja aún se coloque en los archivos Cargo.toml
de los miembros del espacio de trabajo:
# 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 " ,
]
En el modo Remoto, se selecciona un directorio similar al modo de proveedor. Sin embargo, en este caso, contiene sólo archivos BUILD, una instrucción de proveedor para el ESPACIO DE TRABAJO y alias de las dependencias explícitas. Se requiere plomería ligeramente diferente.
Esto le dice a Raze que no espere que se proporcionen las dependencias y que genere archivos diferentes.
Primero, instale cargo-raze.
$ cargo install cargo-raze
A continuación, ejecute cargo raze desde el directorio de carga.
$ cargo raze
Finalmente, invoque la función de búsqueda remota de biblioteca dentro de su ESPACIO DE TRABAJO:
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 ()
Esto le dice a Bazel de dónde obtener las dependencias y cómo construirlas: usando los archivos generados en //cargo
.
Puede depender de cualquier dependencia explícita en cualquier regla de Rust dependiendo de //cargo:your_dependency_name
.
En el modo de venta, se selecciona directamente una raíz que albergará las dependencias proporcionadas y se convertirá en la puerta de entrada a esas reglas de compilación. //cargo
es convencional, pero //third_party/cargo
puede ser deseable para satisfacer las necesidades de la organización. La venta directa en la raíz no es compatible debido a idiosincrasias específicas de la implementación, pero es posible que se admita en el futuro. De aquí en adelante, //cargo
será el directorio asumido.
Primero, instale las herramientas necesarias para vender y generar objetivos CONSTRUIBLES.
$ cargo install cargo-raze
Después de eso, proporcione sus dependencias desde el directorio cargo/. Esto también actualizará su archivo Cargo.lock
.
$ cargo vendor --versioned-dirs
Finalmente, genere sus archivos BUILD, nuevamente desde el directorio cargo/
$ cargo raze
Ahora puede depender de cualquier dependencia explícita en cualquier regla de Rust dependiendo de //cargo:your_dependency_name
.
Cargo-raze se puede construir completamente en Bazel y usarse sin necesidad de configurar cargo en la máquina host. Para hacerlo, simplemente agregue lo siguiente al archivo WORKSPACE en su proyecto:
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 ()
Una vez implementado esto, los usuarios pueden ejecutar el objetivo @cargo_raze//:raze
para generar nuevos archivos BUILD. p.ej:
bazel run @cargo_raze//:raze -- --manifest-path= $( realpath /Cargo.toml )
Tenga en cuenta que los usuarios que utilicen el modo gen vendored
aún tendrán que vender sus dependencias de alguna manera, ya que cargo-raze
actualmente no lo hace por usted.
Algunas cajas ejecutan un "script de compilación" que, aunque técnicamente no tiene restricciones en lo que puede hacer, generalmente hace una de algunas cosas comunes.
Todas las opciones que se indican a continuación se enumeran en el archivo src/settings.rs.
En algunos casos, una caja utiliza solo información básica para generar un archivo fuente de Rust. Estas reglas de scripts de compilación se pueden ejecutar y usar dentro de Bazel al incluir una directiva en su Cargo.toml antes de la generación:
[ package . metadata . raze . crates . clang-sys . '0 . 21 . 1' ]
gen_buildrs = true
Esta configuración le dice a cargo-raze que genere un objetivo rust_binary para el script de compilación y que dirija sus salidas generadas (estilo OUT_DIR) a la caja principal.
Algunos scripts de compilación emiten directivas condicionalmente para indicar que Cargo sabe cómo propagarse. Desafortunadamente, no es tan sencillo administrar la información de dependencia generada en el momento de la compilación, por lo que si los indicadores se conocen estáticamente (quizás, debido a que el objetivo de compilación se conoce estáticamente), se pueden proporcionar desde Cargo.toml, de la siguiente manera
[ 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 " ,
]
Las banderas proporcionadas de esta manera se entregan directamente a Rustc. Puede resultar útil consultar la sección build-script de la documentación para interpretar los scripts de compilación y las directivas stdout que se encuentran, disponible aquí: https://doc.rust-lang.org/cargo/reference/build-scripts.html
Hay dos formas de proporcionar las bibliotecas del sistema que una caja necesita para su compilación. La primera es vender la biblioteca del sistema directamente, crear una regla BUILD para ella y agregar la dependencia a la caja -sys
correspondiente. Para openssl, esto puede verse en parte así:
[ 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 " ,
]
En algunos casos, puede ser preferible conectar directamente una dependencia del sistema local. Para hacer esto, consulte la sección new_local_repository
de la documentación de Bazel. Para una versión precompilada de llvm en un ESPACIO DE TRABAJO, esto puede verse así:
new_local_repository (
name = "llvm" ,
build_file = "BUILD.llvm.bazel" ,
path = "/usr/lib/llvm-3.9" ,
)
En algunos casos, es posible que sea necesario anular por completo la caja del sistema. Esto se puede facilitar eliminando y complementando las dependencias en Cargo.toml, pregeneración:
[ package . metadata . raze . crates . sdl2 . '0 . 31 . 0' ]
skipped_deps = [
" sdl2-sys-0.31.0 "
]
additional_deps = [
" @//cargo/overrides/sdl2-sys:sdl2_sys "
]
Algunas cajas proporcionan binarios útiles que pueden usarse como parte de un proceso de compilación: Bindgen es un gran ejemplo. Bindgen produce archivos fuente de Rust procesando archivos C o C++. Se puede agregar una directiva a Cargo.toml para indicarle a Bazel que exponga dichos archivos binarios por usted:
[ package . metadata . raze . crates . bindgen . '0 . 32 . 2' ]
gen_buildrs = true # needed to build bindgen
extra_aliased_targets = [
" cargo_bin_bindgen "
]
Cargo-raze antepone objetivos binarios con cargo_bin_
, ya que aunque Cargo permite que los binarios y las bibliotecas compartan el mismo nombre de objetivo, Bazel no lo permite.
Actualmente, cargo no recopila metadatos sobre cajas que no proporcionan bibliotecas. Esto significa que si los especifica en la sección [dependencies]
de su archivo Cargo.toml
no generará objetivos Bazel generados. Cargo-raze tiene un campo especial para manejar estas cajas cuando se usa genmode = "Remote"
:
[ package . metadata . raze . binary_deps ]
wasm-bindgen-cli = " 0.2.68 "
En el fragmento anterior, la caja wasm-bindgen-cli
se define como dependencia binaria y Cargo-raze garantizará que los metadatos para esta y cualquier otra caja definida aquí se incluyan en el directorio de salida resultante. Los archivos de bloqueo para los objetivos especificados en [package.metadata.raze.binary_deps]
se generarán en un directorio lockfiles
dentro de la ruta especificada por workspace_path
.
Tenga en cuenta que el campo binary_deps
puede ir al espacio de trabajo y a los metadatos del paquete; sin embargo, solo puede existir una definición de dependencia binaria a la vez. Si tiene varios paquetes que dependen de una única dependencia binaria, esa definición debe trasladarse a los metadatos del espacio de trabajo.
Establecer default_gen_buildrs en verdadero hará que cargo-raze genere scripts de compilación para todas las cajas que los requieran:
[ package . metadata . raze ]
workspace_path = " //cargo "
genmode = " Remote "
default_gen_buildrs = true
Esta configuración es un equilibrio entre conveniencia y corrección. Al habilitarlo, debería encontrar que muchas cajas funcionan sin tener que especificar ningún indicador explícitamente y sin tener que habilitar manualmente los scripts de compilación individuales. Pero al activarlo, permite que todas las cajas que está utilizando ejecuten código arbitrario en el momento de la compilación, y las acciones que realizan pueden no ser herméticas.
Incluso con esta configuración habilitada, es posible que aún necesites proporcionar configuraciones adicionales para algunas cajas. Por ejemplo, la caja de anillos necesita acceso al árbol de origen en el momento de la compilación:
[ package . metadata . raze . crates . ring . '*' ]
compile_data_attr = " glob([ " **/*.der " ]) "
Si desea deshabilitar el script de compilación en una caja individual, puede hacerlo de la siguiente manera:
[ package . metadata . raze . crates . some_dependency . '*' ]
gen_buildrs = false
Bazel ("rápido", "correcto", elija dos) es un sistema de compilación probado en batalla utilizado por Google para compilar proyectos multilingües increíblemente grandes sin duplicar esfuerzos y sin comprometer la corrección. Lo logra en parte limitando los mecanismos que un objeto de compilación determinado puede utilizar para descubrir dependencias y obligando a las unidades compilables a expresar el conjunto completo de sus dependencias. Espera que dos conjuntos idénticos de entradas de destino de compilación produzcan un resultado final equivalente byte por byte.
A cambio, los usuarios son recompensados con un sistema de compilación personalizable y extensible que compila cualquier tipo de objetivo compilable y permite expresar "dependencias no convencionales", como objetos Protobuf, sombreadores de gráficos precompilados o código generado, sin dejar de ser rápido y correcto.
También es probable (aunque aún no se ha demostrado con pruebas comparativas) que las aplicaciones grandes creadas teniendo en cuenta las fortalezas de Bazel: unidades de compilación altamente granulares, se compilarán significativamente más rápido, ya que pueden almacenar en caché de manera más agresiva y evitar la recompilación de tanto código mientras se itera.
Para bien o para mal, el ecosistema Rust depende en gran medida de las cajas de carga para proporcionar una funcionalidad que a menudo está presente en las bibliotecas estándar. En realidad, esto es algo fantástico para la evolución del lenguaje, ya que describe un proceso estructurado hacia la estabilización (caja experimental -> caja 1.0 -> RFC -> inclusión en stdlib), pero significa que las personas que carecen de acceso a este ecosistema deben reinventar muchas ruedas.
Dejando eso de lado, también hay cajas fantásticas que ayudan a los desarrolladores de Rust a interactuar con bibliotecas y sistemas estándar de la industria que pueden acelerar enormemente el desarrollo del lenguaje.
Aunque la carga de emular la funcionalidad de Cargo (¡cuando sea posible!) es alta, parece ser la única forma de mantener las garantías (corrección, reproducibilidad) de las que depende Bazel para seguir funcionando. Es posible y probable con los RFC a bordo que Cargo se vuelva lo suficientemente flexible como para permitir su uso directo para la compilación, pero en este momento parece que mantener una apariencia de paridad de características es en realidad más fácil que evitar todos los bordes afilados introducidos por tratando a Cargo como el compilador de Rust.
Con un poco de esfuerzo es posible construir casi todo, incluidos proyectos que dependen de openssl-sys. Muchas cajas de sistemas requerirán identificar la biblioteca del sistema que empaquetan y venderla en el proyecto o decirle a Bazel dónde se encuentra en su sistema. Algunos pueden requerir ajustes menores en el origen, como eliminar los requisitos variables del entorno de carga codificados. Las correcciones pueden no ser triviales en algunos casos, pero una buena cantidad de las cajas más populares se han creado en un repositorio de ejemplo, disponible en https://github.com/acmcarther/cargo-raze-crater.
Vea estos ejemplos de cómo proporcionar configuración de caja:
Usando el modo vendedor :
Usando el modo remoto :
Compilando OpenSSL :
La sección [package.metadata.raze]
se deriva de una estructura declarada en impl/src/settings.rs.