공개 상태

문제 신고 소스 보기 Nightly · 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

이 페이지에서는 Bazel의 두 가지 공개 상태 시스템인 타겟 공개 상태로드 공개 상태를 설명합니다.

두 유형의 공개 상태 모두 다른 개발자가 라이브러리의 공개 API와 구현 세부정보를 구분하고 워크스페이스가 커짐에 따라 구조를 적용하는 데 도움이 됩니다. 공개 API를 지원 중단할 때 공개 상태를 사용하여 현재 사용자는 허용하고 새 사용자는 거부할 수 있습니다.

타겟 공개 상태

타겟 공개 상태는 타겟에 종속될 수 있는 사용자(즉, deps와 같은 속성 내에서 타겟 라벨을 사용할 수 있는 사용자)를 제어합니다.

타겟 A는 동일한 패키지에 있거나 AB의 패키지에 가시성을 부여하는 경우 타겟 B에 표시됩니다. 따라서 패키지는 액세스 허용 여부를 결정하기 위한 세부사항의 단위입니다. BA에 종속되지만 AB에 표시되지 않으면 분석 중에 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를 사용하세요. 이렇게 하면 가독성이 높아지고 목록이 동기화되지 않는 것을 방지할 수 있습니다.

규칙 타겟 공개 상태

규칙 타겟의 공개 상태는 다음과 같습니다.

  1. visibility 속성 값(설정된 경우) 또는 기타

  2. 대상의 BUILD 파일에 있는 package 문에 관한 default_visibility 인수의 값입니다(이러한 선언이 있는 경우).

  3. //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 대상에 공개 상태를 적용하지 않았습니다. 이 기존 동작을 삭제하는 플래그에는 두 가지가 있습니다.

  • --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++ 컴파일러를 나타내는 실행 파일 타겟으로의 암시적 종속 항목을 만들 수 있습니다.

현재 이러한 암시적 종속 항목은 가시성을 위해 다른 종속 항목과 마찬가지로 취급됩니다. 즉, 종속 항목인 대상(예: C++ 컴파일러)이 규칙의 모든 인스턴스에 표시되어야 합니다. 실제로 이는 일반적으로 타겟이 공개 상태를 유지해야 함을 의미합니다.

--incompatible_visibility_private_attributes_at_definition를 설정하여 이 동작을 변경할 수 있습니다. 사용 설정하면 해당 타겟은 암시적 종속 항목이라고 선언하는 규칙에만 표시될 수 있습니다. 즉, 규칙이 정의된 .bzl 파일이 포함된 패키지에 표시되어야 합니다. 이 예에서 C++ 컴파일러는 cc_library 규칙 정의와 동일한 패키지에 있는 한 비공개일 수 있습니다.

로드 공개 상태

로드 공개 상태.bzl 파일을 다른 BUILD 또는 .bzl 파일에서 로드할 수 있는지를 제어합니다.

타겟 공개 상태가 타겟에 의해 캡슐화된 소스 코드를 보호하는 것과 마찬가지로, 로드 공개 상태는 .bzl 파일에 의해 캡슐화된 빌드 로직을 보호합니다. 예를 들어 BUILD 파일 작성자는 반복되는 일부 타겟 정의를 .bzl 파일의 매크로로 분해할 수 있습니다. 로드 공개 상태를 보호하지 않으면 동일한 작업공간에서 다른 공동작업자가 매크로를 재사용하여 매크로를 수정하면 다른 팀의 빌드가 손상될 수 있습니다.

.bzl 파일에는 상응하는 소스 파일 타겟이 있을 수도 있고 없을 수도 있습니다. 로드 가시성과 대상 가시성이 일치하지 않을 수 있습니다. 즉, 동일한 BUILD 파일은 .bzl 파일을 로드할 수 있지만 filegroupsrcs에 나열하지 못할 수도 있고 그 반대의 경우도 가능합니다. 이로 인해 문서 생성 또는 테스트와 같이 .bzl 파일을 소스 코드로 사용하려는 규칙에서 문제가 발생할 수 있습니다.

프로토타입 제작의 경우 --check_bzl_visibility=false를 설정하여 로드 공개 상태 적용을 사용 중지할 수 있습니다. --check_visibility=false와 마찬가지로 제출된 코드에서 이 작업을 실행하면 안 됩니다.

로드 공개 상태는 Bazel 6.0부터 사용할 수 있습니다.

로드 공개 상태 선언

.bzl 파일의 로드 공개 상태를 설정하려면 파일 내에서 visibility() 함수를 호출합니다. visibility()의 인수는 package_grouppackages 속성과 마찬가지로 패키지 사양 목록입니다. 그러나 visibility()는 제외 패키지 사양은 허용하지 않습니다.

visibility() 호출은 파일당 한 번만, 최상위 수준(함수 내부가 아님)에서, 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를 볼 수 있는지 여부를 제어할 수 있지만, 밑줄이 없는 기호가 로드되는 것을 방지할 수는 없습니다.

다행히 이 두 기능을 결합하여 세밀하게 제어할 수 있습니다.

# //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 린트가 있습니다. 이 린트는 로드 가시성 기능보다 먼저 도입되었으며 .bzl 파일이 가시성을 선언하는 워크스페이스에서는 필요하지 않습니다.