Görünürlük

Bu sayfada, Bazel'in iki görünürlük sistemi olan hedef görünürlüğü ve yükleme görünürlüğü ele alınmaktadır.

Her iki görünürlük türü de diğer geliştiricilerin kitaplığınızın herkese açık API'si ile uygulama ayrıntıları arasında ayrım yapmasına ve çalışma alanınız büyüdükçe yapıyı zorunlu kılmaya yardımcı olur. Ayrıca, herkese açık bir API'nin desteğini sonlandırırken görünürlüğü kullanarak mevcut kullanıcılara izin verebilir, yeni kullanıcıları ise engelleyebilirsiniz.

Hedef görünürlüğü

Hedef görünürlüğü, hedefinizden kimlerin yararlanabileceğini (ör. deps gibi bir özellik içinde hedefinizin etiketini kimlerin kullanabileceğini) kontrol etmenizi sağlar.

Aynı paketteyse veya A, B'nin paketine görünürlük veriyorsa bir hedef A, hedef B tarafından görülebilir. Bu nedenle, erişime izin verilip verilmeyeceğine karar verirken paketler ayrıntı birimi olarak kullanılır. B, A öğesine bağlıysa ancak A, B öğesine görünmüyorsa B öğesini oluşturma girişimi analiz sırasında başarısız olur.

Bir pakete görünürlük verilmesinin, alt paketlerine görünürlük verilmesini sağlamadığını unutmayın. Paketler ve alt paketler hakkında daha fazla bilgi için Kavramlar ve terminoloji başlıklı makaleyi inceleyin.

Prototip oluşturma için --check_visibility=false işaretini ayarlayarak hedef görünürlüğü zorunluluğunu devre dışı bırakabilirsiniz. Bu işlem, gönderilen kodda üretim kullanımı için yapılmamalıdır.

Görünürlüğü kontrol etmenin birincil yolu, kural hedeflerindeki visibility özelliğini kullanmaktır. Bu bölümde, bu özelliğin biçimi ve bir hedefin görünürlüğünün nasıl belirleneceği açıklanmaktadır.

Görünürlük özellikleri

Tüm kural hedeflerinde, etiket listesi alan bir visibility özelliği bulunur. Her etiket aşağıdaki biçimlerden birine sahiptir. Son form hariç, bunlar herhangi bir gerçek hedefle eşleşmeyen yalnızca söz dizimsel yer tutuculardır.

  • "//visibility:public": Tüm paketlere erişim izni verir. (Başka bir spesifikasyonla birleştirilemez.)

  • "//visibility:private": Ek erişim izni vermez. Yalnızca bu paketteki hedefler bu hedefi kullanabilir. (Başka bir spesifikasyonla birleştirilemez.)

  • "//foo/bar:__pkg__": //foo/bar'ye (ancak alt paketlerine değil) erişim verir.

  • "//foo/bar:__subpackages__": //foo/bar ve doğrudan ya da dolaylı olarak tüm alt paketlerine erişim izni verir.

  • "//some_pkg:my_package_group": Belirtilen package_group kapsamında yer alan tüm paketlere erişim izni verir.

    • Paket grupları, paketleri belirtmek için farklı bir söz dizimi kullanır. Bir paket grubunda, "//foo/bar:__pkg__" ve "//foo/bar:__subpackages__" biçimleri sırasıyla "//foo/bar" ve "//foo/bar/..." ile değiştirilir. Benzer şekilde, "//visibility:public" ve "//visibility:private" yalnızca "public" ve "private"'dür.

Örneğin, //some/package:mytarget öğesinin visibility özelliği [":__subpackages__", "//tests:__pkg__"] olarak ayarlanmışsa bu öğe, //some/package/... kaynak ağacının parçası olan tüm hedefler ve //tests/BUILD içinde tanımlanan hedefler tarafından kullanılabilir ancak //tests/integration/BUILD içinde tanımlanan hedefler tarafından kullanılamaz.

