En esta página, se describen los dos sistemas de visibilidad de Bazel: visibilidad del objetivo y visibilidad de la carga.
Ambos tipos de visibilidad ayudan a otros desarrolladores a distinguir entre tus la API pública de la biblioteca y sus detalles de implementación, y ayudan a aplicar a medida que crece tu espacio de trabajo. También puedes usar la visibilidad cuando se da de baja una para permitir a los usuarios actuales y denegar los nuevos.
Visibilidad objetivo
La visibilidad del objetivo controla quién puede depender de tu objetivo, es decir, quién puede
usa la etiqueta de destino dentro de un atributo como deps
.
Un A
de destino es visible para un B
de destino si están en el mismo paquete o si
A
otorga visibilidad al paquete de B
. Por lo tanto, los paquetes son la unidad de
nivel de detalle para decidir si se permite o no el acceso. Si B
depende de A
pero A
no es visible para B
, entonces cualquier intento de compilar B
fallará durante
análisis.
Ten en cuenta que otorgar visibilidad a un paquete no otorga por sí mismo visibilidad a sus subpaquetes. Para obtener más información sobre los paquetes y subpaquetes, consulta Conceptos y terminología.
Para el prototipado, puedes inhabilitar la aplicación forzosa de la visibilidad del objetivo estableciendo la
marca --check_visibility=false
. Esto no se debería hacer para uso de producción en
código enviado.
La forma principal de controlar la visibilidad es con
Atributo visibility
activado
los objetivos de la regla. En esta sección, se describe el formato del atributo y cómo
determinar la visibilidad de un objetivo.
Especificaciones de visibilidad
Todos los destinos de la regla tienen un atributo visibility
que toma una lista de etiquetas. Cada
etiqueta tiene una de las siguientes formas. A excepción del último formato, estos
son solo marcadores de posición sintácticos que no corresponden a ningún objetivo real.
"//visibility:public"
: Otorga acceso a todos los paquetes. (No se puede combinar con cualquier otra especificación)."//visibility:private"
: No otorga ningún acceso adicional. solo objetivos incluidos en este paquete. (No se puede combinar con ninguna otra specification.)"//foo/bar:__pkg__"
: Otorga acceso a//foo/bar
(pero no a su subpaquetes)."//foo/bar:__subpackages__"
: Otorga acceso a//foo/bar
y a todos sus directos e indirectos."//some_pkg:my_package_group"
: Otorga acceso a todos los paquetes que son parte de lapackage_group
especificada.- Los grupos de paquetes usan un
sintaxis diferente para
especificar paquetes. Dentro de un grupo de paquetes, los formularios
"//foo/bar:__pkg__"
y"//foo/bar:__subpackages__"
son respectivamente se reemplaza por"//foo/bar"
y"//foo/bar/..."
. Del mismo modo,"//visibility:public"
y"//visibility:private"
son solo"public"
y"private"
.
- Los grupos de paquetes usan un
sintaxis diferente para
especificar paquetes. Dentro de un grupo de paquetes, los formularios
Por ejemplo, si //some/package:mytarget
tiene su visibility
establecido en
[":__subpackages__", "//tests:__pkg__"]
, lo puede usar cualquier destino
que es parte del árbol de fuentes de //some/package/...
, así como los destinos definidos
en //tests/BUILD
, pero no por objetivos definidos en //tests/integration/BUILD
.
Práctica recomendada: Si quieres que el mismo conjunto pueda ver varios destinos, sigue estos pasos:
de paquetes, usa un package_group
en lugar de repetir la lista en cada
atributo visibility
del destino. Esto aumenta la legibilidad y evita que
las listas no estén sincronizadas.
Visibilidad del objetivo de la regla
La visibilidad de un objetivo de regla es la siguiente:
El valor de su atributo
visibility
, si está configurado. o bienEl valor del
default_visibility
argumento de la sentenciapackage
en el archivoBUILD
del destino, si existe tal declaración; o bien//visibility:private
.
Práctica recomendada: Evita configurar default_visibility
como público. Puede ser
conveniente para el prototipado o en bases de código pequeñas, pero el riesgo de
La creación de objetivos públicos aumenta
a medida que crece la base de código. Es mejor estar
de forma explícita sobre qué destinos forman parte de la interfaz pública de un paquete.
Ejemplo
Archivo //frobber/bin/BUILD
:
# This target is visible to everyone
cc_binary(
name = "executable",
visibility = ["//visibility:public"],
deps = [":library"],
)
# This target is visible only to targets declared in the same package
cc_library(
name = "library",
# No visibility -- defaults to private since no
# package(default_visibility = ...) was used.
)
# This target is visible to targets in package //object and //noun
cc_library(
name = "subject",
visibility = [
"//noun:__pkg__",
"//object:__pkg__",
],
)
# See package group "//frobber:friends" (below) for who can
# access this target.
cc_library(
name = "thingy",
visibility = ["//frobber:friends"],
)
Archivo //frobber/BUILD
:
# This is the package group declaration to which target
# //frobber/bin:thingy refers.
#
# Our friends are packages //frobber, //fribber and any
# subpackage of //fribber.
package_group(
name = "friends",
packages = [
"//fribber/...",
"//frobber",
],
)
Visibilidad del destino del archivo generado
Un destino de archivo generado tiene la misma visibilidad que el objetivo de la regla que lo genera.
Visibilidad del objetivo del archivo de origen
Puedes configurar explícitamente la visibilidad de un destino de archivo de origen llamando
exports_files
Cuando no hay visibility
de estado se pasa a exports_files
, hace que la visibilidad sea pública.
No se puede usar exports_files
para anular la visibilidad de un archivo generado.
En el caso de los destinos del archivo de origen que no aparecen en una llamada a exports_files
, el elemento
La visibilidad depende del valor de la marca
--incompatible_no_implicit_file_export
:
Si la marca está configurada, la visibilidad es privada.
De lo contrario, se aplica el comportamiento heredado: la visibilidad es la misma que la
default_visibility
del archivoBUILD
, o privado si se establece la visibilidad predeterminada no especificado.
Evita confiar en el comportamiento heredado. Escribe siempre un exports_files
.
cuando el destino del archivo de origen necesita visibilidad no privada.
Práctica recomendada: Cuando sea posible, es preferible exponer el destino de la regla en lugar del
archivo fuente. Por ejemplo, en lugar de llamar a exports_files
en un archivo .java
,
une el archivo en un destino java_library
no privado. Por lo general, los objetivos de la regla
solo debe hacer referencia directamente a archivos de origen que se encuentren en el mismo paquete.
Ejemplo
Archivo //frobber/data/BUILD
:
exports_files(["readme.txt"])
Archivo //frobber/bin/BUILD
:
cc_binary(
name = "my-program",
data = ["//frobber/data:readme.txt"],
)
Visibilidad de los parámetros de configuración
Históricamente, Bazel no ha aplicado visibilidad para
config_setting
destinos que son
a las que se hace referencia en las claves de un select()
. Hay
hay dos marcas para quitar este comportamiento heredado:
--incompatible_enforce_config_setting_visibility
y habilita la verificación de visibilidad de estos objetivos. Para ayudar con la migración, también provoca que se muestre cualquierconfig_setting
que no especifique unvisibility
se considerará pública (independientemente deldefault_visibility
a nivel de paquete).--incompatible_config_setting_private_default_visibility
hace que losconfig_setting
que no especifiquen unvisibility
respeten eldefault_visibility
del paquete, y recurrir a la visibilidad privada, solo como cualquier otro objetivo de la regla. Es una no-op si No se estableció--incompatible_enforce_config_setting_visibility
.
Evita confiar en el comportamiento heredado. Cualquier config_setting
cuya finalidad sea
usarse fuera del paquete actual debe tener un visibility
explícito, si el
El paquete aún no especifica un default_visibility
adecuado.
Visibilidad del objetivo del grupo de paquetes
Los destinos de package_group
no tienen un atributo visibility
. Siempre son
públicamente visibles.
Visibilidad de dependencias implícitas
Algunas reglas tienen dependencias implícitas:
las dependencias que no se deletrean en un archivo BUILD
, pero son inherentes a
cada instancia de esa regla. Por ejemplo, una regla cc_library
podría crear una
dependencia implícita de cada uno de los objetivos de la regla a un destino ejecutable
que representan un compilador de C++.
Actualmente, por motivos de visibilidad, estas dependencias implícitas se tratan de la siguiente manera: ninguna otra dependencia. Esto significa que el objetivo del que se depende (como nuestro compilador C++) debe ser visible para cada instancia de la regla. En la práctica, esto generalmente significa que el destino debe tener visibilidad pública.
Para cambiar este comportamiento, configura
--incompatible_visibility_private_attributes_at_definition
Cuando se habilita, el
objetivo en cuestión solo deben ser visibles para la regla que lo declara implícita
dependencia. Es decir, debe ser visible para el paquete que contiene el .bzl
en el que se define la regla. En nuestro ejemplo, el compilador C++ podría ser
privada, siempre que se encuentre en el mismo paquete que la definición del
Regla cc_library
.
Visibilidad de la carga
La visibilidad de la carga controla si un archivo .bzl
se puede cargar desde otros
BUILD
o .bzl
.
De la misma manera que la visibilidad del objetivo protege el código fuente que está encapsulado
por los destinos, la visibilidad de carga protege la lógica de compilación que encapsula .bzl
archivos. Por ejemplo, el autor de un archivo BUILD
podría querer tener en cuenta algunos elementos
objetivo de las definiciones en una macro en un archivo .bzl
. Sin la protección de la carga
visibilidad, es posible que encuentren su macro reutilizada por otros colaboradores en la
mismo espacio de trabajo, por lo que modificar la macro interrumpe la experiencia compilaciones.
Ten en cuenta que un archivo .bzl
puede o no tener un destino de archivo de origen correspondiente.
Si es así, no hay garantía de que la visibilidad de la carga y el destino
la visibilidad coinciden. Es decir, el mismo archivo BUILD
podría cargar la
.bzl
, pero no en la lista del srcs
de un filegroup
,
o viceversa. Esto a veces puede causar problemas para las reglas que desean consumir
Archivos .bzl
como código fuente, por ejemplo, para la generación de documentación o las pruebas.
Para el prototipado, puedes inhabilitar la aplicación forzosa de la visibilidad de carga estableciendo
--check_bzl_visibility=false
Al igual que con --check_visibility=false
, este debe
el código enviado.
La visibilidad de la carga está disponible a partir de Bazel 6.0.
Cómo declarar la visibilidad de la carga
Para establecer la visibilidad de carga de un archivo .bzl
, llama al
visibility()
desde el archivo.
El argumento para visibility()
es una lista de especificaciones de paquete, como
el atributo packages
de
package_group
Sin embargo, visibility()
no acepta paquetes negativos.
y las especificaciones del servicio.
La llamada a visibility()
solo debe ocurrir una vez por archivo, en el nivel superior (no
dentro de una función) y, si es posible, inmediatamente después de las sentencias load()
.
A diferencia de la visibilidad de objetivos, la visibilidad de carga predeterminada siempre es pública. Archivos
que no llamen a visibility()
siempre se puedan cargar desde cualquier parte
Workspace. Se recomienda agregar visibility("private")
en la parte superior de cualquier
Un nuevo archivo .bzl
que no está diseñado específicamente para usarse fuera del paquete
Ejemplo
# //mylib/internal_defs.bzl
# Available to subpackages and to mylib's tests.
visibility(["//mylib/...", "//tests/mylib/..."])
def helper(...):
...
# //mylib/rules.bzl
load(":internal_defs.bzl", "helper")
# Set visibility explicitly, even though public is the default.
# Note the [] can be omitted when there's only one entry.
visibility("public")
myrule = rule(
...
)
# //someclient/BUILD
load("//mylib:rules.bzl", "myrule") # ok
load("//mylib:internal_defs.bzl", "helper") # error
...
Prácticas de visibilidad de la carga
En esta sección, se describen las sugerencias para administrar las declaraciones de visibilidad de carga.
Factorizar visibilidades
Cuando varios archivos .bzl
deben tener la misma visibilidad, puede ser útil
incluir sus especificaciones de paquetes en una lista común. Por ejemplo:
# //mylib/internal_defs.bzl
visibility("private")
clients = [
"//foo",
"//bar/baz/...",
...
]
# //mylib/feature_A.bzl
load(":internal_defs.bzl", "clients")
visibility(clients)
...
# //mylib/feature_B.bzl
load(":internal_defs.bzl", "clients")
visibility(clients)
...
Esto ayuda a evitar el sesgo accidental entre los diversos archivos .bzl
visibilidades. También es más legible cuando la lista clients
es grande.
Composición de visibilidad
En ocasiones, es posible que un archivo .bzl
deba ser visible para una lista de entidades permitidas que
compuesta por varias listas de entidades permitidas más pequeñas. Esto es similar a cómo un
package_group
puede incorporar otros elementos package_group
a través de su
includes
.
Supongamos que darás de baja una macro que se usa con mucha frecuencia. Quieres que solo sea visible. a los usuarios existentes y a los paquetes que son propiedad de tu propio equipo. Puedes escribir lo siguiente:
# //mylib/macros.bzl
load(":internal_defs.bzl", "our_packages")
load("//some_big_client:defs.bzl", "their_remaining_uses)
# List concatenation. Duplicates are fine.
visibility(our_packages + their_remaining_uses)
Anula la duplicación con grupos de paquetes
A diferencia de la visibilidad del objetivo, no se puede definir la visibilidad de una carga en términos de una
package_group
Si quieres reutilizar la misma lista de entidades permitidas para ambos
y de la carga, es mejor mover la lista de paquetes
específicas en un archivo .bzl, en el que ambos tipos de declaraciones pueden hacer referencia
que la modifica. Tomando como base el ejemplo de Factorizar visibilidades
arriba, podrías escribir:
# //mylib/BUILD
load(":internal_defs", "clients")
package_group(
name = "my_pkg_grp",
packages = clients,
)
Esto solo funciona si la lista no contiene ningún paquete negativo y las especificaciones del servicio.
Protección de símbolos individuales
No se puede cargar ningún símbolo de Starlark cuyo nombre comience con un guion bajo.
otro archivo. Esto facilita la creación de símbolos privados, pero no permite
que te permita compartir estos símbolos con un conjunto limitado de archivos de confianza. Del otro
La visibilidad de carga permite controlar qué otros paquetes pueden ver
.bzl file
, pero no te permite evitar que ningún símbolo que no tenga guion bajo la
que se está cargando.
Por suerte, puedes combinar estas dos funciones para obtener un control detallado.
# //mylib/internal_defs.bzl
# Can't be public, because internal_helper shouldn't be exposed to the world.
visibility("private")
# Can't be underscore-prefixed, because this is
# needed by other .bzl files in mylib.
def internal_helper(...):
...
def public_util(...):
...
# //mylib/defs.bzl
load(":internal_defs", "internal_helper", _public_util="public_util")
visibility("public")
# internal_helper, as a loaded symbol, is available for use in this file but
# can't be imported by clients who load this file.
...
# Re-export public_util from this file by assigning it to a global variable.
# We needed to import it under a different name ("_public_util") in order for
# this assignment to be legal.
public_util = _public_util
Lint de Buildifier de bzl-visibility
Hay un Lint de Buildifier.
que muestra una advertencia si los usuarios cargan un archivo desde un directorio llamado internal
o private
, cuando el archivo del usuario no está debajo del elemento superior
. Este lint es anterior a la función de visibilidad de carga y no es necesaria en
espacios de trabajo en los que los archivos .bzl
declaran visibilidades