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ü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ını ayırt etmesine ve çalışma alanınız büyüdükçe yapıyı zorunlu kılmaya yardımcı olur. Mevcut kullanıcılara izin verirken yeni kullanıcıları reddetmek için herkese açık bir API'yi kullanımdan kaldırırken de görünürlüğü kullanabilirsiniz.

Hedef görünürlüğü

Hedef görünürlüğü, hedefinize bağlı olabilecek kişileri (yani hedefinizin etiketini deps gibi bir özellik içinde kimlerin kullanabileceğini) kontrol eder.

Bir hedef A, bir B hedefi aynı paket içindeyse veya A, B paketine görünürlük sağlıyorsa bu hedef tarafından görülebilir. Bu nedenle paketler, erişime izin verilip verilmeyeceğine karar verirken kullanılan ayrıntı birimidir. B, A bağımlıysa ancak A, B tarafından görünmüyorsa analiz sırasında B derleme denemeleri başarısız olur.

Bir pakete görünürlük sağlamanın, tek başına alt paketlerine de görünürlük sağlamadığını unutmayın. Paket ve alt paketler hakkında daha fazla bilgi için Kavramlar ve terminoloji bölümüne bakın.

Prototip oluşturma için --check_visibility=false işaretini ayarlayarak hedef görünürlüğü uygulamasını 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 hedefleri, etiketler listesini alan bir visibility özelliğine sahip. Her etiket aşağıdaki biçimlerden birine sahiptir. Son biçim haricinde, bunlar yalnızca herhangi bir gerçek hedefe karşılık gelmeyen söz dizimi yer tutucularıdır.

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

  • "//visibility:private": Herhangi bir ek erişim izni vermez. Yalnızca bu paketteki hedefler bu hedefi kullanabilir. (Diğer spesifikasyonlarla birleştirilemez.)

  • "//foo/bar:__pkg__": //foo/bar için erişim izni verir (ancak alt paketlerine erişim izni vermez).

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

  • "//some_pkg:my_package_group": Belirtilen package_group öğesinin 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. Benzer bir şekilde, "//visibility:public" ve "//visibility:private" yalnızca "public" ve "private"'dir.

Örneğin, //some/package:mytarget için visibility değeri [":__subpackages__", "//tests:__pkg__"] olarak ayarlanmışsa bu öğe, //some/package/... kaynak ağacının parçası olan herhangi bir hedefin yanı sıra //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: Birkaç hedefi aynı paket grubuna görünür hale getirmek için her bir hedefin visibility özelliğinde listeyi tekrarlamak yerine bir package_group kullanın. Bu, okunabilirliği artırır ve listelerin senkronize olmasını önler.

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

Bir kural hedefinin görünürlüğü şudur:

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

  2. Böyle bir beyan varsa hedefin BUILD dosyasındaki package ifadesinin default_visibility bağımsız değişkeni değeri veya

  3. //visibility:private.

En iyi uygulama: default_visibility ayarını herkese açık olarak ayarlamaktan kaçının. Bu yöntem, prototip oluşturmak veya küçük kod tabanlarında kullanım için elverişli olabilir. Ancak kod tabanı büyüdükçe, yanlışlıkla herkese açık hedefler oluşturma riski de artar. Hangi hedeflerin, paketin herkese açık arayüzünün parçası olduğunu açıkça belirtmek daha iyidir.

Örnek

//frobber/bin/BUILD dosyası:

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

//frobber/BUILD dosyası:

# 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 dosya hedefi görünürlüğü

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

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

exports_files yöntemini çağırarak kaynak dosya hedefinin görünürlüğünü açık bir şekilde ayarlayabilirsiniz. exports_files için hiçbir visibility bağımsız değişkeni 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, işaretin --incompatible_no_implicit_file_export değerine bağlıdır:

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

  • Diğer durumlarda eski davranış geçerlidir: Görünürlük BUILD dosyasının default_visibility özelliğiyle aynıdır veya varsayılan görünürlük belirtilmezse gizli olur.

Eski davranışa güvenmekten kaçının. Kaynak dosya hedefinin gizli olmayan görünürlüğe ihtiyacı olduğunda her zaman bir exports_files bildirimi 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 öğesini çağırmak yerine dosyayı gizli olmayan bir java_library hedefi içinde sarmalayın. Genel olarak, kural hedefleri yalnızca aynı pakette bulunan kaynak dosyalarına doğrudan başvuruda bulunmalıdır.

Ö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üğü

Geçmişte Bazel, select() anahtarlarında başvurulan config_setting hedefleri için görünürlük zorunlu tutmadı. Bu eski davranışı kaldırmanın iki işareti vardır:

  • --incompatible_enforce_config_setting_visibility, bu hedefler için görünürlük kontrolünü etkinleştirir. Bu işlem, taşımaya yardımcı olmak amacıyla, bir visibility belirtmeyen config_setting öğelerinin herkese açık olarak kabul edilmesine de neden olur (paket düzeyinde default_visibility ne olursa olsun).

  • --incompatible_config_setting_private_default_visibility, visibility belirtmeyen config_setting öğelerinin, paketin default_visibility politikasına uymasına ve diğer kural hedeflerinde olduğu gibi gizli görünürlük ayarına dönmesine neden olur. --incompatible_enforce_config_setting_visibility ayarlanmazsa işlem yapılamaz.

Eski davranışa güvenmekten kaçının. Mevcut paketin dışında kullanılması amaçlanan herhangi bir config_setting, pakette zaten uygun bir default_visibility belirtilmiyorsa açık bir visibility içermelidir.

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

