このページでは、Bazel の 2 つの可視化システム(ターゲットの可視性と負荷の可視性)について説明します。
どちらの公開設定も、他のデベロッパーがライブラリの公開 API とその実装の詳細を区別するのに役立ち、ワークスペースの拡大に合わせて構造を強化するのに役立ちます。また、公開 API のサポートを終了する際に可視性を使用して、現在のユーザーを許可し、新しいユーザーを拒否することもできます。
ターゲットの可視性
ターゲットの公開設定は、ターゲットに依存するユーザー、つまり deps
などの属性内でターゲットのラベルを使用できるユーザーを制御します。
ターゲット A
がターゲット B
にある場合は、それらが同じパッケージ内にある場合、または A
が B
のパッケージに対する公開設定を許可している場合に表示されます。したがって、パッケージはアクセスを許可するかどうかを決定するための粒度単位です。B
が A
に依存しているが、A
が B
に表示されない場合、B
のビルドの試行はすべて分析中に失敗します。
パッケージに可視性を付与しても、そのサブパッケージに対する可視性は付与されないことに注意してください。パッケージとサブパッケージの詳細については、コンセプトと用語をご覧ください。
プロトタイピングでは、--check_visibility=false
フラグを設定することで、ターゲットの公開設定の適用を無効にできます。送信されたコードの本番環境で使用する場合は、この操作を行わないでください。
公開設定を制御する主な方法は、ルール ターゲットの visibility
属性です。このセクションでは、この属性の形式と、ターゲットの公開設定を決定する方法について説明します。
公開設定の仕様
すべてのルール ターゲットには、ラベルのリストを受け取る visibility
属性があります。各ラベルの形式は次のいずれかです。最後の形式を除き、これらは実際のターゲットに対応しない単なる構文プレースホルダです。
"//visibility:public"
: すべてのパッケージへのアクセスを許可します。(他の仕様と組み合わせることはできません)。"//visibility:private"
: 追加のアクセス権を付与しません。このパッケージ内のターゲットのみがこのターゲットを使用できます。(他の仕様と組み合わせることはできません)。"//foo/bar:__pkg__"
://foo/bar
へのアクセスを許可します(サブパッケージは付与しません)。"//foo/bar:__subpackages__"
://foo/bar
とそのすべての直接的および間接的なサブパッケージへのアクセスを許可します。"//some_pkg:my_package_group"
: 指定されたpackage_group
に含まれるすべてのパッケージへのアクセスを許可します。- パッケージ グループでは、パッケージを指定するために異なる構文を使用します。パッケージ グループ内では、フォーム
"//foo/bar:__pkg__"
と"//foo/bar:__subpackages__"
がそれぞれ"//foo/bar"
と"//foo/bar/..."
に置き換えられます。同様に、"//visibility:public"
と"//visibility:private"
は単に"public"
と"private"
です。
- パッケージ グループでは、パッケージを指定するために異なる構文を使用します。パッケージ グループ内では、フォーム
たとえば、//some/package:mytarget
の visibility
が [":__subpackages__", "//tests:__pkg__"]
に設定されている場合、//some/package/...
ソースツリーの一部であるターゲットや、//tests/BUILD
で定義されたターゲットで使用できますが、//tests/integration/BUILD
で定義されたターゲットでは使用できません。
ベスト プラクティス: 複数のターゲットを同じパッケージのセットに公開するには、各ターゲットの visibility
属性でリストを繰り返すのではなく、package_group
を使用します。これにより、可読性が向上し、リストの同期が失われるのを防ぐことができます。
ベスト プラクティス: 別のチームのプロジェクトに可視性を付与する場合は、__pkg__
よりも __subpackages__
を優先して、プロジェクトが進化して新しいサブパッケージを追加するときに不必要に可視性のチャーンが発生しないようにします。
ルール ターゲットの公開設定
ルール ターゲットの公開設定は次のとおりです。
visibility
属性の値(設定されている場合)。または、ターゲットの
BUILD
ファイル内にあるpackage
ステートメントのdefault_visibility
引数の値(そのような宣言が存在する場合)。//visibility:private
.
ベスト プラクティス: default_visibility
を公開に設定しないでください。プロトタイピングや小規模なコードベースでは便利ですが、コードベースが大きくなると、誤って公開ターゲットを作成するリスクが高くなります。どのターゲットがパッケージの公開インターフェースの一部であるかを明示することをおすすめします。
例
ファイル //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"],
)
ファイル //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",
],
)
生成されたファイル ターゲットの公開設定
生成されたファイル ターゲットは、それを生成したルール ターゲットと同じ公開設定になります。
ソースファイル ターゲットの公開設定
ソースファイル ターゲットの公開設定を明示的に設定するには、exports_files
を呼び出します。visibility
引数が exports_files
に渡されない場合、公開設定が公開されます。exports_files
を使用して、生成されたファイルの公開設定をオーバーライドすることはできません。
exports_files
の呼び出しに含まれていないソースファイル ターゲットの場合、可視性はフラグ --incompatible_no_implicit_file_export
の値によって異なります。
このフラグが設定されている場合、公開設定は非公開です。
それ以外の場合は、従来の動作が適用されます。公開設定は
BUILD
ファイルのdefault_visibility
と同じです。デフォルトの公開設定が指定されていない場合は非公開です。
従来の動作に依存しないでください。ソースファイルのターゲットで非公開以外の可視性が必要な場合は常に、exports_files
宣言を記述します。
ベスト プラクティス: 可能であれば、ソースファイルではなくルール ターゲットを公開してください。たとえば、.java
ファイルに対して exports_files
を呼び出すのではなく、非公開ではない java_library
ターゲットでファイルをラップします。一般に、ルールのターゲットは、同じパッケージ内にあるソースファイルを直接参照する必要があります。
例
ファイル //frobber/data/BUILD
:
exports_files(["readme.txt"])
ファイル //frobber/bin/BUILD
:
cc_binary(
name = "my-program",
data = ["//frobber/data:readme.txt"],
)
構成設定の公開設定
これまで、Bazel は、select()
のキーで参照されている config_setting
ターゲットに対して可視性を適用していませんでした。この従来の動作を削除するためのフラグが 2 つあります。
--incompatible_enforce_config_setting_visibility
は、これらのターゲットの公開設定チェックを有効にします。また、移行を容易にするため、visibility
を指定していないconfig_setting
は、(パッケージ レベルのdefault_visibility
に関係なく)公開と見なされます。--incompatible_config_setting_private_default_visibility
を使用すると、visibility
を指定していないconfig_setting
は、他のルール ターゲットと同様に、パッケージのdefault_visibility
を尊重し、非公開の公開設定にフォールバックします。--incompatible_enforce_config_setting_visibility
が設定されていない場合、何も行いません。
従来の動作に依存しないでください。パッケージで適切な default_visibility
をまだ指定していない場合は、現在のパッケージの外部で使用される config_setting
に明示的な visibility
を指定する必要があります。
パッケージ グループ ターゲットの公開設定
package_group
ターゲットには visibility
属性がありません。ログは常に一般公開されます。
暗黙的な依存関係の可視性
一部のルールには暗黙的な依存関係があります。これは、BUILD
ファイルでは指定されていませんが、そのルールのすべてのインスタンスに固有の依存関係です。たとえば、cc_library
ルールでは、各ルール ターゲットから、C++ コンパイラを表す実行可能ターゲットへの暗黙的な依存関係を作成できます。
このような暗黙的な依存関係の可視性は、ルール(またはアスペクト)が定義されている .bzl
ファイルを含むパッケージに関してチェックされます。この例では、cc_library
ルールの定義と同じパッケージ内にある限り、C++ コンパイラを非公開にできます。代わりに、暗黙的な依存関係が定義から見えない場合、cc_library
ターゲットに関してチェックされます。
ルールの使用を特定のパッケージに制限する場合は、代わりに読み込みの可視性を使用します。
負荷の可視性
読み込みの公開設定は、.bzl
ファイルを現在のパッケージ外の他の BUILD
ファイルまたは .bzl
ファイルから読み込めるかどうかを制御します。
ターゲットの公開設定がターゲットによってカプセル化されたソースコードを保護するのと同様に、読み込みの可視性は、.bzl
ファイルによってカプセル化されたビルドロジックを保護します。たとえば、BUILD
ファイルの作成者は、反復的なターゲット定義を .bzl
ファイルのマクロに分解できます。読み込みの可視性が保護されていないと、同じワークスペース内の他の共同編集者がマクロを再利用し、マクロを変更すると他のチームのビルドが中断される可能性があります。
.bzl
ファイルには、対応するソースファイルのターゲットが存在する場合と存在しない場合があります。設定されている場合、負荷の可視性とターゲットの可視性が一致する保証はありません。つまり、同じ BUILD
ファイルで .bzl
ファイルを読み込めても、filegroup
の srcs
にリストできないことがあります(その逆も同様です)。このため、ドキュメントの生成やテストなど、.bzl
ファイルをソースコードとして使用するルールで問題が発生することがあります。
プロトタイピングでは、--check_bzl_visibility=false
を設定することで、負荷の可視性の適用を無効にできます。--check_visibility=false
と同様に、送信されたコードに対してはこの操作を行わないでください。
負荷の可視性は、Bazel 6.0 以降で利用できます。
負荷の可視性の宣言
.bzl
ファイルの読み込み可視性を設定するには、ファイルから visibility()
関数を呼び出します。visibility()
の引数は、package_group
の packages
属性と同様に、パッケージ仕様のリストです。ただし、visibility()
ではネガティブ パッケージ指定は指定できません。
visibility()
の呼び出しは、ファイルごとにトップレベル(関数内ではない)で 1 回だけ行う必要があります。また、load()
ステートメントの直後に呼び出すのが理想的です。
ターゲットの公開設定とは異なり、デフォルトの負荷の公開設定は常に公開です。visibility()
を呼び出さないファイルは、常にワークスペースのどこからでも読み込めます。パッケージ外での使用を特に想定していない新しい .bzl
ファイルの先頭に、visibility("private")
を追加することをおすすめします。
例
# //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
...
負荷の可視性の実践
このセクションでは、負荷の可視性の宣言を管理するためのヒントについて説明します。
可視性の因数分解
複数の .bzl
ファイルの公開設定を同じにする必要がある場合は、パッケージ仕様を共通のリストにまとめると便利です。次に例を示します。
# //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)
...
これにより、さまざまな .bzl
ファイルの公開設定の間で意図しない歪みを防ぐことができます。また、clients
リストが大きい場合にも読みやすくなります。
作成時の公開設定
場合によっては、複数の小さな許可リストで構成される許可リストに対して .bzl
ファイルを表示する必要があります。これは、package_group
が includes
属性を介して他の package_group
を組み込む方法に似ています。
広く使用されているマクロを廃止するとします。既存のユーザーと自分のチームが所有するパッケージにのみ公開する必要があります。たとえば、次のように記述します。
# //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)
パッケージ グループによる重複排除
ターゲットの公開設定とは異なり、package_group
で負荷の可視性を定義することはできません。ターゲットの公開設定と読み込みの可視性の両方に同じ許可リストを再利用する場合は、パッケージ仕様のリストを .bzl ファイルに移動することをおすすめします。これにより、両方の種類の宣言で参照できます。前述の可視性の因数分解の例から、次のように作成できます。
# //mylib/BUILD
load(":internal_defs", "clients")
package_group(
name = "my_pkg_grp",
packages = clients,
)
これは、リストにネガティブ パッケージ仕様が含まれていない場合にのみ機能します。
個々のシンボルの保護
名前がアンダースコアで始まる Starlark シンボルは、別のファイルから読み込むことはできません。これにより、非公開シンボルを簡単に作成できますが、信頼できる一部のファイルとシンボルを共有することはできません。一方、読み込みの可視性では、他のパッケージで .bzl file
が認識される対象を制御できますが、アンダースコア以外の記号が読み込まれないようにすることはできません。
これら 2 つの機能を組み合わせることで、きめ細かい管理が可能です。
# //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
ユーザーのファイル自体がそのディレクトリの親の下にない場合に、ユーザーが internal
または private
という名前のディレクトリからファイルを読み込むと、Buildifier lint によって警告が表示されます。この lint は読み込みの可視性機能より前から存在しており、.bzl
ファイルで可視性を宣言するワークスペースでは不要です。