ระดับการเข้าถึง

รายงานปัญหา ดูแหล่งที่มา รุ่น Nightly · 7.4 7.3 · 7.2 · 7.1 · 7.0 · 6.5

หน้านี้อธิบายระบบระดับการมองเห็น 2 รูปแบบของ Bazel ได้แก่ ระดับการมองเห็นเป้าหมายและระดับการมองเห็นการโหลด

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

ระดับการเข้าถึงเป้าหมาย

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

โดยทั่วไป เป้าหมาย A จะมองเห็นเป้าหมาย B ได้หากอยู่ในตำแหน่งเดียวกัน หรือหาก A ให้สิทธิ์เข้าถึงตำแหน่งของ B หากไม่มีมาโครสัญลักษณ์ คุณอาจใช้คำว่า "แพ็กเกจ" แทน "ตำแหน่ง" ได้ ดูข้อมูลเพิ่มเติมเกี่ยวกับมาโครสัญลักษณ์ได้ด้านล่าง

ระดับการเข้าถึงจะระบุโดยการระบุแพ็กเกจที่อนุญาต การอนุญาตแพ็กเกจไม่ได้หมายความว่าระบบจะอนุญาตแพ็กเกจย่อยด้วย ดูรายละเอียดเพิ่มเติมเกี่ยวกับแพ็กเกจและแพ็กเกจย่อยได้ที่แนวคิดและคําศัพท์

สําหรับการสร้างต้นแบบ คุณสามารถปิดใช้การบังคับใช้ระดับการเข้าถึงเป้าหมายได้โดยการตั้งค่า Flag --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" และ "//foo/bar/..." จะแทนที่รูปแบบ "//foo/bar:__pkg__" และ "//foo/bar:__subpackages__" ตามลำดับ ในทำนองเดียวกัน "//visibility:public" และ "//visibility:private" ก็คือ "public" และ "private"

ตัวอย่างเช่น หาก //some/package:mytarget มีการตั้งค่า visibility เป็น [":__subpackages__", "//tests:__pkg__"] เป้าหมายใดก็ได้ที่เป็นส่วนหนึ่งของต้นไม้แหล่งที่มา //some/package/... รวมถึงเป้าหมายที่ประกาศใน //tests/BUILD จะใช้ //some/package:mytarget ได้ แต่จะไม่สามารถใช้ได้กับเป้าหมายที่กําหนดไว้ใน //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 ระดับการมองเห็นจะขึ้นอยู่กับค่าของ Flag --incompatible_no_implicit_file_export ดังนี้

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

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

หลีกเลี่ยงการพึ่งพาลักษณะการทำงานเดิม เขียน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 Flag ในการนําลักษณะการทํางานเดิมนี้ออก

  • --incompatible_enforce_config_setting_visibility เปิดใช้การตรวจสอบระดับการเข้าถึงสําหรับเป้าหมายเหล่านี้ นอกจากนี้ ระบบจะถือว่า config_setting ที่ไม่ได้ระบุ visibility เป็นสาธารณะ (โดยไม่คำนึงถึง default_visibility ระดับแพ็กเกจ) เพื่อช่วยในการย้ายข้อมูล

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

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

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

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

ระดับการเข้าถึงของ Dependency ที่ไม่ชัด

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

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

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

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

ส่วนนี้จะอธิบายวิธีที่ระบบการแสดงผลโต้ตอบกับมาโครเชิงสัญลักษณ์

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

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

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

ซึ่งหมายความว่ามาโครทั้งหมดที่กําหนดโค้ดไว้ในแพ็กเกจเดียวกันจะ "เป็นเพื่อน" กันโดยอัตโนมัติ เป้าหมายใดก็ตามที่มาโครที่กําหนดใน //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 ด้วย และตรวจสอบระดับการเข้าถึงของข้อกําหนดตามตำแหน่งของการเรียกนี้ //macro แทน

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

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

ระดับการมองเห็นการโหลดจะควบคุมว่าจะโหลดไฟล์ .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

โปรแกรมตรวจสอบ Buildifier ของ bzl-visibility

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