En iyi uygulama: Aynı paket grubunun birden fazla hedefi görmesini sağlamak için listeyi her hedefin visibility özelliğinde tekrarlamak yerine package_group kullanın. Bu sayede okunabilirlik artar ve listelerin senkronizasyonunun bozulması önlenir.

Kural hedefi görünürlüğü

Bir kuralın hedef görünürlüğü:

  1. Ayarlanmışsa visibility özelliğinin değeri, aksi takdirde

  2. Hedefin BUILD dosyasındaki package ifadesinin default_visibility bağımsız değişkeninin değeri (böyle bir bildirim varsa) veya

  3. //visibility:private.

En iyi uygulama: default_visibility değerini herkese açık olarak ayarlamaktan kaçının. Prototip oluşturma veya küçük kod tabanlarında kullanışlı olabilir ancak kod tabanı büyüdükçe yanlışlıkla herkese açık hedefler oluşturma riski artar. Hangi hedeflerin bir paketin herkese açık arayüzünün parçası olduğu konusunda açık olmak daha iyidir.

Örnek

Dosya //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"],
)

Dosya //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",
    ],
)

Oluşturulan dosyanın hedef görünürlüğü

Oluşturulan dosya hedefi, kendisini oluşturan kural hedefiyle aynı görünürlüğe sahiptir.

Kaynak dosya hedef görünürlüğü

exports_files işlevini çağırarak bir kaynak dosya hedefinin görünürlüğünü açıkça ayarlayabilirsiniz. visibility exports_files işlevine herhangi bir bağımsız değişken iletilmediğinde görünürlük herkese açık hale gelir. exports_files, oluşturulan bir dosyanın görünürlüğünü geçersiz kılmak için kullanılamaz.

exports_files çağrısında görünmeyen kaynak dosyası hedefleri için görünürlük, --incompatible_no_implicit_file_export işaretinin değerine bağlıdır:

  • İşaret ayarlanırsa görünürlük gizli olur.

  • Aksi takdirde eski davranış geçerli olur: Görünürlük, BUILD dosyasının default_visibility ile aynıdır veya varsayılan görünürlük belirtilmemişse gizlidir.

Eski davranışa güvenmekten kaçının. Bir kaynak dosya hedefinin gizli olmayan görünürlüğe ihtiyacı olduğunda her zaman exports_files bildirim yazın.

En iyi uygulama: Mümkün olduğunda kaynak dosya yerine kural hedefi kullanın. Örneğin, .java dosyasında exports_files işlevini çağırmak yerine dosyayı gizli olmayan bir java_library hedefiyle sarmalayın. Genel olarak, kural hedefleri yalnızca aynı pakette bulunan kaynak dosyalara doğrudan referans vermelidir.

Örnek

Dosya //frobber/data/BUILD:

exports_files(["readme.txt"])

Dosya //frobber/bin/BUILD:

cc_binary(
  name = "my-program",
  data = ["//frobber/data:readme.txt"],
)

Yapılandırma ayarı görünürlüğü

