Visibilidad

Informar un problema Ver fuente Nightly · 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

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 la API pública de tu biblioteca y sus detalles de implementación, y a aplicar la estructura a medida que crece tu espacio de trabajo. También puedes usar la visibilidad cuando desactives una API pública para permitir a los usuarios actuales y rechazar a los nuevos.

Visibilidad del objetivo

La visibilidad del objetivo controla quién puede depender de tu objetivo, es decir, quién puede usar la etiqueta de tu objetivo 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 detalle para decidir si se permite o no el acceso. Si B depende de A, pero A no es visible para B, cualquier intento de compilar B fallará durante el 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 el atributo visibility en los objetivos de las reglas. 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 los destinos de este paquete pueden usar este destino. (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 forman parte de la package_group determinada.

    • Los grupos de paquetes usan una sintaxis diferente para especificar paquetes. Dentro de un grupo de paquetes, los formularios "//foo/bar:__pkg__" y "//foo/bar:__subpackages__" se reemplazan, respectivamente, por "//foo/bar" y "//foo/bar/...". Del mismo modo, "//visibility:public" y "//visibility:private" son solo "public" y "private".

Por ejemplo, si //some/package:mytarget tiene su visibility configurado en [":__subpackages__", "//tests:__pkg__"], cualquier destino que forme parte del árbol de origen //some/package/..., así como los destinos definidos en //tests/BUILD, podría usarlo, pero no los destinos definidos en //tests/integration/BUILD.

Práctica recomendada: Para que varios destinos sean visibles para el mismo conjunto de paquetes, usa un package_group en lugar de repetir la lista en el atributo visibility de cada 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:

  1. El valor de su atributo visibility, si está configurado

  2. El valor del argumento default_visibility de la sentencia package en el archivo BUILD del destino, si existe tal declaración; de lo contrario,

  3. //visibility:private.

Práctica recomendada: Evita establecer 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 objetivo 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 se pasa ningún argumento visibility a exports_files, la visibilidad se hace pública. No se puede usar exports_files para anular la visibilidad de un archivo generado.

En el caso de los destinos de archivos de origen que no aparecen en una llamada a exports_files, la visibilidad depende del valor de la marca --incompatible_no_implicit_file_export:

  • Si se establece la marca, la visibilidad es privada.

  • De lo contrario, se aplica el comportamiento heredado: la visibilidad es la misma que la default_visibility del archivo BUILD o privada si no se especifica una visibilidad predeterminada.

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, prefiere exponer un objetivo de regla en lugar de un 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 habilita la verificación de visibilidad para estos objetivos. Para ayudar con la migración, también hace que cualquier config_setting que no especifique un visibility se considere público (independientemente del default_visibility a nivel del paquete).

  • --incompatible_config_setting_private_default_visibility hace que los config_setting que no especifican un visibility respeten el default_visibility del paquete y recurran a la visibilidad privada, al igual que cualquier otro objetivo de regla. No realiza ninguna acción si no se establece --incompatible_enforce_config_setting_visibility.

Evita depender del comportamiento heredado. Cualquier config_setting que se use fuera del paquete actual debe tener un visibility explícito, si el paquete aún no especifica un default_visibility adecuado.

Visibilidad del objetivo del grupo de paquetes

Los objetivos de package_group no tienen un atributo visibility. Siempre son públicamente visibles.

Visibilidad de las dependencias implícitas

Algunas reglas tienen dependencias implícitas, que son dependencias que no se escriben en un archivo BUILD, pero que 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 sus destinos de reglas a un destino ejecutable que represente un compilador de C++.

Actualmente, para fines de visibilidad, estas dependencias implícitas se tratan como cualquier 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 carga controla si se puede cargar un archivo .bzl desde otros archivos BUILD o .bzl.

De la misma manera que la visibilidad del objetivo protege el código fuente que encapsulan los objetivos, la visibilidad de carga protege la lógica de compilación que encapsulan los archivos .bzl. Por ejemplo, el autor de un archivo BUILD podría querer considerar algunas definiciones de objetivos repetitivas en una macro en un archivo .bzl. Sin la protección de la visibilidad de carga, es posible que otros colaboradores vuelvan a usar su macro en el mismo espacio de trabajo, de modo que modificarla interrumpa las compilaciones de otros equipos.

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 carga y la visibilidad del objetivo coincidan. Es decir, el mismo archivo BUILD podría cargar el archivo .bzl, pero no incluirlo en el srcs de un filegroup o viceversa. Esto puede causar problemas en las reglas que desean consumir archivos .bzl como código fuente, por ejemplo, para la generación o prueba de documentación.

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, esto no se debe hacer para 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, de preferencia, inmediatamente después de las sentencias load().

A diferencia de la visibilidad del objetivo, la visibilidad de carga predeterminada siempre es pública. Los archivos que no llaman a visibility() siempre se pueden cargar desde cualquier lugar del espacio de trabajo. Es recomendable agregar visibility("private") a la parte superior de cualquier archivo .bzl nuevo 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 la forma en que un package_group puede incorporar otros package_group a través de su atributo includes.

Supongamos que darás de baja una macro que se usa con mucha frecuencia. Quieres que solo sea visible para los usuarios existentes y para los paquetes que pertenecen a 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 puedes 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

Cualquier símbolo de Starlark cuyo nombre comience con un guion bajo no se puede cargar desde 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