可視性

このページでは、Bazel の 2 つの公開設定システム( ターゲットの公開設定読み込みの公開設定)について説明します。

どちらのタイプの公開設定も、ライブラリの公開 API と実装の詳細を区別するのに役立ち、ワークスペースの拡大に伴って構造を強化するのに役立ちます。また、公開 API を非推奨にする際に、現在のユーザーを許可しながら新しいユーザーを拒否するために、公開設定を使用することもできます。

ターゲットの公開設定

ターゲットの公開設定 は、ターゲットに依存できるユーザー( `deps` などの属性内でターゲットのラベルを使用できるユーザー)を制御します。depsターゲットが依存関係のいずれかの公開設定に違反している場合、分析フェーズでビルドに失敗します。

通常、ターゲット A は、ターゲット B と同じ 場所にある場合、または AB's の場所に公開設定を付与する場合に、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:mytargetvisibility[":__subpackages__", "//tests:__pkg__"] に設定されている場合、//some/package/... ソースツリーの一部であるターゲットと //tests/BUILD で宣言されたターゲットで使用できますが、 //tests/integration/BUILD で定義されたターゲットでは使用できません。

ベスト プラクティス: 同じパッケージ セット に対して複数のターゲットを表示するには、各 ターゲットの visibility 属性でリストを繰り返すのではなく、package_group を使用します。これにより、可読性が向上し、 リストの同期が維持されます。

ベスト プラクティス: 別のチームのプロジェクトに公開設定を付与する場合は、 __subpackages__ よりも __pkg__ を優先して、プロジェクトの進化と新しいサブパッケージの追加に伴う不要な公開設定の変更を回避します。

ルール ターゲットの公開設定

ルール ターゲットの公開設定は、visibility 属性 (指定されていない場合は適切なデフォルト)を取得し、ターゲットが宣言された場所を追加することで決まります。シンボリック マクロで宣言されていないターゲットの場合、パッケージで default_visibility が指定されている場合は、このデフォルトが使用されます。他のすべてのパッケージとシンボリック マクロで宣言されたターゲットの場合、デフォルトは ["//visibility:private"] です。

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

ベスト プラクティス: default_visibility を public に設定しないでください。プロトタイピングや小規模なコードベースでは 便利ですが、コードベースが大きくなるにつれて、誤って 公開ターゲットを作成するリスクが高まります。パッケージの公開インターフェースの一部であるターゲットを 明示的に指定することをおすすめします。

生成されたファイル ターゲットの公開設定

生成されたファイル ターゲットの公開設定は、生成元のルール ターゲットと 同じです。

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

ソースファイル ターゲットの公開設定

ソースファイル ターゲットは、 exports_files を使用して明示的に宣言することも、 ルールのラベル属性( シンボリック マクロの外部)でファイル名を参照して暗黙的に作成することもできます。ルール ターゲットと同様に、 exports_files の呼び出しの場所、または入力ファイルを参照した BUILD ファイルは、常に ファイルの公開設定に自動的に追加されます。

exports_files で宣言されたファイルは、 visibility パラメータで公開設定を設定できます。このパラメータが指定されていない場合、公開設定は public になります。

`exports_files` の呼び出しに表示されないファイルの場合、公開設定 はフラグ --incompatible_no_implicit_file_exportの値によって異なります。

  • フラグが true の場合、公開設定は private になります。

  • それ以外の場合は、以前の動作が適用されます。公開設定は BUILD ファイルの default_visibility と同じです。デフォルトの公開設定が 指定されていない場合は private になります。

以前の動作に依存することは避けてください。ソースファイル ターゲットに private 以外の公開設定が必要な場合は、常に exports_files 宣言を記述してください。

ベスト プラクティス: 可能であれば、 ソース ファイルではなくルール ターゲットを公開することをおすすめします。たとえば、exports_files ファイルで .java を呼び出すのではなく、非公開の java_library ターゲットでファイルをラップします。通常、ルール ターゲット は、同じパッケージにあるソースファイルのみを直接参照する必要があります。

ファイル //frobber/data/BUILD

exports_files(["readme.txt"])

ファイル //frobber/bin/BUILD

cc_binary(
  name = "my-program",
  data = ["//frobber/data:readme.txt"],
)

構成設定の公開設定

これまで、Bazel は config_setting ターゲットの公開設定を適用していませんでした。select()この以前の動作を削除するフラグは 2 つあります。

  • --incompatible_enforce_config_setting_visibility は、これらのターゲットの公開設定チェックを有効にします。移行を支援するため、 config_setting を指定しない visibility は、パッケージ レベルの default_visibility に関係なく、public と見なされます。

  • --incompatible_config_setting_private_default_visibility を指定しない config_setting は、他のルール ターゲットと同様に、 パッケージの default_visibility を尊重し、private の公開設定にフォールバックします。visibility --incompatible_enforce_config_setting_visibility が設定されていない場合は、何も行いません。

