การเปิดเผย

รายงานปัญหา ดูแหล่งที่มา Nightly · 8.4 · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

หน้านี้ครอบคลุมระบบระดับการเข้าถึง 2 ระบบของ Bazel ได้แก่ ระดับการเข้าถึงเป้าหมายและระดับการเข้าถึงการโหลด

การมองเห็นทั้ง 2 ประเภทช่วยให้นักพัฒนาแอปรายอื่นๆ แยกความแตกต่างระหว่าง API สาธารณะของไลบรารีกับรายละเอียดการใช้งาน และช่วยบังคับใช้โครงสร้างเมื่อพื้นที่ทํางานของคุณเติบโตขึ้น นอกจากนี้ คุณยังใช้ระดับการมองเห็นเมื่อเลิกใช้งาน API สาธารณะ เพื่ออนุญาตผู้ใช้ปัจจุบันในขณะที่ปฏิเสธผู้ใช้ใหม่ได้ด้วย

การมองเห็นเป้าหมาย

ระดับการเข้าถึงเป้าหมายจะควบคุมผู้ที่พึ่งพาเป้าหมายของคุณได้ ซึ่งก็คือผู้ที่ใช้ป้ายกำกับของเป้าหมายภายในแอตทริบิวต์ เช่น deps เป้าหมายจะสร้างไม่สำเร็จในระหว่างระยะการวิเคราะห์หากละเมิดระดับการเข้าถึงของทรัพยากร Dependency รายการใดรายการหนึ่ง

โดยทั่วไปแล้ว A เป้าหมายจะมองเห็น B เป้าหมายได้หากอยู่สถานที่เดียวกัน หรือหาก A อนุญาตให้มองเห็นตำแหน่งของ 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

แนวทางปฏิบัติแนะนำ: หากต้องการทำให้เป้าหมายหลายรายการแสดงต่อชุดแพ็กเกจเดียวกัน ให้ใช้ package_group แทนการทำซ้ำรายการในแอตทริบิวต์ visibility ของแต่ละเป้าหมาย ซึ่งจะช่วยให้อ่านได้ง่ายขึ้นและป้องกันไม่ให้รายการ ไม่ซิงค์กัน

แนวทางปฏิบัติแนะนำ: เมื่อให้สิทธิ์การมองเห็นโปรเจ็กต์ของทีมอื่น ให้เลือกใช้ __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 เป็นสาธารณะ ซึ่งอาจสะดวกสำหรับการสร้างต้นแบบหรือในโค้ดเบสขนาดเล็ก แต่ความเสี่ยงในการสร้างเป้าหมายสาธารณะโดยไม่ตั้งใจจะเพิ่มขึ้นเมื่อโค้ดเบสเติบโตขึ้น คุณควรระบุอย่างชัดเจนว่าเป้าหมายใดเป็นส่วนหนึ่งของอินเทอร์เฟซสาธารณะของแพ็กเกจ

ระดับการเข้าถึงเป้าหมายของไฟล์ที่สร้างขึ้น

เป้าหมายไฟล์ที่สร้างขึ้นจะมีการมองเห็นเหมือนกับเป้าหมายกฎที่สร้างไฟล์นั้น

# //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 กับฟังก์ชันนั้น หากไม่ได้ระบุพารามิเตอร์นี้ ค่าระดับการแชร์จะเป็นสาธารณะ

สำหรับไฟล์ที่ไม่ปรากฏในการเรียกใช้ exports_files ระดับการมองเห็น จะขึ้นอยู่กับค่าของแฟล็ก --incompatible_no_implicit_file_export ดังนี้

  • หากตั้งค่าเป็นจริง ระดับการแชร์จะเป็นแบบส่วนตัว

  • ไม่เช่นนั้น ระบบจะใช้ลักษณะการทำงานเดิม นั่นคือระดับการแชร์จะเหมือนกับBUILDdefault_visibilityของไฟล์ หรือเป็นแบบส่วนตัวหากไม่ได้ระบุระดับการแชร์เริ่มต้น

