Variables "Make"

Las variables "Make" son una clase especial de variables de cadena expandibles disponibles para los atributos marcados como "Subject to 'Make variable' sustitution".

Estas se pueden usar, por ejemplo, para insertar rutas de acceso específicas de cadenas de herramientas en acciones de compilación construidas por el usuario.

Bazel proporciona variables predefinidas, que están disponibles para todos los objetivos, y variables personalizadas, que se definen en objetivos de dependencia y solo están disponibles para los destinos que dependen de ellos.

El motivo del término "Make" es histórico: la sintaxis y semántica de estas variables originalmente iba a coincidir con GNU Make.

Usa

Los atributos marcados como "Subject to 'Make variable' sustitution" pueden hacer referencia a la variable "Make" FOO de la siguiente manera:

my_attr = "prefix $(FOO) suffix"

En otras palabras, cualquier substring que coincida con $(FOO) se expande al valor de FOO. Si ese valor es "bar", la última string se convierte en la siguiente:

my_attr = "prefix bar suffix"

Si FOO no corresponde a una variable conocida por el destino de consumo, Bazel falla con un error.

También se puede hacer referencia a las variables "Make" con nombres que no son letras, como @, con un signo de dólar, sin los paréntesis. Por ejemplo:

my_attr = "prefix $@ suffix"

Para escribir $ como un literal de string (es decir, para evitar la expansión de variables), escribe $$.

Variables predefinidas

Cualquier atributo marcado como "Subject to 'Make variable' sustitution" en cualquier destino puede hacer referencia a las variables predefinidas "Make".

Para ver la lista de estas variables y sus valores para un conjunto determinado de opciones de compilación, ejecuta

bazel info --show_make_env [build options]

y mira las líneas de salida superiores con mayúsculas.

Consulta un ejemplo de variables predefinidas.

Variables de opción de la cadena de herramientas

Variables de ruta de acceso

  • BINDIR: Es la base del árbol binario generado para la arquitectura de destino.

    Ten en cuenta que se puede usar un árbol diferente para los programas que se ejecutan durante la compilación en la arquitectura de host a fin de admitir la compilación cruzada.

    Si deseas ejecutar una herramienta desde un genrule, la forma recomendada de obtener su ruta de acceso es $(execpath toolname), donde toolname debe estar enumerado en el atributo tools de genrule.

  • GENDIR: Es la base del árbol de código generado para la arquitectura de destino.

Variables de arquitectura de máquinas

  • TARGET_CPU: La CPU de la arquitectura de destino, p.ej., k8.

Variables de genrule predefinidas

Los siguientes elementos están especialmente disponibles para el atributo cmd de genrule y, por lo general, son importantes para que ese atributo funcione.

Consulta un ejemplo de variables de genrule predefinidas.

  • OUTS: Es la lista outs de genrule. Si solo tienes un archivo de salida, también puedes usar $@.
  • SRCS: Es la lista srcs de genrule (o, más precisamente, los nombres de ruta de acceso de los archivos correspondientes a las etiquetas de la lista srcs). Si solo tienes un archivo de origen, también puedes usar $<.
  • <: Es SRCS, si se trata de un solo archivo. De lo contrario, se activará un error de compilación.
  • @: Es OUTS, si se trata de un solo archivo. De lo contrario, se activa un error de compilación.
  • RULEDIR: Es el directorio de salida del destino, es decir, el directorio correspondiente al nombre del paquete que contiene el destino en los árboles genfiles o bin. Para //my/pkg:my_genrule, esto siempre termina en my/pkg, incluso si los resultados de //my/pkg:my_genrule están en subdirectorios.

  • @D: Es el directorio de salida. Si outs tiene una entrada, se expande al directorio que contiene ese archivo. Si tiene varias entradas, se expande al directorio raíz del paquete en el árbol genfiles, incluso si todos los archivos de salida están en el mismo subdirectorio.

    Nota: Usa RULEDIR en lugar de @D, ya que RULEDIR tiene una semántica más simple y se comporta de la misma manera sin importar la cantidad de archivos de salida.

    Si la genrule necesita generar archivos intermedios temporales (quizás como resultado del uso de alguna otra herramienta, como un compilador), debe intentar escribirlos en @D (aunque /tmp también podrá escribirse) y quitarlos antes de finalizar.

    En especial, evita escribir en directorios que contengan entradas. Pueden estar en sistemas de archivos de solo lectura. Incluso si no, hacerlo destruiría el árbol fuente.

Variables predefinidas de la ruta de acceso fuente/salida

