หน้านี้อธิบายระบบระดับการมองเห็น 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
ประกาศระดับการเข้าถึง