หลีกเลี่ยงการพึ่งพาพฤติกรรมเดิม เขียน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ระดับแพ็กเกจจะเป็นอย่างไร)

  • --incompatible_config_setting_private_default_visibility ทำให้ config_settings ที่ไม่ได้ระบุ visibility ต้องปฏิบัติตามdefault_visibility ของแพ็กเกจและใช้ระดับการเข้าถึงแบบส่วนตัวเป็นค่าเริ่มต้น เช่นเดียวกับเป้าหมายกฎอื่นๆ โดยจะไม่มีการดำเนินการใดๆ หากไม่ได้ตั้งค่า --incompatible_enforce_config_setting_visibility

หลีกเลี่ยงการพึ่งพาพฤติกรรมเดิม config_setting ใดๆ ที่ตั้งใจจะใช้ภายนอกแพ็กเกจปัจจุบันควรมี visibility ที่ชัดเจน หากแพ็กเกจยังไม่ได้ระบุ default_visibility ที่เหมาะสม

ระดับการเข้าถึงเป้าหมายของกลุ่มแพ็กเกจ

เป้าหมาย package_group ไม่มีแอตทริบิวต์ visibility โดยจะ แสดงต่อสาธารณะเสมอ

ระดับการเข้าถึงทรัพยากร Dependency โดยนัย

กฎบางอย่างมีการอ้างอิงโดยนัย ซึ่งเป็นการอ้างอิงที่ไม่ได้ระบุไว้ในไฟล์ BUILD แต่มีอยู่ในทุกอินสแตนซ์ของกฎนั้น เช่น cc_library กฎอาจสร้างการอ้างอิงโดยนัยจากเป้าหมายกฎแต่ละรายการไปยังเป้าหมายที่เรียกใช้งานได้ ซึ่งแสดงถึงคอมไพเลอร์ C++

ระบบจะตรวจสอบระดับการเข้าถึงของการอ้างอิงโดยนัยดังกล่าวโดยอิงตามแพ็กเกจที่มีไฟล์ .bzl ซึ่งกำหนดกฎ (หรือ Aspect) ใน ตัวอย่างของเรา คอมไพเลอร์ C++ อาจเป็นแบบส่วนตัวได้ตราบใดที่อยู่ในแพ็กเกจเดียวกันกับคำจำกัดความของcc_libraryกฎ ในกรณีที่การอ้างอิงโดยนัยไม่ปรากฏในคำจำกัดความ ระบบจะตรวจสอบการอ้างอิงโดยนัยดังกล่าวโดยอิงตามเป้าหมาย cc_library

หากต้องการจำกัดการใช้กฎกับแพ็กเกจบางรายการ ให้ใช้ระดับการเข้าถึงการโหลดแทน

มาโครระดับการเข้าถึงและมาโครสัญลักษณ์

ส่วนนี้จะอธิบายวิธีที่ระบบการมองเห็นทำงานร่วมกับมาโครสัญลักษณ์

ตำแหน่งภายในมาโครสัญลักษณ์

รายละเอียดสำคัญของระบบการมองเห็นคือวิธีที่เรากำหนดตำแหน่งของ การประกาศ สําหรับเป้าหมายที่ไม่ได้ประกาศในมาโครสัญลักษณ์ ตําแหน่ง คือแพ็กเกจที่เป้าหมายอยู่ ซึ่งก็คือแพ็กเกจของไฟล์ BUILD แต่สำหรับเป้าหมายที่สร้างในมาโครสัญลักษณ์ ตำแหน่งคือแพ็กเกจ ที่มีไฟล์ .bzl ซึ่งคำจำกัดความของมาโคร (คำสั่ง my_macro = macro(...)) ปรากฏอยู่ เมื่อสร้างเป้าหมายภายในเป้าหมายที่ซ้อนกันหลายรายการ ระบบจะใช้คำจำกัดความของมาโครสัญลักษณ์ที่อยู่ด้านในสุดเสมอ