以前の動作に依存することは避けてください。現在のパッケージの外部で使用する config_setting は、パッケージで適切な default_visibility が指定されていない場合は、明示的な visibility を指定する必要があります。

パッケージ グループ ターゲットの公開設定

package_group ターゲットには visibility 属性がありません。常に 公開されます。

暗黙的な依存関係の公開設定

一部のルールには暗黙的な依存関係があります。これは、 BUILD ファイルに記述されていませんが、 そのルールのすべてのインスタンスに固有の依存関係です。たとえば、cc_library ルールは、各ルール ターゲットから C++ コンパイラを表す実行可能ターゲットへの 暗黙的な依存関係を作成する場合があります。

このような暗黙的な依存関係の公開設定は、ルール(またはアスペクト)が定義されている .bzl ファイルを含む パッケージに関してチェックされます。この例では、C++ コンパイラは、定義と同じ パッケージにある限り、private にできます。cc_libraryフォールバックとして、 暗黙的な依存関係が定義から見えない場合は、 cc_library ターゲットに関してチェックされます。

ルールの使用を特定のパッケージに制限する場合は、代わりに 読み込みの公開設定を使用します。

公開設定とシンボリック マクロ

このセクションでは、公開設定システムと シンボリック マクロの相互作用について説明します。

シンボリック マクロ内の場所

公開設定システムの重要な点は、宣言の場所を決定する方法です。シンボリック マクロで宣言されていないターゲットの場合、場所 はターゲットが存在するパッケージ(BUILD ファイルのパッケージ)です。 ただし、シンボリック マクロで作成されたターゲットの場合、場所はマクロの定義( my_macro = macro(...) ステートメント)が表示される .bzl ファイルを含むパッケージです。ターゲットが複数のネストされたターゲット内で作成される場合は、常に最も内側のシンボリック マクロの定義が使用されます。

同じシステムを使用して、特定の 依存関係の公開設定に対してチェックする場所を決定します。使用するターゲットがマクロ内で作成された場合は、使用するターゲットが存在するパッケージではなく、最も内側のマクロの定義を確認します。

つまり、同じパッケージでコードが定義されているすべてのマクロは、 自動的に「フレンド」になります。//lib:defs.bzl で定義されたマクロ によって直接作成されたターゲットは、マクロが実際にインスタンス化されるパッケージに関係なく、//lib で定義された他のマクロから参照できます。同様に、 //lib/BUILD と そのレガシー マクロで直接宣言されたターゲットを参照でき、参照されることもできます。逆に、同じパッケージにあるターゲットでも、少なくとも 1 つがシンボリック マクロによって作成されている場合は、必ずしも相互に参照できるとは限りません。

シンボリック マクロの実装関数内では、visibility パラメータ は、マクロが呼び出された場所を追加した後のマクロの visibility 属性の有効な値になります。マクロがターゲットの 1 つを呼び出し元にエクスポートする標準的な方法は、 この値をターゲットの 宣言に転送することです。これは some_rule(..., visibility = visibility) のようになります。この属性を省略したターゲットは、呼び出し元がマクロ定義と同じパッケージにある場合を除き、マクロの呼び出し元には表示されません。この動作 は、サブマクロへのネストされた呼び出しチェーンがそれぞれ visibility = visibilityを渡すことで構成されます。これにより、マクロの実装 の詳細を公開することなく、内部マクロのエクスポートされたターゲットが 呼び出し元に各レベルで再エクスポートされます。

サブマクロへの権限の委任

公開設定モデルには、マクロが権限をサブマクロに委任できる特別な機能があります。これは、マクロのファクタリングと構成に重要です。

別のパッケージのルール some_libraryを使用して依存関係エッジを作成するマクロmy_macroがあるとします。

# //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 ターゲットには visibility が指定されていないため、 //macro 内でのみ表示されます。これは、使用するターゲットでは問題ありません。ここで、 `//lib` の作成者が //lib をリファクタリングして、some_library マクロを使用して実装するとどうなるでしょうか。

# //lib:defs.bzl

def _impl(name, visibility, deps, ...):
    some_rule(
        # Main target, exported.
        name = name,
        visibility = visibility,
        deps = deps,
        ...)

some_library = macro(implementation = _impl, ...)

この変更により、//pkg:foo_consumer の場所が //macro ではなく //lib になったため、//pkg:foo_dependency の使用は依存関係の 公開設定に違反します。my_macro の作成者は、この実装の詳細を回避するために、依存関係の宣言に visibility = ["//lib"] を渡すことはできません。