package_group hedeflerinde visibility özelliği yok. Bu dosyalar her zaman her zaman görünür durumdadır.

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

Bazı kuralların dolaylı bağımlılıkları vardır. Bunlar bir BUILD dosyasında yazılmamış olan ancak söz konusu kuralın her örneğinde yerleşik olan bağımlılıklardır. Örneğin bir cc_library kuralı, kural hedeflerinin her birinden bir C++ derleyicisini temsil eden yürütülebilir bir hedefe yönelik örtülü bir bağımlılık oluşturabilir.

Şu anda, görünürlük amacıyla bu dolaylı bağımlılıklar diğer herhangi bir bağımlılık gibi ele alınmaktadır. Bu, bağımlı olan hedefin (ör. C++ derleyicimiz) kuralın her örneğinde görünür olması gerektiği anlamına gelir. Pratikte bu, genellikle hedefin herkes tarafından görülebilir olması gerektiği anlamına gelir.

--incompatible_visibility_private_attributes_at_definition ayarını yaparak bu davranışı değiştirebilirsiniz. Etkinleştirildiğinde, söz konusu hedefin yalnızca örtülü bağımlılık olduğunu belirten kural tarafından görülebilmesi gerekir. Yani, kuralın tanımlandığı .bzl dosyasını içeren paket tarafından görülebilmelidir. Örneğimizde C++ derleyicisi, cc_library kuralının tanımıyla aynı pakette olduğu sürece gizli olabilir.

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

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

Hedef görünürlüğün, hedefler tarafından kapsüllenmiş kaynak kodunu koruduğu gibi, yük görünürlüğü de .bzl dosyaları tarafından içine alınan derleme mantığını korur. Örneğin bir BUILD dosyasının yazarı, .bzl dosyasındaki bazı tekrarlanan hedef tanımlarını bir makroya dahil etmek isteyebilir. Yük görünürlüğünün korunması olmadan, makrolarının aynı çalışma alanındaki diğer ortak çalışanlar tarafından yeniden kullanıldığını bulabilirler. Bu nedenle, makronun değiştirilmesi diğer ekiplerin derlemelerini bozar.

Bir .bzl dosyasının karşılık gelen bir kaynak dosya hedefine sahip olabileceğini veya olmayabileceğini unutmayın. Eşleşirse yük görünürlüğünün ve hedef görünürlüğün çakışacağı garanti edilmez. Diğer bir deyişle, aynı BUILD dosyası .bzl dosyasını yükleyebilir ancak bir filegroup öğesinin srcs içinde (veya tam tersi) listeleyemez. Bu durum, doküman oluşturma veya test etme gibi kaynak kodu olarak .bzl dosyalarını kullanmak isteyen kurallar için bazen sorunlara yol açabilir.

Prototip oluşturma için --check_bzl_visibility=false değerini ayarlayarak yük görünürlüğünün zorunlu kılınmasını devre dışı bırakabilirsiniz. --check_visibility=false işleminde olduğu gibi, gönderilen kod için bu yapılmamalıdır.

Yük görünürlüğü Bazel 6.0'dan itibaren mevcuttur.

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

Bir .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() bağımsız değişkeni, package_group öğesinin packages özelliği gibi, paket özelliklerinin listesidir. Ancak visibility(), negatif paket özelliklerini 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() ifadelerinin hemen ardından 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() çağırmayan dosyalar her zaman çalışma alanındaki herhangi bir yerden yüklenebilir. Özel olarak paket dışında kullanılmak üzere tasarlanmamış yeni .bzl dosyalarını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

...

Görünürlük uygulamalarını yükle

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 çarpanlarına ayırma

Birden fazla .bzl dosyasının aynı görünürlüğe sahip olması gerektiğinde paket özelliklerini ortak bir liste halinde eklemek 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 sapmaları önlemeye yardımcı olur. Ayrıca, clients listesi geniş olduğunda daha okunabilir olur.

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

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

Yaygın olarak kullanılan bir makroyu kullanımdan kaldırdığınızı varsayalım. Yalnızca mevcut kullanıcılara ve kendi ekibinize ait paketlere görünür olmasını istiyorsunuz. Şunları 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 çoğaltma

Hedef görünürlüğün aksine, yük görünürlüğünü package_group terimleriyle 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 özellikleri listesini, her iki bildirim türünün de referans gösterebileceği bir .bzl dosyasına taşımanız önerilir. Yukarıdaki Görünürlükleri göz önünde bulundurma bölümündeki örneği derleyerek aşağıdakileri yazabilirsiniz:

# //mylib/BUILD

load(":internal_defs", "clients")

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

Bu yalnızca liste herhangi bir negatif paket spesifikasyonu içermiyorsa işe yarar.

Bağımsız sembolleri koruma

Adı alt çizgiyle başlayan Starlark sembolleri başka bir dosyadan yüklenemez. Bu işlem, gizli sembolleri 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ük görünürlüğü, diğer paketlerin .bzl file öğesini görebileceklerini kontrol etmenizi sağlar ancak alt çizgisiz simgelerin yüklenmesini engellemenize izin vermez.

Neyse ki daha hassas bir denetime sahip olmak 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-görünürlük Bücre lint

Kullanıcılar internal veya private adlı bir dizinden dosya yüklerse ve kullanıcı dosyasının kendisi o dizinin üst öğesinin altında değilse uyarı veren bir Buildifier lint bulunur. Bu lint, yükleme görünürlüğü özelliğinden eskidir ve .bzl dosyalarının görünürlük bildirdiği çalışma alanlarında gerekli değildir.