หน้านี้ครอบคลุมระบบระดับการเข้าถึง 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
ดังนี้
หากตั้งค่าเป็นจริง ระดับการแชร์จะเป็นแบบส่วนตัว
ไม่เช่นนั้น ระบบจะใช้ลักษณะการทำงานเดิม นั่นคือระดับการแชร์จะเหมือนกับ
BUILD
default_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_setting
s ที่ไม่ได้ระบุ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
ประกาศระดับการเข้าถึง