ระบบเดียวกันนี้ใช้เพื่อกำหนดตำแหน่งที่จะตรวจสอบเทียบกับระดับการมองเห็นของทรัพยากร Dependency ที่ระบุ หากสร้างเป้าหมายที่ใช้ภายในมาโคร เราจะดูคำจำกัดความของมาโครที่อยู่ด้านในสุดแทนที่จะดูแพ็กเกจที่เป้าหมายที่ใช้มีอยู่

ซึ่งหมายความว่ามาโครทั้งหมดที่มีการกำหนดโค้ดไว้ในแพ็กเกจเดียวกันจะ เป็น "เพื่อน" กันโดยอัตโนมัติ เป้าหมายใดก็ตามที่มาโครสร้างขึ้นโดยตรง ซึ่งกำหนดไว้ใน //lib:defs.bzl จะเห็นได้จากมาโครอื่นๆ ที่กำหนดไว้ใน //lib ไม่ว่ามาโครจะสร้างขึ้นในแพ็กเกจใดก็ตาม ในทำนองเดียวกัน ผู้ซื้อจะเห็นและถูกเห็นโดยกลุ่มเป้าหมายที่ประกาศโดยตรงใน //lib/BUILD และ มาโครเดิมของ //lib/BUILD ในทางกลับกัน เป้าหมายที่อยู่ในแพ็กเกจเดียวกันอาจไม่เห็นกันเสมอไป หากเป้าหมายอย่างน้อย 1 รายการสร้างขึ้นโดยใช้มาโครสัญลักษณ์

ภายในฟังก์ชันการใช้งานของมาโครสัญลักษณ์ พารามิเตอร์ visibility จะมีค่าที่มีผลของแอตทริบิวต์ visibility ของมาโครหลังจากต่อท้าย ตำแหน่งที่เรียกใช้มาโคร วิธีมาตรฐานที่มาโครใช้ในการส่งออกเป้าหมายอย่างใดอย่างหนึ่งไปยังผู้เรียกคือการส่งต่อค่านี้ไปยังการประกาศของเป้าหมาย ดังเช่นใน some_rule(..., visibility = visibility) ผู้โทรของมาโครจะไม่เห็นเป้าหมายที่ละเว้นแอตทริบิวต์นี้ เว้นแต่ผู้โทรจะอยู่ในแพ็กเกจเดียวกันกับคำจำกัดความของมาโคร ลักษณะการทำงานนี้ ประกอบขึ้นในแง่ที่ว่าการเรียกใช้มาโครย่อยแบบซ้อนกันเป็นเชนอาจส่งผ่าน visibility = visibility ซึ่งจะส่งออกเป้าหมายที่ส่งออกจากมาโครด้านในไปยัง ผู้เรียกในแต่ละระดับอีกครั้ง โดยไม่ต้องเปิดเผยรายละเอียดการใช้งานของมาโคร

มอบสิทธิ์ให้กับมาโครย่อย

โมเดลระดับการมองเห็นมีฟีเจอร์พิเศษที่อนุญาตให้มาโครมอบสิทธิ์ของตนเอง ให้กับมาโครย่อย ซึ่งเป็นสิ่งสำคัญสำหรับการแยกตัวประกอบและการเขียนมาโคร

สมมติว่าคุณมีมาโคร my_macro ที่สร้างขอบการอ้างอิงโดยใช้กฎ some_library จากแพ็กเกจอื่น

# //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ปรับโครงสร้าง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 เปลี่ยนเป็น //lib แทนที่จะเป็น //macro ดังนั้นการใช้ //pkg:foo_dependency จึงละเมิดระดับการมองเห็นของ การอ้างอิง เราไม่ควรคาดหวังให้ผู้เขียน my_macro ส่ง visibility = ["//lib"] ไปยังการประกาศการอ้างอิงเพียงเพื่อให้ใช้งานได้ เพื่อหลีกเลี่ยงรายละเอียดการใช้งานนี้

