Bu sayfada Bazel'in iki görünürlük sistemi ele alınmaktadır: hedef görünürlük 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ı 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 mevcut kullanıcılara izin vermek ve yeni kullanıcıları reddetmek için de görünürlük özelliğini kullanabilirsiniz.
Hedef görünürlük
Hedef görünürlüğü, hedefinize bağlı olabilecek kullanıcıları (yani deps
gibi bir özellik içinde hedefinizin etiketini kullanabilecek kullanıcıları) kontrol eder. Bir hedef, bağımlılıklarından birinin görünürlüğünü ihlal ederse analiz aşamasında derlenemez.
Genellikle, aynı konumda olan veya A
, B
'nin konumuna görünürlük veren hedefler A
tarafından görülebilir.B
Sembol makroları olmadığında "konum" terimi yalnızca "paket" olarak basitleştirilebilir. Sembol makroları hakkında daha fazla bilgi için aşağıya bakın.
Görünürlük, izin verilen paketlerin listelenmesiyle 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.
Prototipleme için --check_visibility=false
işaretini ayarlayarak hedef görünürlüğü yaptırımını devre dışı bırakabilirsiniz. Gönderilen kodda üretim kullanımı için bu işlem yapılmamalıdır.
Görünürlüğü kontrol etmenin birincil 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, etiketlerin listesini alan bir visibility
özelliği bulunur. Her etiket aşağıdaki biçimlerden birine sahiptir. Son form hariç, bunlar gerçek bir hedefe karşılık gelmeyen söz dizimi yer tutucularıdır.
"//visibility:public"
: Tüm paketlere erişim izni verir."//visibility:private"
: Ek erişim izni vermez. Yalnızca bu konumun paketindeki hedefler bu hedefi kullanabilir."//foo/bar:__pkg__"
://foo/bar
'a erişim izni verir (ancak alt paketlerine erişim vermez)."//foo/bar:__subpackages__"
://foo/bar
'a ve doğrudan ve dolaylı tüm alt paketlerine erişim izni verir."//some_pkg:my_package_group"
: Belirtilenpackage_group
kapsamındaki 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. Benzer şekilde,"//visibility:public"
ve"//visibility:private"
,"public"
ve"private"
'tır.
- Paket grupları, paketleri belirtmek için farklı bir söz dizimi kullanır. Bir paket grubunda
Örneğin, //some/package:mytarget
'ün visibility
özelliği [":__subpackages__", "//tests:__pkg__"]
olarak ayarlanmışsa //some/package/...
kaynak ağacının parçası olan tüm hedeflerin yanı sıra //tests/BUILD
'te tanımlanan hedefler tarafından kullanılabilir ancak //tests/integration/BUILD
'te tanımlanan hedefler tarafından kullanılamaz.
En iyi uygulama: Birden fazla hedefi aynı paket grubuna görünür hale getirmek için her hedefin visibility
özelliğinde listeyi tekrarlamak yerine bir package_group
kullanın. Bu, okunabilirliği artırır ve listelerin senkronize olmasını önler.
En iyi uygulama: Başka bir ekibin projesine görünürlük verirken proje geliştikçe ve yeni alt paketler eklendikçe gereksiz görünürlük değişikliklerini önlemek için __pkg__
yerine __subpackages__
seçeneğini tercih edin.
Kural hedefi görünürlüğü
Kural hedefinin görünürlüğü, visibility
özelliği (veya verilmemişse uygun bir varsayılan değer) alınarak ve hedefin tanımlandığı konum eklenerek belirlenir. Sembolik makroda tanımlanmayan hedefler için pakette bir default_visibility
belirtilirse bu varsayılan değer kullanılır. Diğer tüm paketler ve sembolik makroda tanımlanan hedefler için varsayılan değer yalnızca ["//visibility:private"]
'tır.
# //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
'yi herkese açık olarak ayarlamamaya çalışın. Bu, 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. Bir paketin herkese açık arayüzünün hangi hedefleri içerdiği konusunda net olmak daha iyidir.
Oluşturulan dosya hedefi 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 adlarına atıfta bulunarak dolaylı olarak oluşturulabilir. Kural hedeflerinde olduğu gibi, exports_files
çağrısının konumu veya giriş dosyasına atıfta bulunan BUILD dosyası her zaman dosyanın görünürlüğüne otomatik olarak eklenir.
exports_files
tarafından tanımlanan dosyaların görünürlükleri, söz konusu işleve ait visibility
parametresi tarafından ayarlanabilir. Bu parametre belirtilmezse 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çi 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
ile aynıdır veya varsayılan bir 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 bir exports_files
beyanı 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
çağrısı yapmak yerine dosyayı özel olmayan bir java_library
hedefine sarmalayın. Kural hedefleri genellikle yalnızca aynı pakette bulunan kaynak dosyalara doğrudan referans vermelidir.
Örnek
//frobber/data/BUILD
dosyası:
exports_files(["readme.txt"])
//frobber/bin/BUILD
dosyası:
cc_binary(
name = "my-program",
data = ["//frobber/data:readme.txt"],
)
Yapılandırma ayarı görünürlüğü
Bazel geçmişte, select()
anahtarlarında referans verilen config_setting
hedefleri için görünürlüğü zorunlu kılmamıştır. Bu eski davranışı kaldırmak için iki işaret vardır:
--incompatible_enforce_config_setting_visibility
bu hedefler için görüntülenebilirlik kontrolünü etkinleştirir. Taşıma işlemine yardımcı olmak için,visibility
belirtmeyen tümconfig_setting
'lerin de herkese açık olarak kabul edilmesine neden olur (paket düzeyindekidefault_visibility
'den bağımsız olarak).--incompatible_config_setting_private_default_visibility
,visibility
belirtmeyenconfig_setting
'ların paketindefault_visibility
'ine uymasına ve diğer tüm kural hedeflerinde olduğu gibi gizli görünürlükte geriye dönük bir işlem yapmasına 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ılması amaçlanan tüm config_setting
öğelerinin açık bir visibility
değeri olmalıdır. Aksi takdirde, pakette uygun bir default_visibility
belirtilmemişse config_setting
öğesi geçersiz olur.
Paket grubu hedef görünürlüğü
package_group
hedeflerinin visibility
özelliği yok. Bu bilgiler her zaman herkese açıktır.
Örtük bağımlılıkların görünürlüğü
Bazı kurallarda örtülü bağımlılıklar bulunur. Bu bağımlılıklar, BUILD
dosyasında belirtilmez ancak söz konusu kuralın her örneğine özgüdür. Örneğin, bir cc_library
kuralı, kural hedeflerinin her biri ile C++ derleyicisini temsil eden bir yürütülebilir hedef arasında gizli bir bağımlılık oluşturabilir.
Bu tür bir örtülü bağımlığın görünürlüğü, kuralın (veya özelliğin) tanımlandığı .bzl
dosyasını içeren paketle ilgili olarak kontrol edilir. Örneğimizde, C++ derleyicisi cc_library
kuralı tanımı ile aynı pakette bulunduğu sürece özel olabilir. Yedek olarak, gizli bağımlılık tanımda görünmüyorsa cc_library
hedefiyle ilgili olarak kontrol edilir.
Bir kuralın kullanımını belirli paketlerle kısıtlamak istiyorsanız bunun yerine yük görünürlük özelliğini 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şimde bulunduğu açıklanmaktadır.
Sembolik makrolardaki konumlar
Görünürlük sisteminin önemli bir ayrıntısı, bir beyanın konumunu nasıl belirlediğimizdir. Sembolik makroda tanımlanmayan hedefler için konum, yalnızca hedefin bulunduğu pakettir (BUILD
dosyasının paketi).
Ancak sembolik makroda oluşturulan hedefler için konum, makronun tanımının (my_macro = macro(...)
ifadesi) yer aldığı .bzl
dosyasını içeren pakettir. Birden fazla iç içe yerleştirilmiş hedefin içinde bir hedef oluşturulduğunda her zaman en içteki sembolik makronun tanımı kullanılır.
Belirli bir bağımlılık için hangi konumun kontrol edileceğini belirlemek amacıyla da aynı sistem kullanılır. Tüketen hedef bir makro içinde oluşturulduysa, tüketen hedefin bulunduğu paket yerine en içteki makronun tanımına bakarız.
Bu, kodu aynı pakette tanımlanan tüm makroların otomatik olarak birbirleriyle "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 oluşturulduğundan bağımsız olarak //lib
içinde tanımlanan diğer tüm makrolardan görülebilir. Benzer şekilde, doğrudan //lib/BUILD
ve eski makrolarında tanımlanan hedefleri görebilir ve bu hedefler tarafından görülebilir. Buna karşılık, aynı pakette bulunan hedefler, en az biri sembolik bir makro tarafından oluşturulmuşsa birbirlerini göremeyebilir.
Sembolik bir makronun uygulama işlevinde visibility
parametresi, makronun çağrıldığı konumu ekledikten sonra makronun visibility
özelliğinin geçerli değerine sahiptir. Bir makronun, hedeflerinden birini arayan kullanıcıya aktarmasının standart yolu, bu değeri hedefin tanımına iletmektir (some_rule(..., visibility = visibility)
'te olduğu gibi). Bu özelliği atlayan hedefler, arayan makro tanımı ile aynı pakette olmadığı sürece makroyu çağıran kullanıcı tarafından görülemez. Bu davranış, alt makrolara yönelik iç içe yerleştirilmiş çağrı zincirinin her birinin visibility = visibility
değerini iletebileceği, makroların uygulama ayrıntılarının hiçbirini göstermeden iç makronun dışa aktarılan hedeflerini her düzeyde arayana yeniden aktaracağı anlamına gelir.
Ayrıcalıkları alt makroya verme
Görünürlük modelinde, bir makronun izinlerini alt makroya devretmesine olanak tanıyan özel bir özellik bulunur. Bu, makroları faktörlere ayırmak ve oluşturmak için önemlidir.
Başka bir paketteki some_library
kuralını kullanarak bağımlılık kenarı oluşturan bir my_macro
makronuz 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 sorunsuzdur. //lib
işlevinin yazarı, some_library
işlevini makro kullanılarak 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 //pkg:foo_consumer
'ın konumu //macro
yerine //lib
oldu. Bu nedenle //pkg:foo_dependency
'ın kullanımı, bağımlılık için görünürlük kuralını ihlal ediyor. my_macro
yazarının, yalnızca bu uygulama ayrıntısını atlatmak için visibility = ["//lib"]
'yi bağımlılık beyanına iletmesi beklenemez.
Bu nedenle, bir hedefin bağımlılığı aynı zamanda hedefi açıklayan makronun bir özellik değeri olduğunda, bağımlılığın görünürlüğünü kullanan hedefin konumu yerine makronun konumuna göre kontrol ederiz.
Bu örnekte, //pkg:foo_consumer
'ün //pkg:foo_dependency
'u görüp göremeyeceğini doğrulamak için //pkg:foo_dependency
'un my_macro
içindeki some_library
çağrısına giriş olarak da iletildiğini görüyoruz ve bunun yerine bağımlılık öğesinin görünürlüğünü bu çağrının konumu olan //macro
ile karşılaştırmalı olarak kontrol ediyoruz.
Bu işlem, hedef veya makro beyanı, etiket türündeki özelliklerinden birinde bağımlılık etiketini alan başka bir sembolik makronun içinde olduğu sürece yinelemeli olarak tekrarlanabilir.
Yük görünürlüğü
Yükleme görünürlüğü, bir .bzl
dosyasının mevcut paketin dışındaki diğer BUILD
veya .bzl
dosyalarından yüklenip yüklenemeyeceğini kontrol eder.
Hedef görünürlüğü, hedefler tarafından kapsüllenen kaynak kodu koruduğu gibi, yükleme görünürlüğü de .bzl
dosyaları tarafından kapsüllenen derleme mantığını korur. Örneğin, bir BUILD
dosyası yazarı, bazı tekrarlanan hedef beyanlarını .bzl
dosyasındaki bir makroya dahil etmek isteyebilir. Yükleme görünürlüğünün koruması olmadan, makrolarının aynı çalışma alanındaki diğer ortak çalışanlar tarafından yeniden kullanıldığını görebilirler. Bu durumda, makroda yapılan değişiklikler diğer ekiplerin derlemelerini bozar.
.bzl
dosyalarının karşılık gelen bir kaynak dosya hedefi olabileceğini veya olmayabileceğini unutmayın.
Bu durumda, yükleme görünürlüğünün ve hedef görünürlüğün aynı olacağı garanti edilmez. Yani aynı BUILD
dosyası .bzl
dosyasını yükleyebilir ancak filegroup
dosyasının srcs
bölümünde listeleyebilir veya bunun tam tersini yapabilir. Bu durum, bazen doküman oluşturma veya test etme gibi durumlarda .bzl
dosyalarını kaynak kod olarak kullanmak isteyen kurallarda sorunlara neden olabilir.
Prototipleme için --check_bzl_visibility=false
değerini ayarlayarak yükleme görünürlüğü yaptırımını devre dışı bırakabilirsiniz. --check_visibility=false
ile olduğu gibi, gönderilen kod için bu işlem yapılmamalıdır.
Yük görünürlüğü, Bazel 6.0'dan itibaren kullanılabilir.
Yük görünürlüğünü belirtme
Bir .bzl
dosyasının yükleme görünürlüğünü ayarlamak için dosya içinden visibility()
işlevini çağırın.
visibility()
bağımsız değişkeni, package_group
'in packages
özelliği gibi paket özelliklerinin bir listesidir. Ancak visibility()
, negatif paket özelliklerini kabul etmez.
visibility()
çağrısı, her dosya için yalnızca bir kez, üst düzeyde (bir işlevin içinde değil) ve ideal olarak load()
ifadelerinin hemen ardından 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()
çağrısı yapmayan dosyalar, çalışma alanının herhangi bir yerinden her zaman yüklenebilir. Özellikle paketin dışında kullanılmak üzere tasarlanmamış yeni .bzl
dosyalarının başına 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 çarpanlarına ayırma
Birden fazla .bzl
dosyasının aynı görünürlüğe sahip olması gerektiğinde, paket özelliklerini ortak bir listeye dahil etmek yararlı 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 kayma olmasını önlemeye yardımcı olur. Ayrıca, clients
listesi büyük olduğunda daha okunaklı olur.
Görünürlükleri birleştirme
Bazen bir .bzl
dosyasının, birden fazla küçük izin verilenler listesinden oluşan bir izin verilenler listesi tarafından görülebilmesi gerekebilir. Bu, bir package_group
'nin includes
özelliği aracılığıyla diğer package_group
'leri dahil etmesine benzer.
Yaygın olarak kullanılan bir makronun desteğini sonlandırdığınızı varsayalım. Yalnızca mevcut kullanıcılar ve kendi ekibinizin sahip olduğu paketler tarafından görülebilmesini istiyorsunuz. Şunu 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 tekilleştirme
Hedef görünürlüğün aksine, yükleme görünürlüğünü package_group
açısından tanımlayamazsınız. Hem hedef görünürlük hem de yükleme görünürlüğü için aynı izin verilenler listesini yeniden kullanmak istiyorsanız paket spesifikasyonlarının listesini, her iki tür beyanın da referans verebileceği bir .bzl dosyasına taşımak 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 işlem yalnızca liste negatif paket özellikleri içermiyorsa çalışır.
Tek tek simgelerin korunması
Adı alt çizgiyle başlayan Starlark sembolleri başka bir dosyadan yüklenemez. Bu, özel simgeler oluşturmayı kolaylaştırır ancak bu simgeleri sınırlı sayıda güvenilir dosyayla paylaşmanıza izin vermez. Öte yandan, yükleme görünürlüğü, diğer paketlerin .bzl file
'nizi görebileceği durumlar üzerinde kontrol sahibi olmanızı sağlar ancak alt çizgi içermeyen sembollerin yüklenmesini engellemenize izin vermez.
Neyse ki ayrıntılı denetim elde etmek 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ının dosyası söz konusu dizinin üst klasöründe değilken kullanıcılar internal
veya private
adlı bir dizinden dosya yüklerse uyarı veren bir Buildifier lint vardır. Bu lint, yükleme görünürlüğü özelliğinden öncedir ve .bzl
dosyalarının görünürlüğü tanımladığı çalışma alanlarında gereksizdir.