Las variables predefinidas execpath, execpaths, rootpath, rootpaths, location y locations toman parámetros de etiquetas (p.ej., $(execpath //foo:bar)) y sustituyen las rutas de acceso a archivos indicadas por esa etiqueta.

Para los archivos de origen, esta es la ruta de acceso relativa a la raíz de tu lugar de trabajo. Para los archivos que son resultados de reglas, esta es la ruta de salida del archivo (consulta la explicación de archivos de salida a continuación).

Consulta un ejemplo de variables de ruta de acceso predefinidas.

  • execpath: Denota la ruta debajo de execroot donde Bazel ejecuta acciones de compilación.

    En el ejemplo anterior, Bazel ejecuta todas las acciones de compilación en el directorio vinculado por el symlink bazel-myproject en la raíz de tu lugar de trabajo. El archivo fuente empty.source está vinculado en la ruta bazel-myproject/testapp/empty.source. Por lo tanto, su ruta de ejecución (que es la ruta secundaria debajo de la raíz) es testapp/empty.source. Esta es la acción de compilación de la ruta de acceso que pueden usar para encontrar el archivo.

    Los archivos de salida se almacenan en etapa intermedia de manera similar, pero también tienen el prefijo de la ruta secundaria bazel-out/cpu-compilation_mode/bin (o para los resultados de las herramientas: bazel-out/cpu-opt-exec-hash/bin). En el ejemplo anterior, //testapp:app es una herramienta porque aparece en el atributo tools de show_app_output. Por lo tanto, su archivo de salida app se escribe en bazel-myproject/bazel-out/cpu-opt-exec-hash/bin/testapp/app. Por lo tanto, la ruta de ejecución es bazel-out/cpu-opt-exec-hash/bin/testapp/app. Este prefijo adicional permite compilar el mismo destino para, por ejemplo, dos CPU diferentes en la misma compilación sin que los resultados generen una confusión entre sí.

    La etiqueta que se pasa a esta variable debe representar exactamente un archivo. En el caso de las etiquetas que representan archivos de origen, esto se aplica automáticamente. Para las etiquetas que representan reglas, la regla debe generar exactamente un resultado. Si esto es falso o la etiqueta tiene un formato incorrecto, la compilación fallará con un error.

  • rootpath: Denota la ruta de acceso que un objeto binario compilado puede usar para encontrar una dependencia en el entorno de ejecución relacionada con el subdirectorio del directorio de archivos de ejecución que corresponde al repositorio principal. Nota: Esta opción solo funciona si --enable_runfiles está habilitado, lo que no es el caso en Windows de forma predeterminada. Usa rlocationpath para obtener compatibilidad multiplataforma.

    Esto es similar a execpath, pero quita los prefijos de configuración descritos anteriormente. En el ejemplo anterior, esto significa que empty.source y app usan rutas de acceso relativas del lugar de trabajo puras: testapp/empty.source y testapp/app.

    El rootpath de un archivo en un repositorio externo repo comenzará con ../repo/, seguido de la ruta relativa del repositorio.

    Esto tiene los mismos requisitos de “un solo resultado” que execpath.

  • rlocationpath: Es la ruta de acceso que un objeto binario compilado puede pasar a la función Rlocation de una biblioteca de archivos de ejecución para encontrar una dependencia en el entorno de ejecución, ya sea en el directorio de archivos de ejecución (si está disponible) o mediante el manifiesto de archivos de ejecución.

    Es similar a rootpath, ya que no contiene prefijos de configuración, pero difiere en que siempre comienza con el nombre del repositorio. En el ejemplo anterior, esto significa que empty.source y app dan como resultado las siguientes rutas: myproject/testapp/empty.source y myproject/testapp/app.

    El rlocationpath de un archivo en un repositorio externo repo comenzará con repo/, seguido de la ruta relativa del repositorio.

    El método preferido para encontrar dependencias en el entorno de ejecución es pasar esta ruta de acceso a un objeto binario y resolverlo en una ruta de acceso del sistema de archivos con las bibliotecas de runfiles. En comparación con rootpath, tiene la ventaja de que funciona en todas las plataformas, incluso si el directorio runfiles no está disponible.

    Esto tiene los mismos requisitos de “un solo resultado” que execpath.

  • location: Es un sinónimo de execpath o rootpath, según el atributo que se expanda. Este es un comportamiento heredado previo a Starlark y no se recomienda, a menos que realmente sepas lo que hace para una regla en particular. Consulta #2475 para obtener más información.

execpaths, rootpaths, rlocationpaths y locations son las variantes plurales de execpath, rootpath, rlocationpaths y location, respectivamente. Admiten etiquetas que producen varias salidas, en cuyo caso cada resultado se enumera separado por un espacio. Las reglas sin salida y las etiquetas con formato incorrecto producen errores de compilación.

Todas las etiquetas a las que se hace referencia deben aparecer en el srcs, los archivos de salida o deps del destino de consumo. De lo contrario, la compilación fallará. Los destinos de C++ también pueden hacer referencia a etiquetas en data.

No es necesario que las etiquetas estén en formato canónica: las etiquetas foo, :foo y //somepkg:foo están bien.

Variables personalizadas

Se puede hacer referencia a las variables personalizadas de "Make" con cualquier atributo marcado como "Subject to 'Make variable' sustitution", pero solo en objetivos que dependen de otros objetivos que definen estas variables.

Como práctica recomendada, todas las variables deben ser personalizadas, a menos que haya una buena razón para integrarlas en el núcleo de Bazel. Esto evita que Bazel tenga que cargar dependencias potencialmente costosas para proporcionar variables que consuman tarets que podrían no interesarle.

Variables de la cadena de herramientas C++

Los siguientes se definen en las reglas de la cadena de herramientas de C++ y están disponibles para cualquier regla que establezca toolchains = ["@bazel_tools//tools/cpp:current_cc_toolchain"] (o "@bazel_tools//tools/cpp:current_cc_host_toolchain" para el equivalente de la cadena de herramientas del host). Algunas reglas, como java_binary, incluyen de manera implícita la cadena de herramientas de C++ en la definición de sus reglas. Heredan estas variables automáticamente.

Las reglas de C++ integradas son mucho más sofisticadas que "ejecutar el compilador en ellas". Para admitir modos de compilación tan diversos como *SAN, ThinLTO, con o sin módulos y objetos binarios cuidadosamente optimizados al mismo tiempo que las pruebas de ejecución rápida en varias plataformas, las reglas integradas hacen un gran esfuerzo para garantizar que las entradas, salidas y marcas de línea de comandos correctas se establezcan en cada una de las posibles acciones generadas internamente.

Estas variables son un mecanismo de resguardo para uso de expertos en idiomas en casos excepcionales. Si sientes la tentación de usarlas, primero comunícate con los desarrolladores de Bazel.

  • ABI: Es la versión de la ABI de C++.
  • AR: Es el comando "ar" de crosstool.
  • C_COMPILER: El identificador del compilador de C/C++, p.ej., llvm.
  • CC: Es el comando del compilador de C y C++.

    Te recomendamos que siempre uses CC_FLAGS junto con CC. No lo hagas bajo tu propia responsabilidad.

  • CC_FLAGS: Es un conjunto mínimo de marcas para que las genrules puedan usar el compilador C/C++. En particular, contiene marcas para seleccionar la arquitectura correcta si CC admite varias arquitecturas.
  • NM: Es el comando "nm" de crosstool.
  • OBJCOPY: El comando objcopy del mismo paquete que el compilador C/C++.
  • STRIP: Es el comando de eliminación del mismo paquete que el compilador C/C++.

Variables de la cadena de herramientas de Java

Los siguientes elementos se definen en las reglas de la cadena de herramientas de Java y están disponibles para cualquier regla que establezca toolchains = ["@bazel_tools//tools/jdk:current_java_runtime"] (o "@bazel_tools//tools/jdk:current_host_java_runtime" para el equivalente de la cadena de herramientas del host).

La mayoría de las herramientas del JDK no deben usarse directamente. Las reglas de Java integradas usan enfoques mucho más sofisticados para la compilación y el empaquetado de Java que los que pueden expresar las herramientas ascendentes, como los archivos JAR de interfaz, los de interfaz de encabezado y las implementaciones de combinación y empaquetado de archivos JAR altamente optimizados.

Estas variables son un mecanismo de resguardo para uso de expertos en idiomas en casos excepcionales. Si sientes la tentación de usarlas, primero comunícate con los desarrolladores de Bazel.

  • JAVA: Es el comando "java" (una máquina virtual Java). Evita esto y usa una regla java_binary en su lugar cuando sea posible. Puede ser una ruta de acceso relativa. Si debes cambiar de directorio antes de invocar a java, debes capturar el directorio de trabajo antes de cambiarlo.
  • JAVABASE: Es el directorio base que contiene las utilidades de Java. Puede ser una ruta de acceso relativa. Tendrá un subdirectorio “bin”.

Variables definidas por Starlark

Los escritores de reglas y cadenas de herramientas pueden definir variables completamente personalizadas mostrando un proveedor de TemplateVariableInfo. Cualquier regla que dependa de estas a través del atributo toolchains puede leer sus valores:

Consulta un ejemplo de variables definidas por Starlark.