このため、ターゲットの依存関係が、そのターゲットを宣言したマクロの属性値でもある場合は、使用するターゲットの場所ではなく、マクロの場所に対して依存関係の公開設定をチェックします。

この例では、//pkg:foo_consumer//pkg:foo_dependency を参照できるかどうかを検証するために、//pkg:foo_dependencysome_library 内の my_macro の呼び出しへの 入力として渡されたことを確認し、この呼び出しの場所 //macro に対して依存関係の公開設定をチェックします。

ターゲットまたはマクロの宣言が 依存関係のラベルをラベル型の属性の 1 つに取る別のシンボリック マクロ 内にある限り、このプロセスは再帰的に繰り返されます。

ファイナライザ

ルール ファイナライザ(finalizer = True のシンボリック マクロ)で宣言されたターゲットは、通常のシンボリック マクロの公開設定ルールに従ってターゲットを参照できるだけでなく、ファイナライザ ターゲットのパッケージに表示されるすべてのターゲットも参照できます。

つまり、native.existing_rules() ベースのレガシー マクロを ファイナライザに移行しても、ファイナライザで宣言されたターゲットは古い依存関係を参照できます。

ファイナライザが native.existing_rules()を使用してイントロスペクションできるターゲットを定義できますが、 公開設定システムでは依存関係として使用できません。たとえば、マクロ定義のターゲットが独自のパッケージまたはファイナライザ マクロの定義に表示されず、ファイナライザに委任されていない場合、ファイナライザはそのようなターゲットを参照できません。ただし、 native.existing_rules()-ベースのレガシー マクロも、そのような ターゲットを参照できません。

読み込みの公開設定

読み込みの公開設定 は、現在のパッケージの外部にある他の BUILD ファイルまたは .bzl ファイルから .bzl ファイルを読み込めるかどうかを制御します。

ターゲットの公開設定がターゲットでカプセル化されたソースコードを保護するのと同じように、読み込みの公開設定は .bzl ファイルでカプセル化されたビルドロジックを保護します。たとえば、BUILD ファイルの作成者は、繰り返し使用される ターゲット宣言を .bzl ファイルのマクロにファクタリングしたいと考えるかもしれません。読み込みの公開設定による保護がないと、同じワークスペース内の他の共同作業者がマクロを再利用し、マクロを変更すると他のチームのビルドが中断する可能性があります。

.bzl ファイルに、対応するソースファイル ターゲットがある場合とない場合があります。 ある場合でも、読み込みの公開設定とターゲット の公開設定が一致するとは限りません。つまり、同じ BUILD ファイルで .bzl ファイルを読み込むことはできますが、srcsfilegroup にリストすることはできません。 逆の場合もあります。ドキュメントの生成やテストなど、 .bzl ファイルをソースコードとして使用するルールで問題が発生することがあります。

プロトタイピングでは、読み込みの公開設定の適用を無効にできます。 --check_bzl_visibility=false--check_visibility=false と同様に、送信されたコードには使用しないでください。

読み込みの公開設定は、Bazel 6.0 以降で使用できます。

読み込みの公開設定の宣言

.bzl ファイルの読み込みの公開設定を設定するには、ファイル内から visibility() 関数を呼び出します。 visibility() の引数は、 packagespackage_group 属性と同様に、パッケージ指定のリストです。ただし、visibility() は負のパッケージ 指定を受け付けません。

visibility() の呼び出しは、ファイルごとに 1 回だけ、最上位レベル( 関数内ではない)で行う必要があります。理想的には、load() ステートメントの直後に行います。

ターゲットの公開設定とは異なり、デフォルトの読み込みの公開設定は常に public です。`visibility()` を呼び出さないファイルは、ワークスペース内のどこからでも読み込むことができます。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 が他の package_group を介してその includes 属性を組み込む方法に似ています。

広く使用されているマクロを非推奨にするとします。既存のユーザーと自分のチームが所有するパッケージにのみ 表示されるようにします。次のように記述します。

# //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 シンボルは、 別のファイルから読み込むことはできません。これにより、private シンボルを簡単に作成できますが、これらのシンボルを信頼できるファイルの限定されたセットと共有することはできません。一方、読み込みの公開設定を使用すると、他のパッケージが 参照できるかどうかを制御できますが、アンダースコア以外のシンボルが 読み込まれないようにすることはできません。.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 リンター

ユーザーのファイルがそのディレクトリの親の下にない場合、ユーザーが internalまたは privateという名前のディレクトリからファイルを読み込むと、Buildifier lintが警告を表示します。このリンターは読み込みの公開設定機能よりも前に存在し、 ファイルが公開設定を宣言するワークスペースでは不要です。.bzl