ด้วยเหตุนี้ เมื่อการอ้างอิงของเป้าหมายเป็นค่าแอตทริบิวต์ของ มาโครที่ประกาศเป้าหมายด้วย เราจะตรวจสอบระดับการเข้าถึงของการอ้างอิงเทียบกับ ตำแหน่งของมาโครแทนที่จะเป็นตำแหน่งของเป้าหมายที่ใช้

ในตัวอย่างนี้ เพื่อตรวจสอบว่า //pkg:foo_consumer มองเห็น //pkg:foo_dependency ได้หรือไม่ เราจะเห็นว่ามีการส่ง //pkg:foo_dependency เป็นอินพุตไปยังการเรียก some_library ภายใน my_macro ด้วย และแทนที่จะตรวจสอบระดับการมองเห็นของ Dependency กับตำแหน่งของการเรียกนี้ //macro

กระบวนการนี้สามารถทำซ้ำแบบเรียกซ้ำได้ ตราบใดที่เป้าหมายหรือการประกาศมาโครอยู่ภายในมาโครเชิงสัญลักษณ์อื่นที่ใช้ป้ายกำกับของ Dependency ในแอตทริบิวต์ประเภทป้ายกำกับ

Finalizers

เป้าหมายที่ประกาศในตัวสรุปกฎ (มาโครเชิงสัญลักษณ์ที่มี finalizer = True) นอกเหนือจากการเห็นเป้าหมายตามกฎการมองเห็นมาโครเชิงสัญลักษณ์ปกติแล้ว ยังเห็นเป้าหมายทั้งหมดที่แพ็กเกจของเป้าหมายตัวสรุปมองเห็นได้ด้วย

กล่าวคือ หากคุณย้ายข้อมูลมาโครเดิมที่อิงตาม native.existing_rules() ไปยัง Finalizer เป้าหมายที่ประกาศโดย Finalizer จะยังคงเห็น การอ้างอิงเดิมของตน

คุณสามารถกำหนดเป้าหมายที่ Finalizer สามารถตรวจสอบได้โดยใช้ native.existing_rules() แต่ไม่สามารถใช้เป็นทรัพยากร Dependency ภายใต้ระบบการมองเห็นได้ ตัวอย่างเช่น หากเป้าหมายที่กำหนดด้วยมาโครไม่ปรากฏในแพ็กเกจของตัวเองหรือในคำจำกัดความของมาโคร Finalizer และไม่ได้มอบสิทธิ์ให้มาโคร Finalizer มาโคร Finalizer จะมองไม่เห็นเป้าหมายดังกล่าว อย่างไรก็ตาม โปรดทราบว่ามาโครเดิมที่อิงตาม native.existing_rules()จะดูเป้าหมายดังกล่าวไม่ได้เช่นกัน

การแสดงผลการโหลด

ระดับการเข้าถึงการโหลดจะควบคุมว่าไฟล์ .bzl จะโหลดจากไฟล์ BUILD หรือ .bzl อื่นๆ นอกแพ็กเกจปัจจุบันได้หรือไม่

ในลักษณะเดียวกับที่ระดับการเข้าถึงเป้าหมายปกป้องซอร์สโค้ดที่แคปซูลโดยเป้าหมาย ระดับการเข้าถึงการโหลดจะปกป้องตรรกะการบิลด์ที่แคปซูลโดยไฟล์ .bzl เช่น ผู้เขียนไฟล์ BUILD อาจต้องการรวมการประกาศเป้าหมายที่ซ้ำกันบางรายการ ไว้ในมาโครในไฟล์ .bzl หากไม่มีการป้องกัน ระดับการมองเห็นการโหลด ผู้ใช้เหล่านั้นอาจพบว่าผู้ร่วมงานคนอื่นๆ นำมาโครไปใช้ซ้ำใน พื้นที่ทำงานเดียวกัน ซึ่งการแก้ไขมาโครจะทำให้บิลด์ของทีมอื่นๆ เสียหาย

