หน้านี้ครอบคลุมระบบการแสดงผล 2 ระบบของ Bazel: การแสดงผลเป้าหมาย และ การแสดงผลการโหลด
การแสดงผลทั้ง 2 ประเภทช่วยให้นักพัฒนาซอฟต์แวร์คนอื่นๆ แยกแยะ API สาธารณะของไลบรารีกับรายละเอียดการใช้งาน และช่วยบังคับใช้โครงสร้างเมื่อพื้นที่ทำงานขยายใหญ่ขึ้น นอกจากนี้ คุณยังใช้การแสดงผลเมื่อเลิกใช้งาน API สาธารณะเพื่ออนุญาตผู้ใช้ปัจจุบันขณะที่ปฏิเสธผู้ใช้ใหม่ได้ด้วย
การมองเห็นเป้าหมาย
การแสดงผลเป้าหมาย จะควบคุมผู้ที่อาจขึ้นอยู่กับเป้าหมายของคุณ ซึ่งหมายความว่าผู้ที่อาจใช้ป้ายกำกับของเป้าหมายภายในแอตทริบิวต์ เช่น deps เป้าหมายจะสร้างไม่สำเร็จ
ในระยะการวิเคราะห์หาก
ละเมิดการแสดงผลของทรัพยากร Dependency รายการใดรายการหนึ่ง
โดยทั่วไปแล้ว เป้าหมาย A จะแสดงต่อเป้าหมาย B หากเป้าหมายทั้ง 2 อยู่ในตำแหน่งเดียวกัน หรือหาก 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 ดังนี้
หากแฟล็กเป็นจริง การแสดงผลจะเป็นแบบส่วนตัว
หากไม่เป็นจริง ระบบจะใช้ลักษณะการทำงานเดิม การแสดงผลจะเหมือนกับ
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"],
)
การแสดงผลการตั้งค่า Config
ในอดีต Bazel ไม่ได้บังคับใช้การแสดงผลสำหรับ
config_setting เป้าหมายที่
อ้างอิงในคีย์ของ select() โดยมีแฟล็ก 2 รายการเพื่อนำลักษณะการทำงานเดิมนี้ออก
--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` ที่เหมาะสมไว้แล้วconfig_settingvisibilitydefault_visibility
การแสดงผลเป้าหมายกลุ่มแพ็กเกจ
เป้าหมาย package_group ไม่มีแอตทริบิวต์ visibility โดยจะแสดงต่อสาธารณะเสมอ
การแสดงผลทรัพยากร Dependency โดยนัย
กฎบางข้อมี ทรัพยากร Dependency โดยนัย ซึ่งเป็น
ทรัพยากร Dependency ที่ไม่ได้ระบุไว้ในไฟล์ BUILD แต่เป็นส่วนสำคัญของ
กฎแต่ละอินสแตนซ์ ตัวอย่างเช่น กฎ cc_library อาจสร้างทรัพยากร Dependency โดยนัยจากเป้าหมายกฎแต่ละรายการไปยังเป้าหมายที่เรียกใช้งานได้ซึ่งแสดงถึงคอมไพเลอร์ C++
ระบบจะตรวจสอบการแสดงผลของทรัพยากร Dependency โดยนัยดังกล่าวโดยอ้างอิงถึงแพ็กเกจที่มีไฟล์ .bzl ซึ่งกำหนดกฎ (หรือ Aspect) ในตัวอย่างของเรา คอมไพเลอร์ C++ อาจเป็นแบบส่วนตัวได้ตราบใดที่อยู่ในแพ็กเกจเดียวกับคำจำกัดความของกฎ cc_library หากทรัพยากร Dependency โดยนัยไม่แสดงจากคำจำกัดความ ระบบจะตรวจสอบทรัพยากร Dependency โดยนัยโดยอ้างอิงถึงเป้าหมาย cc_library
หากต้องการจำกัดการใช้งานกฎไว้เฉพาะแพ็กเกจบางรายการ ให้ใช้ การแสดงผลการโหลดแทน
การแสดงผลและมาโครสัญลักษณ์
ส่วนนี้จะอธิบายวิธีที่ระบบการแสดงผลโต้ตอบกับ มาโครสัญลักษณ์
ตำแหน่งภายในมาโครสัญลักษณ์
รายละเอียดที่สำคัญของระบบการแสดงผลคือวิธีที่เรากำหนดตำแหน่งของการประกาศ สำหรับเป้าหมายที่ไม่ได้ประกาศในมาโครสัญลักษณ์ ตำแหน่งจะเป็นเพียงแพ็กเกจที่เป้าหมายอยู่ ซึ่งก็คือแพ็กเกจของไฟล์ BUILD
แต่สำหรับเป้าหมายที่สร้างขึ้นในมาโครสัญลักษณ์ ตำแหน่งจะเป็นแพ็กเกจที่มีไฟล์ .bzl ซึ่งคำจำกัดความของมาโคร (คำสั่ง my_macro = macro(...)) ปรากฏอยู่ เมื่อสร้างเป้าหมายภายในเป้าหมายที่ซ้อนกันหลายรายการ ระบบจะใช้คำจำกัดความของมาโครสัญลักษณ์ที่อยู่ด้านในสุดเสมอ
ระบบเดียวกันนี้ใช้เพื่อกำหนดตำแหน่งที่จะตรวจสอบการแสดงผลของทรัพยากร Dependency ที่กำหนด หากเป้าหมายที่ใช้ทรัพยากร Dependency ถูกสร้างขึ้นภายในมาโคร เราจะดูคำจำกัดความของมาโครที่อยู่ด้านในสุดแทนที่จะดูแพ็กเกจที่เป้าหมายที่ใช้ทรัพยากร Dependency อยู่
ซึ่งหมายความว่ามาโครทั้งหมดที่มีการกำหนดโค้ดไว้ในแพ็กเกจเดียวกันจะเป็น "เพื่อน" กันโดยอัตโนมัติ เป้าหมายใดก็ตามที่สร้างขึ้นโดยตรงโดยมาโคร
ที่กำหนดไว้ใน //lib:defs.bzl จะมองเห็นได้จากมาโครอื่นๆ ที่กำหนดไว้ใน //lib,
ไม่ว่ามาโครจะสร้างอินสแตนซ์ในแพ็กเกจใดก็ตาม เช่นเดียวกัน มาโครเหล่านี้จะมองเห็นเป้าหมายที่ประกาศไว้ใน //lib/BUILD และมาโครเดิมของแพ็กเกจ รวมถึงเป้าหมายที่ประกาศไว้ใน //lib/BUILD และมาโครเดิมของแพ็กเกจก็จะมองเห็นมาโครเหล่านี้ได้ ในทางกลับกัน เป้าหมายที่อยู่ในแพ็กเกจเดียวกันอาจมองไม่เห็นกันและกันหากเป้าหมายอย่างน้อย 1 รายการถูกสร้างขึ้นโดยมาโครสัญลักษณ์
ภายในฟังก์ชันการใช้งานของมาโครสัญลักษณ์ พารามิเตอร์ visibility จะมีค่าที่มีผลของแอตทริบิวต์ visibility ของมาโครหลังจากต่อท้ายตำแหน่งที่เรียกมาโคร วิธีมาตรฐานที่มาโครจะส่งออกเป้าหมายรายการใดรายการหนึ่งไปยังผู้เรียกคือการส่งต่อค่านี้ไปยังการประกาศของเป้าหมาย เช่น some_rule(..., visibility = visibility) ผู้เรียกมาโครจะมองไม่เห็นเป้าหมายที่ละเว้นแอตทริบิวต์นี้ เว้นแต่ว่าผู้เรียกจะอยู่ในแพ็กเกจเดียวกับคำจำกัดความของมาโคร ลักษณะการทำงานนี้จะรวมกันในแง่ที่ว่าการเรียกมาโครย่อยที่ซ้อนกันเป็นลำดับอาจส่ง visibility = visibility แต่ละครั้ง ซึ่งจะส่งออกเป้าหมายที่ส่งออกของมาโครด้านในไปยังผู้เรียกในแต่ละระดับ โดยไม่เปิดเผยรายละเอียดการใช้งานของมาโคร
การมอบสิทธิ์ให้กับมาโครย่อย
โมเดลการแสดงผลมีฟีเจอร์พิเศษที่ช่วยให้มาโครมอบสิทธิ์ของตนให้กับมาโครย่อยได้ ซึ่งเป็นสิ่งสำคัญสำหรับการแยกตัวประกอบและการรวมมาโคร
สมมติว่าคุณมีมาโคร my_macro ที่สร้างขอบทรัพยากร Dependency โดยใช้กฎ 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 ซึ่งใช้ได้กับเป้าหมายที่ใช้ทรัพยากร Dependency ทีนี้จะเกิดอะไรขึ้นหากผู้เขียน //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 จึงละเมิดการแสดงผลของทรัพยากร Dependency ผู้เขียน my_macro ไม่ควรส่ง
visibility = ["//lib"] ไปยังการประกาศทรัพยากร Dependency เพียงเพื่อหลีกเลี่ยงรายละเอียดการใช้งานนี้
ด้วยเหตุนี้ เมื่อทรัพยากร Dependency ของเป้าหมายเป็นค่าแอตทริบิวต์ของมาโครที่ประกาศเป้าหมายด้วย เราจะตรวจสอบการแสดงผลของทรัพยากร Dependency โดยอ้างอิงถึงตำแหน่งของมาโครแทนที่จะอ้างอิงถึงตำแหน่งของเป้าหมายที่ใช้ทรัพยากร Dependency
ในตัวอย่างนี้ หากต้องการตรวจสอบว่า //pkg:foo_consumer มองเห็น //pkg:foo_dependency ได้หรือไม่ เราจะดูว่า //pkg:foo_dependency ถูกส่งเป็นอินพุตไปยังการเรียก some_library ภายใน my_macro ด้วยหรือไม่ และตรวจสอบการแสดงผลของทรัพยากร Dependency โดยอ้างอิงถึงตำแหน่งของการเรียกนี้ ซึ่งก็คือ //macro
กระบวนการนี้สามารถทำซ้ำแบบเรียกซ้ำได้ ตราบใดที่การประกาศเป้าหมายหรือมาโครอยู่ภายในมาโครสัญลักษณ์อื่นที่ใช้ป้ายกำกับของทรัพยากร Dependency ในแอตทริบิวต์ประเภทป้ายกำกับรายการใดรายการหนึ่ง
การแสดงผลการโหลด
การแสดงผลการโหลด จะควบคุมว่าไฟล์ .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 อาจต้องแสดงต่อรายการที่อนุญาตซึ่งประกอบด้วยรายการที่อนุญาตขนาดเล็กหลายรายการ ซึ่งคล้ายกับวิธีที่ a
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 Lint
มี Buildifier lint ที่แสดงคำเตือนหากผู้ใช้โหลดไฟล์จากไดเรกทอรีที่ชื่อ internal หรือ private เมื่อไฟล์ของผู้ใช้ไม่ได้อยู่ใต้ไดเรกทอรีระดับบนสุดของ ไดเรกทอรีนั้น เครื่องมือวิเคราะห์ซอร์สโค้ดนี้มีมาก่อนฟีเจอร์การแสดงผลการโหลดและไม่จำเป็นในพื้นที่ทำงานที่ไฟล์ .bzl ประกาศการแสดงผล