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, bağımlılıklarından birinin görünürlüğünü ihlal ederse analiz aşamasında oluşturulamaz.
Genel olarak, bir hedef A
ile hedef B
aynı konumdaysa veya A
, B
'nin konumuna görünürlük izni veriyorsa A
, B
'ye görünür olur. Sembolik makrolar olmadığında "konum" terimi yalnızca "paket" olarak basitleştirilebilir. Sembolik makrolar hakkında daha fazla bilgi için aşağıya bakın.
Görünürlük, izin verilen paketler listelenerek belirtilir. Bir pakete izin verilmesi, alt paketlerine de izin verileceği anlamına gelmez. 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ın visibility
özelliğini kullanmaktır.
Aşağıdaki alt bölümlerde, özelliğin biçimi, çeşitli hedef türlerine nasıl uygulanacağı ve görünürlük sistemi ile sembolik makrolar arasındaki etkileşim 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."//visibility:private"
: Ek erişim izni vermez. Yalnızca bu konum paketindeki hedefler bu hedefi kullanabilir."//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"
: Belirtilenpackage_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.
- Paket grupları, paketleri belirtmek için farklı bir söz dizimi kullanır. Bir paket grubunda,
Örneğin, //some/package:mytarget
öğesinin visibility
değeri [":__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 belirtilen 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.
En iyi uygulama: Başka bir ekibin projesine görünürlük izni verirken, bu proje geliştikçe ve yeni alt paketler eklendikçe gereksiz görünürlük değişikliklerinden kaçınmak için __pkg__
yerine __subpackages__
tercih edin.
Kural hedefi görünürlüğü
Bir kural hedefinin görünürlüğü, visibility
özelliği (verilmediyse uygun bir varsayılan değer) alınarak ve hedefin bildirildiği konum eklenerek belirlenir. Sembolik bir makroda belirtilmeyen hedefler için paket bir default_visibility
belirtiyorsa bu varsayılan değer kullanılır. Diğer tüm paketler ve sembolik bir makroda belirtilen hedefler için varsayılan değer yalnızca ["//visibility:private"]
'dir.
# //mypkg/BUILD
package(default_visibility = ["//friend:__pkg__"])
cc_library(
name = "t1",
...
# No visibility explicitly specified.
# Effective visibility is ["//friend:__pkg__", "//mypkg:__pkg__"].
# If no default_visibility were given in package(...), the visibility would
# instead default to ["//visibility:private"], and the effective visibility
# would be ["//mypkg:__pkg__"].
)
cc_library(
name = "t2",
...
visibility = [":clients"],
# Effective visibility is ["//mypkg:clients, "//mypkg:__pkg__"], which will
# expand to ["//another_friend:__subpackages__", "//mypkg:__pkg__"].
)
cc_library(
name = "t3",
...
visibility = ["//visibility:private"],
# Effective visibility is ["//mypkg:__pkg__"]
)
package_group(
name = "clients",
packages = ["//another_friend/..."],
)
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.
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.
# //mypkg/BUILD
java_binary(
name = "foo",
...
visibility = ["//friend:__pkg__"],
)
# //friend/BUILD
some_rule(
name = "bar",
deps = [
# Allowed directly by visibility of foo.
"//mypkg:foo",
# Also allowed. The java_binary's "_deploy.jar" implicit output file
# target the same visibility as the rule target itself.
"//mypkg:foo_deploy.jar",
]
...
)
Kaynak dosya hedef görünürlüğü
Kaynak dosya hedefleri, exports_files
kullanılarak açıkça tanımlanabilir veya bir kuralın etiket özelliğinde (sembolik makro dışında) dosya adına referans verilerek örtülü olarak oluşturulabilir. Kural hedeflerinde olduğu gibi, exports_files
çağrısının konumu veya giriş dosyasına başvuran BUILD dosyası her zaman dosyanın görünürlüğüne otomatik olarak eklenir.
exports_files
tarafından bildirilen dosyaların görünürlüğü, bu işlevin visibility
parametresiyle ayarlanabilir. Bu parametre verilmezse görünürlük herkese açık olur.
exports_files
çağrısında görünmeyen dosyaların görünürlüğü, --incompatible_no_implicit_file_export
işaretinin değerine bağlıdır:
İşaret doğruysa görünürlük gizlidir.
Aksi takdirde eski davranış geçerli olur: Görünürlük,
BUILD
dosyasınındefault_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çinvisibility
belirtilmeyen tümconfig_setting
öğelerinin herkese açık olarak kabul edilmesine de neden olur (paket düzeyindekidefault_visibility
'den bağımsız olarak).--incompatible_config_setting_private_default_visibility
visibility
belirtmeyenconfig_setting
'lerin, paketindefault_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.
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++ derleyicisi 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.
Bir kuralın kullanımını belirli paketlerle sınırlamak istiyorsanız bunun yerine load visibility'yi kullanın.
Görünürlük ve sembolik makrolar
Bu bölümde, görünürlük sisteminin sembolik makrolarla nasıl etkileşime girdiği açıklanmaktadır.
Sembolik makrolardaki konumlar
Görünürlük sisteminin önemli bir ayrıntısı, bir bildirimin konumunu nasıl belirlediğimizdir. Sembolik bir makroda beyan edilmeyen hedefler için konum, yalnızca hedefin bulunduğu pakettir (BUILD
dosyasının paketi).
Ancak sembolik bir makroda oluşturulan hedefler için konum, makronun tanımının (my_macro = macro(...)
ifadesi) göründüğü .bzl
dosyasını içeren pakettir. Bir hedef, iç içe yerleştirilmiş birden fazla hedef içinde oluşturulduğunda her zaman en içteki sembolik makronun tanımı kullanılır.
Belirli bir bağımlılığın görünürlüğünü kontrol etmek için hangi konumun kullanılacağını belirlemek üzere aynı sistem kullanılır. Tüketen hedef bir makro içinde oluşturulduysa tüketen hedefin bulunduğu pakete değil, en içteki makronun tanımına bakarız.
Bu, kodu aynı pakette tanımlanan tüm makroların otomatik olarak birbirinin "arkadaşı" olduğu anlamına gelir. //lib:defs.bzl
içinde tanımlanan bir makro tarafından doğrudan oluşturulan tüm hedefler, makroların gerçekte hangi paketlerde örneklendiğinden bağımsız olarak //lib
içinde tanımlanan diğer tüm makrolardan görülebilir. Aynı şekilde, //lib/BUILD
ve eski makrolarında doğrudan belirtilen hedefleri görebilir ve bu hedefler tarafından görülebilirler. Aynı pakette bulunan hedeflerden en az biri sembolik bir makro tarafından oluşturulmuşsa bu hedefler birbirini göremeyebilir.
Sembolik bir makronun uygulama işlevinde, visibility
parametresi, makronun çağrıldığı konum eklendikten sonra makronun visibility
özelliğinin etkin değerine sahiptir. Bir makronun hedeflerinden birini arayanına aktarmasının standart yolu, bu değeri hedef beyanına iletmektir (some_rule(..., visibility = visibility)
örneğinde olduğu gibi). Bu özelliği atlayan hedefler, makro tanımıyla aynı pakette olmadıkları sürece makroyu çağıran kişiye görünmez. Bu davranış, alt makrolara yapılan iç içe yerleştirilmiş çağrılar zincirinin her biri visibility = visibility
'yı geçirebileceği anlamında birleştirir. Bu durumda, iç makronun dışa aktarılan hedefleri, makroların uygulama ayrıntılarından herhangi birini göstermeden her düzeyde arayana yeniden dışa aktarılır.
Ayrıcalıkları bir alt makroya devretme
Görünürlük modelinde, bir makronun izinlerini alt makroya devretmesine olanak tanıyan özel bir özellik bulunur. Bu, makroların faktöriyel olarak hesaplanması ve oluşturulması için önemlidir.
Başka bir paketteki some_library
kuralını kullanarak bağımlılık kenarı oluşturan bir makronuz my_macro
olduğunu varsayalım:
# //macro/defs.bzl
load("//lib:defs.bzl", "some_library")
def _impl(name, visibility, ...):
...
native.genrule(
name = name + "_dependency"
...
)
some_library(
name = name + "_consumer",
deps = [name + "_dependency"],
...
)
my_macro = macro(implementation = _impl, ...)
# //pkg/BUILD
load("//macro:defs.bzl", "my_macro")
my_macro(name = "foo", ...)
//pkg:foo_dependency
hedefinde visibility
belirtilmediğinden yalnızca //macro
içinde görünür. Bu durum, tüketen hedef için sorun teşkil etmez. Peki //lib
yazarı, some_library
işlevini makro kullanarak uygulanacak şekilde yeniden düzenlerse ne olur?
# //lib:defs.bzl
def _impl(name, visibility, deps, ...):
some_rule(
# Main target, exported.
name = name,
visibility = visibility,
deps = deps,
...)
some_library = macro(implementation = _impl, ...)
Bu değişiklikle birlikte //pkg:foo_consumer
'nın konumu artık //macro
yerine //lib
olduğundan //pkg:foo_dependency
kullanımı, bağımlılığın görünürlüğünü ihlal ediyor. my_macro
yazarı, bu uygulama ayrıntısını çözmek için visibility = ["//lib"]
bağımlılık bildirimine iletmek zorunda kalmamalıdır.
Bu nedenle, bir hedefin bağımlılığı aynı zamanda hedefi bildiren makronun bir özellik değeri olduğunda, bağımlılığın görünürlüğünü tüketen hedefin konumu yerine makronun konumuna göre kontrol ederiz.
Bu örnekte, //pkg:foo_consumer
öğesinin //pkg:foo_dependency
öğesini görebildiğini doğrulamak için //pkg:foo_dependency
öğesinin my_macro
içindeki some_library
çağrısına giriş olarak da iletildiğini görüyoruz ve bunun yerine bağımlılığın görünürlüğünü bu çağrının konumu olan //macro
'e göre kontrol ediyoruz.
Bu işlem, bir hedef veya makro bildirimi, bağımlılığın etiketini etiket türünde özelliklerinden birinde alan başka bir sembolik makronun içinde olduğu sürece yinelemeli olarak tekrarlanabilir.
Sonlandırıcılar
Bir kural sonlandırıcıda (finalizer = True
ile sembolik bir makro) belirtilen hedefler, normal sembolik makro görünürlük kurallarına uyan hedefleri görmenin yanı sıra, sonlandırıcı hedefinin paketine görünür olan tüm hedefleri de görebilir.
Diğer bir deyişle, native.existing_rules()
tabanlı eski bir makroyu sonlandırıcıya taşırsanız sonlandırıcı tarafından bildirilen hedefler eski bağımlılıklarını görmeye devam edebilir.
Sonlandırıcıların native.existing_rules()
kullanarak inceleyebileceği ancak görünürlük sistemi kapsamında bağımlılık olarak kullanamayacağı hedefler tanımlamak mümkündür. Örneğin, makro tanımlı bir hedef kendi paketine veya sonlandırıcı makronun tanımına görünmüyorsa ve sonlandırıcıya devredilmemişse sonlandırıcı bu tür bir hedefi göremez. Ancak native.existing_rules()
tabanlı eski bir makronun da böyle bir hedefi göremeyeceğini unutmayın.
Yük görünürlüğü
Yükleme görünürlüğü, geçerli paketin dışındaki diğer BUILD
veya .bzl
dosyalarından bir .bzl
dosyasının 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
dosyasının yazarı, bazı tekrarlayan hedef bildirimlerini .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 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şamazsınız. 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.