Görünürlük

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

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ını ayırt etmesine 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 mevcut kullanıcılara izin verip yeni kullanıcıları engellemek için de görünürlüğü kullanabilirsiniz.

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.

Bir hedef A, aynı paketteyse veya A, B'nin paketine görünürlük veriyorsa 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 SDK'sına bağlıysa ancak A, B SDK'sına görünmüyorsa B SDK'sını oluşturma girişimleri 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 temel 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ç olmak üzere 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'e (ancak alt paketlerine değil) erişim izni verir.

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

  • "//some_pkg:my_package_group": Belirtilen package_group'ın parçası olan 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__" formları sırasıyla "//foo/bar" ve "//foo/bar/..." ile değiştirilir. Aynı ş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, onu 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 argümanı exports_files'ye 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 dosya 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 görünürlüğüyle 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 göstermeyi tercih edin. Ö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 hedefler 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 paketin 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.

Şu anda, görünürlük amacıyla bu örtülü bağımlılıklar diğer bağımlılıklar gibi ele alınır. 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 görünürlüğe sahip olması gerektiği anlamına gelir.

--incompatible_visibility_private_attributes_at_definition değerini ayarlayarak bu davranışı değiştirebilirsiniz. Etkinleştirildiğinde, söz konusu hedef yalnızca bunu örtülü bağımlılık olarak bildiren kural tarafından görülebilir. Yani, kuralın tanımlandığı .bzl dosyasını içeren pakette görünür olmalıdır. Örneğimizde, C++ derleyici, cc_library kuralının tanımıyla aynı pakette bulunduğu sürece özel olabilir.

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

.bzl dosyasının karşılık gelen bir kaynak dosyası 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 bölümünde listelemeyebilir veya bunun tam tersi olabilir. Bu durum, bazen doküman oluşturma veya test etme 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, bu işlem gönderilen kod için yapılmamalıdır.

Yük görünürlüğü, Bazel 6.0'dan 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 spesifikasyonları 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 yapılmalıdır.

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ük görünürlüğü uygulamaları

Bu bölümde, yük 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 dosyanı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.

Görünürlükleri oluşturma

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 yinelenen öğeleri kaldırma

Hedef görünürlüğün aksine, yük görünürlüğünü bir 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 taraftan, yük görünürlüğü, diğer paketlerin .bzl file öğenizi görme şekli üzerinde kontrol sahibi olmanızı 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'i

Kullanıcılar, dosyaları internal veya private adlı bir dizinden yüklediğinde ve dosyaları bu dizinin üst dizininin 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.