Nesta página, abordamos os dois sistemas de visibilidade do Bazel: visibilidade do destino e visibilidade do carregamento.
Ambos os tipos de visibilidade ajudam outros desenvolvedores a distinguir entre a API pública da biblioteca e os detalhes de implementação, além de ajudar a aplicar a estrutura à medida que seu espaço de trabalho aumenta. Também é possível usar a visibilidade ao suspender o uso de uma API para permitir os usuários atuais, mas negar os novos.
Visibilidade desejada
A visibilidade do público-alvo controla quem pode depender do público-alvo, ou seja, quem pode
use o rótulo do destino em um atributo, como deps
.
Um A
de destino fica visível para um B
de destino se eles estão no mesmo pacote ou se
A
concede visibilidade ao pacote de B
. Assim, os pacotes são a unidade
granularidade para decidir se o acesso será permitido ou não. Se B
depender de A
mas A
não estiver visível para B
, qualquer tentativa de criar B
falhará durante
análise.
Observe que conceder visibilidade a um pacote não concede visibilidade por si só aos subpacotes. Para mais detalhes sobre pacotes e subpacotes, consulte Conceitos e terminologia.
Para prototipagem, você pode desativar a aplicação da visibilidade de segmentação definindo a propriedade
sinalização --check_visibility=false
. Isso não deve ser feito para uso de produção em
código enviado.
A principal forma de controlar a visibilidade é com o
Atributo visibility
ativado
os destinos das regras. Esta seção descreve o formato desse atributo e como
determinar a visibilidade de um alvo.
Especificações de visibilidade
Todos os destinos de regras têm um atributo visibility
que aceita uma lista de rótulos. Cada
o rótulo tem uma das formas a seguir. Com exceção da última forma, esses
são apenas espaços reservados sintáticos que não correspondem a qualquer destino real.
"//visibility:public"
: concede acesso a todos os pacotes. (não pode ser combinado) com qualquer outra especificação.)"//visibility:private"
: não concede nenhum acesso adicional. somente destinos neste pacote podem usar esse destino. (não pode ser combinado com nenhum outro specification.)"//foo/bar:__pkg__"
: concede acesso a//foo/bar
(mas não a subpacotes)."//foo/bar:__subpackages__"
: concede acesso//foo/bar
e todos os subpacotes diretos e indiretos."//some_pkg:my_package_group"
: concede acesso a todos os pacotes que fazem parte dopackage_group
fornecido.- Os grupos de pacotes usam um
sintaxe diferente para
especificar pacotes. Em um grupo de pacotes, os formulários
"//foo/bar:__pkg__"
e"//foo/bar:__subpackages__"
são respectivamente substituído por"//foo/bar"
e"//foo/bar/..."
. Da mesma forma,"//visibility:public"
e"//visibility:private"
são apenas"public"
e"private"
.
- Os grupos de pacotes usam um
sintaxe diferente para
especificar pacotes. Em um grupo de pacotes, os formulários
Por exemplo, se //some/package:mytarget
tiver o visibility
definido como
[":__subpackages__", "//tests:__pkg__"]
, ela poderá ser usada por qualquer destino
que faz parte da árvore de origem do //some/package/...
, bem como os destinos definidos
em //tests/BUILD
, mas não por destinos definidos em //tests/integration/BUILD
.
Prática recomendada:tornar vários destinos visíveis para o mesmo conjunto.
de pacotes, use uma package_group
em vez de repetir a lista em cada
atributo visibility
do destino. Isso aumenta a legibilidade e evita que
dessincronizadas das listas.
Visibilidade da meta da regra
A visibilidade da meta de uma regra é:
O valor do atributo
visibility
, se definido. ou outroO valor do parâmetro
default_visibility
da instruçãopackage
no o arquivoBUILD
do destino, se essa declaração existir; ou outro//visibility:private
.
Prática recomendada:evite definir default_visibility
como pública. Podem ser
conveniente para prototipagem ou em pequenas bases de código, mas o risco de acabar
a criação de destinos públicos aumenta conforme a base de código aumenta. É melhor estar
explícito sobre quais destinos são parte da interface pública de um pacote.
Exemplo
Arquivo //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"],
)
Arquivo //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",
],
)
Visibilidade do destino do arquivo gerado
Uma segmentação de arquivo gerada tem a mesma visibilidade que a segmentação de regra que que o gera.
Visibilidade do destino do arquivo de origem
É possível definir explicitamente a visibilidade de um destino de arquivo de origem chamando
exports_files
Quando não há visibility
for transmitido para exports_files
, a visibilidade será pública.
exports_files
não pode ser usado para substituir a visibilidade de um arquivo gerado.
Para destinos de arquivo de origem que não aparecem em uma chamada para exports_files
, o
A visibilidade depende do valor do sinalizador
--incompatible_no_implicit_file_export
:
Se a flag for definida, a visibilidade será particular.
Caso contrário, o comportamento legado se aplica: a visibilidade é a mesma que a O atributo
default_visibility
do arquivoBUILD
ou particular se a visibilidade padrão for não especificado.
Evite confiar no comportamento legado. Sempre escreva um exports_files
.
sempre que um destino de arquivo de origem precisar de visibilidade não particular.
Prática recomendada:quando possível, prefira expor uma segmentação de regra em vez de
arquivo de origem. Por exemplo, em vez de chamar exports_files
em um arquivo .java
,
encapsular o arquivo em um destino java_library
não particular. Geralmente, as metas de regras
só podem referenciar diretamente arquivos de origem que estejam no mesmo pacote.
Exemplo
Arquivo //frobber/data/BUILD
:
exports_files(["readme.txt"])
Arquivo //frobber/bin/BUILD
:
cc_binary(
name = "my-program",
data = ["//frobber/data:readme.txt"],
)
Visibilidade da definição de configuração
Historicamente, o Bazel não aplica a visibilidade
config_setting
metas que estão
referenciadas nas chaves de um select()
.
Há duas sinalizações para remover esse comportamento legado:
--incompatible_enforce_config_setting_visibility
ativa a verificação de visibilidade para esses destinos. Para ajudar na migração, também faz com que qualquerconfig_setting
que não especifique umvisibility
seja considerado público, independente dodefault_visibility
no nível do pacote.--incompatible_config_setting_private_default_visibility
faz com que asconfig_setting
s que não especificam umvisibility
respeitem odefault_visibility
do pacote e para fallback na visibilidade privada, apenas como qualquer outra meta de regra. É um ambiente autônomo--incompatible_enforce_config_setting_visibility
não foi definido.
Evite confiar no comportamento legado. Qualquer config_setting
que se destina a
ser usada fora do pacote atual precisa ter um visibility
explícito, se o
ainda não especifica um default_visibility
adequado.
Visibilidade do destino do grupo de pacotes
Os destinos package_group
não têm um atributo visibility
. Eles são sempre
visíveis publicamente.
Visibilidade de dependências implícitas
Algumas regras têm dependências implícitas:
dependências que não são explicadas em um arquivo BUILD
, mas são inerentes a
cada instância dessa regra. Por exemplo, uma regra cc_library
pode criar uma
dependência implícita de cada um dos destinos de regra para um destino executável
que representam um compilador C++.
A visibilidade dessa dependência implícita é verificada em relação ao
pacote que contém o arquivo .bzl
em que a regra (ou aspecto) está definido. Em
Em nosso exemplo, o compilador C++ pode ser privado desde que esteja no mesmo
como a definição da regra cc_library
. Como alternativa, se o
dependência implícita não é visível na definição, ela é verificada com
em relação ao destino cc_library
.
Você pode alterar esse comportamento desativando
--incompatible_visibility_private_attributes_at_definition
Quando desativadas, as dependências implícitas são tratadas como qualquer outra dependência.
Isso significa que o destino de que depende (como nosso compilador C++) deve ser
fica visível para todas as instâncias da regra. Na prática, isso geralmente significa
precisam ter visibilidade pública.
Se você quiser restringir o uso de uma regra a determinados pacotes, use visibilidade do carregamento.
Visibilidade da carga
A visibilidade de carregamento controla se um arquivo .bzl
pode ser carregado de outro
arquivos BUILD
ou .bzl
.
Da mesma forma que a visibilidade do destino protege o código-fonte encapsulado,
por destinos, a visibilidade de carga protege a lógica de build encapsulada por .bzl
. Por exemplo, o autor de um arquivo BUILD
pode querer fatorar
definições de destino em uma macro em um arquivo .bzl
. Sem proteção contra cargas
visibilidade, eles poderão encontrar a macro reutilizada por outros colaboradores no
mesmo espaço de trabalho, de modo que a modificação da macro prejudica o trabalho builds.
Um arquivo .bzl
pode ou não ter um destino de arquivo de origem correspondente.
Se isso acontecer, não há garantia de que a visibilidade da carga e o valor
visibilidade dos dados coincidem. Ou seja, o mesmo arquivo BUILD
pode ser capaz de carregar o
.bzl
, mas não o listam no srcs
de um filegroup
.
ou vice-versa. Isso às vezes pode causar problemas para regras que querem consumir
Arquivos .bzl
como código-fonte, como para geração ou teste de documentação.
Para prototipagem, você pode desativar a aplicação da visibilidade de carga definindo
--check_bzl_visibility=false
: Assim como acontece com --check_visibility=false
, isso precisa ser
para o código enviado.
A visibilidade de carregamento está disponível a partir do Bazel 6.0.
Como declarar a visibilidade da carga
Para definir a visibilidade de carregamento de um arquivo .bzl
, chame o método
visibility()
no arquivo.
O argumento para visibility()
é uma lista de especificações de pacote, assim como
o atributo packages
do
package_group
. No entanto, visibility()
não aceita pacote negativo
especificações.
A chamada para visibility()
só deve ocorrer uma vez por arquivo, no nível superior (não
em uma função) e idealmente logo após as instruções load()
.
Ao contrário da visibilidade do destino, a visibilidade de carga padrão é sempre pública. Arquivos
que não chamam visibility()
são sempre carregáveis de qualquer lugar da
espaço de trabalho. Recomendamos adicionar visibility("private")
ao topo de qualquer
Novo arquivo .bzl
que não se destina especificamente para uso fora do pacote.
Exemplo
# //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áticas de visibilidade de carregamento
Esta seção descreve dicas para gerenciar declarações de visibilidade de carga.
Visibilidades de fatoração
Quando vários arquivos .bzl
precisam ter a mesma visibilidade, pode ser útil
incluem as especificações dos pacotes
em uma lista comum. Exemplo:
# //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)
...
Isso ajuda a evitar desvios acidentais entre os vários arquivos .bzl
.
visibilidades. Também é mais legível quando a lista de clients
é grande.
Visibilidades de composição
Às vezes, um arquivo .bzl
pode precisar ficar visível para uma lista de permissões
composto por várias listas de permissões menores. Isso é análogo à forma como um
O package_group
pode incorporar outros package_group
s usando o
includes
.
Suponha que você esteja descontinuando uma macro amplamente utilizada. Você quer que ela seja apenas visível aos usuários atuais e aos pacotes que pertencem à sua equipe. Você pode escrever:
# //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)
Eliminação de duplicação com grupos de pacotes
Diferentemente da visibilidade do alvo, não é possível definir uma visibilidade da carga em termos de um
package_group
: Se você quiser reutilizar a mesma lista de permissões para os dois destinos
visibilidade de carregamento e de carga, é melhor mover a lista de pacotes
especificações em um arquivo .bzl, no qual ambos os tipos de declarações podem se referir a
reimplantá-lo. Com base no exemplo em Visibilidades de fatoração
acima, você pode escrever:
# //mylib/BUILD
load(":internal_defs", "clients")
package_group(
name = "my_pkg_grp",
packages = clients,
)
Isso só funciona se a lista não tiver pacotes negativos especificações.
Proteção de símbolos individuais
Qualquer símbolo Starlark cujo nome comece com um sublinhado não possa ser carregado de
outro arquivo. Isso facilita a criação de símbolos privados, mas não permite
que você compartilhe esses símbolos com um conjunto limitado de arquivos confiáveis. No outro
a visibilidade de carga dá a você controle sobre quais outros pacotes podem ver seu
.bzl file
, mas não permite que você impeça que qualquer símbolo não sublinhado seja
que está sendo carregado.
Felizmente, você pode combinar esses dois recursos para obter um controle refinado.
# //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 do Buildifier bzl-visibilidade
Há um lint do Buildifier.
que forneça um aviso se os usuários carregarem um arquivo de um diretório chamado internal
ou private
, quando o arquivo do usuário não está abaixo do pai desse
diretório. Esse lint é anterior ao recurso de visibilidade de carregamento e é desnecessário no
espaços de trabalho em que arquivos .bzl
declaram visibilidades.