โปรดทราบว่าไฟล์ .bzl อาจมีหรือไม่มีเป้าหมายไฟล์ต้นฉบับที่สอดคล้องกันก็ได้ หากเป็นเช่นนั้น เราไม่รับประกันว่าการโหลดที่มองเห็นได้และความสามารถในการมองเห็นเป้าหมายจะตรงกัน กล่าวคือ ไฟล์ BUILD เดียวกันอาจโหลดไฟล์ .bzl ได้ แต่แสดงใน srcs ของ filegroup ไม่ได้ หรือในทางกลับกัน ซึ่งบางครั้งอาจทำให้เกิดปัญหากับกฎที่ต้องการใช้ไฟล์ .bzl เป็นซอร์สโค้ด เช่น สำหรับการสร้างเอกสารหรือการทดสอบ

สำหรับการสร้างต้นแบบ คุณอาจปิดใช้การบังคับใช้ระดับการมองเห็นการโหลดได้โดยการตั้งค่า --check_bzl_visibility=false เช่นเดียวกับ --check_visibility=false คุณไม่ควรทำเช่นนี้กับโค้ดที่ส่ง

ความสามารถในการมองเห็นการโหลดพร้อมใช้งานตั้งแต่ Bazel 6.0 เป็นต้นไป

การประกาศระดับการเข้าถึงการโหลด

หากต้องการตั้งค่าระดับการเข้าถึงการโหลดของไฟล์ .bzl ให้เรียกใช้ฟังก์ชัน visibility() จากภายในไฟล์ อาร์กิวเมนต์ของ visibility() คือรายการข้อกำหนดของแพ็กเกจ เช่นเดียวกับแอตทริบิวต์ packages ของ package_group อย่างไรก็ตาม visibility() ไม่ยอมรับข้อกำหนดของแพ็กเกจที่เป็นค่าลบ

การเรียกใช้ visibility() ต้องเกิดขึ้นเพียงครั้งเดียวต่อไฟล์ ที่ระดับบนสุด (ไม่อยู่ ภายในฟังก์ชัน) และควรเกิดขึ้นทันทีหลังจากคำสั่ง load()

ระดับการเข้าถึงการโหลดเริ่มต้นจะเป็นแบบสาธารณะเสมอ ซึ่งแตกต่างจากระดับการเข้าถึงเป้าหมาย ไฟล์ ที่ไม่ได้เรียกใช้ visibility() จะโหลดได้จากทุกที่ใน พื้นที่ทำงานเสมอ เราขอแนะนำให้เพิ่ม visibility("private") ที่ด้านบนของไฟล์ .bzl ใหม่ที่ไม่ได้มีไว้สำหรับการใช้งานภายนอกแพ็กเกจโดยเฉพาะ

ตัวอย่าง

# //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 ซึ่งการประกาศทั้ง 2 ประเภทอาจอ้างอิงถึงไฟล์นี้ จากตัวอย่างในการพิจารณาระดับการมองเห็น ด้านบน คุณอาจเขียนว่า

# //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

มี Buildifier lint ที่จะแสดงคำเตือนหากผู้ใช้โหลดไฟล์จากไดเรกทอรีที่ชื่อ internal หรือ private เมื่อไฟล์ของผู้ใช้ไม่ได้อยู่ใต้ไดเรกทอรีหลักของไดเรกทอรีนั้น Lint นี้มีมาก่อนฟีเจอร์ระดับการเข้าถึงการโหลดและไม่จำเป็นใน เวิร์กสเปซที่ไฟล์ .bzl ประกาศระดับการเข้าถึง