Geçmişte Bazel, select() anahtarlarında referans verilen config_setting hedefleri için görünürlüğü zorunlu kılmıyordu. Bu eski davranışı kaldırmak için iki işaret vardır:

  • --incompatible_enforce_config_setting_visibility bu hedefler için görünürlük kontrolünü etkinleştirir. Taşımaya yardımcı olmak için visibility belirtilmeyen tüm config_setting öğelerinin herkese açık olarak kabul edilmesine de neden olur (paket düzeyindeki default_visibility'den bağımsız olarak).

  • --incompatible_config_setting_private_default_visibility visibility belirtmeyen config_setting'lerin, paketin default_visibility'ına uymasına ve diğer tüm kural hedefleri gibi özel görünürlüğe geri dönmesine neden olur. --incompatible_enforce_config_setting_visibility ayarlanmamışsa işlem yapılmaz.

Eski davranışa güvenmekten kaçının. Mevcut paket dışında kullanılmak üzere tasarlanan tüm config_setting, paket uygun bir default_visibility belirtmiyorsa açık bir visibility içermelidir.

Paket grubu hedef görünürlüğü

package_group hedeflerinin visibility özelliği yok. Bu yorumlar her zaman herkese açık olarak görünür.

Örtülü bağımlılıkların görünürlüğü

Bazı kuralların örtülü bağımlılıkları vardır. Bu bağımlılıklar, BUILD dosyasında açıkça belirtilmeyen ancak kuralın her örneğinde bulunan bağımlılıklardır. Örneğin, bir cc_library kuralı, kural hedeflerinin her birinden C++ derleyicisini temsil eden yürütülebilir bir hedefe örtülü bağımlılık oluşturabilir.

Bu tür bir örtülü bağımlılığın görünürlüğü, kuralın (veya yönün) tanımlandığı .bzl dosyasını içeren paketle ilgili olarak kontrol edilir. Örneğimizde, C++ derleyici cc_library kuralının tanımıyla aynı pakette bulunduğu sürece özel olabilir. Yedek olarak, tanımda örtülü bağımlılık görünmüyorsa cc_library hedefiyle ilgili olarak kontrol edilir.

--incompatible_visibility_private_attributes_at_definition seçeneğini devre dışı bırakarak bu davranışı değiştirebilirsiniz. Devre dışı bırakıldığında, örtülü bağımlılıklar diğer bağımlılıklar gibi değerlendirilir. Bu, bağımlı olunan hedefin (ör. C++ derleyicimiz) kuralın her örneği tarafından görülebilir olması gerektiği anlamına gelir. Uygulamada bu genellikle hedefin herkese açık olması gerektiği anlamına gelir.

Bir kuralın kullanımını belirli paketlerle kısıtlamak istiyorsanız bunun yerine load visibility'yi kullanın.

Yük görünürlüğü

Yükleme görünürlüğü, .bzl dosyasının diğer BUILD veya .bzl dosyalarından yüklenip yüklenemeyeceğini kontrol eder.

Hedef görünürlüğü, hedefler tarafından kapsüllenmiş kaynak kodu koruduğu gibi yük görünürlüğü de .bzl dosyaları tarafından kapsüllenmiş derleme mantığını korur. Örneğin, bir BUILD dosyasının yazarı, bazı tekrarlayan hedef tanımlarını .bzl dosyasındaki bir makroya dahil etmek isteyebilir. Yük görünürlüğü koruması olmadan, makrolarının aynı çalışma alanındaki diğer katılımcılar tarafından yeniden kullanıldığını görebilirler. Bu durumda, makroda yapılan değişiklikler diğer ekiplerin derlemelerini bozabilir.

.bzl dosyasının karşılık gelen bir kaynak dosya hedefi olabilir veya olmayabilir. Bu durumda, yük görünürlüğü ile hedef görünürlüğün aynı olacağı garanti edilmez. Yani, aynı BUILD dosyası .bzl dosyasını yükleyebilir ancak filegroup srcs'sında listelemeyebilir veya bunun tam tersi olabilir. Bu durum bazen doküman oluşturma veya test gibi kaynak kodu olarak .bzl dosyalarını kullanmak isteyen kurallar için sorunlara neden olabilir.

Prototip oluşturma için --check_bzl_visibility=false ayarını yaparak yükleme görünürlüğü zorunluluğunu devre dışı bırakabilirsiniz. --check_visibility=false ile aynı şekilde, gönderilen kod için bu işlem yapılmamalıdır.

Yük görünürlüğü, Bazel 6.0 sürümünden itibaren kullanılabilir.

Yük görünürlüğünü bildirme

.bzl dosyasının yükleme görünürlüğünü ayarlamak için dosyanın içinden visibility() işlevini çağırın. visibility() işlevinin bağımsız değişkeni, package_group öğesinin packages özelliği gibi bir paket özellikleri listesidir. Ancak visibility(), negatif paket spesifikasyonlarını kabul etmez.

visibility() çağrısı, dosya başına yalnızca bir kez, en üst düzeyde (bir işlevin içinde değil) ve ideal olarak load() ifadelerinden hemen sonra gerçekleşmelidir.

Hedef görünürlüğün aksine, varsayılan yükleme görünürlüğü her zaman herkese açıktır. visibility() işlevi çağrılmayan dosyalar, çalışma alanının herhangi bir yerinden her zaman yüklenebilir. Paket dışında kullanılmak üzere tasarlanmamış yeni .bzl dosyaların en üstüne visibility("private") eklemek iyi bir fikirdir.

Örnek

# //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

...

Yükleme görünürlüğü uygulamaları

Bu bölümde, yükleme görünürlüğü beyanlarını yönetmeyle ilgili ipuçları açıklanmaktadır.

Görünürlükleri faktörize etme

Birden fazla .bzl dosyasının aynı görünürlüğe sahip olması gerektiğinde paket özelliklerini ortak bir listede birleştirmek faydalı olabilir. Örneğin:

# //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)

...

Bu, çeşitli .bzl dosyalarının görünürlükleri arasında yanlışlıkla eğrilik oluşmasını önlemeye yardımcı olur. Ayrıca, clients listesi büyük olduğunda daha kolay okunur.

Oluşturma görünürlükleri

Bazen bir .bzl dosyasının, birden fazla küçük izin verilenler listesinden oluşan bir izin verilenler listesi tarafından görünür olması gerekebilir. Bu, bir package_group öğesinin includes özelliği aracılığıyla diğer package_group öğelerini dahil etmesine benzer.

Yaygın olarak kullanılan bir makroyu kullanımdan kaldırdığınızı varsayalım. Yalnızca mevcut kullanıcılar ve kendi ekibinizin sahip olduğu paketler tarafından görülebilmesini istiyorsanız. Şuna benzer bir mesaj yazabilirsiniz:

# //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)

Paket gruplarıyla yinelenenleri kaldırma

Hedef görünürlüğün aksine, yükleme görünürlüğünü package_group cinsinden tanımlayamazsınız. Hem hedef görünürlüğü hem de yük görünürlüğü için aynı izin verilenler listesini yeniden kullanmak istiyorsanız paket spesifikasyonları listesini, her iki tür bildirimin de başvurabileceği bir .bzl dosyasına taşımanız en iyisidir. Yukarıdaki Görünürlükleri hesaba katma bölümündeki örnekten yola çıkarak şunları yazabilirsiniz:

# //mylib/BUILD

load(":internal_defs", "clients")

package_group(
    name = "my_pkg_grp",
    packages = clients,
)

Bu yalnızca listede negatif paket belirtimi yoksa çalışır.

Tek tek simgeleri koruma

Adı alt çizgiyle başlayan Starlark sembolleri başka bir dosyadan yüklenemez. Bu sayede özel semboller oluşturmak kolaylaşır ancak bu sembolleri sınırlı sayıda güvenilir dosyayla paylaşmanıza izin verilmez. Diğer yandan, yük görünürlüğü, diğer paketlerin .bzl file öğenizi görmesini kontrol etmenizi sağlar ancak alt çizgi içermeyen sembollerin yüklenmesini engellemenize izin vermez.

Neyse ki ayrıntılı kontrol için bu iki özelliği birleştirebilirsiniz.

# //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

bzl-visibility Buildifier lint

Kullanıcılar, dosyaları internal veya private adlı bir dizinden yüklediğinde ve dosyaları bu dizinin üst dizini altında olmadığında uyarı veren bir Buildifier lint vardır. Bu lint, yükleme görünürlüğü özelliğinden önce oluşturulmuştur ve .bzl dosyalarının görünürlükleri bildirdiği çalışma alanlarında gereksizdir.