หน้านี้ครอบคลุมระบบระดับการเข้าถึง 2 ระบบของ Bazel ได้แก่ ระดับการเข้าถึงเป้าหมายและระดับการเข้าถึงการโหลด
การมองเห็นทั้ง 2 ประเภทช่วยให้นักพัฒนาแอปรายอื่นๆ แยกความแตกต่างระหว่าง API สาธารณะของไลบรารีกับรายละเอียดการใช้งาน และช่วยบังคับใช้โครงสร้างเมื่อพื้นที่ทํางานของคุณเติบโตขึ้น นอกจากนี้ คุณยังใช้ระดับการมองเห็นเมื่อเลิกใช้งาน API สาธารณะ เพื่ออนุญาตผู้ใช้ปัจจุบันในขณะที่ปฏิเสธผู้ใช้ใหม่ได้ด้วย
การมองเห็นเป้าหมาย
ระดับการเข้าถึงเป้าหมายจะควบคุมผู้ที่พึ่งพาเป้าหมายของคุณได้ ซึ่งก็คือผู้ที่ใช้ป้ายกำกับของเป้าหมายภายในแอตทริบิวต์ เช่น deps
A เป้าหมายจะมองเห็น B เป้าหมายได้หากอยู่ในแพ็กเกจเดียวกัน หรือหาก A อนุญาตให้แพ็กเกจของ B มองเห็นได้ ดังนั้น แพ็กเกจจึงเป็นหน่วยของ
ความละเอียดในการตัดสินว่าจะอนุญาตให้เข้าถึงหรือไม่ หาก B ขึ้นอยู่กับ A
แต่ A ไม่ปรากฏต่อ B ความพยายามใดๆ ในการสร้าง 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 ของแต่ละเป้าหมาย ซึ่งจะช่วยให้อ่านได้ง่ายขึ้นและป้องกันไม่ให้รายการ
ไม่ซิงค์กัน
ระดับการเข้าถึงเป้าหมายของกฎ
ระดับการเข้าถึงเป้าหมายของกฎมีดังนี้
ค่าของแอตทริบิวต์
visibilityหากมีการตั้งค่า หรือค่าของอาร์กิวเมนต์
default_visibilityของคำสั่งpackageในไฟล์BUILDของเป้าหมาย หากมีการประกาศดังกล่าว หรือ//visibility:private
แนวทางปฏิบัติแนะนำ: หลีกเลี่ยงการตั้งค่า default_visibility เป็นสาธารณะ ซึ่งอาจสะดวกสำหรับการสร้างต้นแบบหรือในโค้ดเบสขนาดเล็ก แต่ความเสี่ยงในการสร้างเป้าหมายสาธารณะโดยไม่ตั้งใจจะเพิ่มขึ้นเมื่อโค้ดเบสเติบโตขึ้น คุณควรระบุอย่างชัดเจนว่าเป้าหมายใดเป็นส่วนหนึ่งของอินเทอร์เฟซสาธารณะของแพ็กเกจ
ตัวอย่าง
ไฟล์ //frobber/bin/BUILD:
# This target is visible to everyone
cc_binary(
name = "executable",
visibility = ["//visibility:public"],
deps = [":library"],
)
# This target is visible only to targets declared in the same package
cc_library(
name = "library",
# No visibility -- defaults to private since no
# package(default_visibility = ...) was used.
)
# This target is visible to targets in package //object and //noun
cc_library(
name = "subject",
visibility = [
"//noun:__pkg__",
"//object:__pkg__",
],
)
# See package group "//frobber:friends" (below) for who can
# access this target.
cc_library(
name = "thingy",
visibility = ["//frobber:friends"],
)
ไฟล์ //frobber/BUILD:
# This is the package group declaration to which target
# //frobber/bin:thingy refers.
#
# Our friends are packages //frobber, //fribber and any
# subpackage of //fribber.
package_group(
name = "friends",
packages = [
"//fribber/...",
"//frobber",
],
)
ระดับการเข้าถึงเป้าหมายของไฟล์ที่สร้างขึ้น
เป้าหมายไฟล์ที่สร้างขึ้นจะมีการมองเห็นเหมือนกับเป้าหมายกฎที่สร้างไฟล์นั้น
ระดับการเข้าถึงเป้าหมายของไฟล์ต้นฉบับ
คุณตั้งค่าระดับการมองเห็นของเป้าหมายไฟล์ต้นฉบับได้อย่างชัดเจนโดยการเรียกใช้
exports_files เมื่อไม่มีการส่งvisibility
อาร์กิวเมนต์ไปยัง exports_files ฟังก์ชันนี้จะทำให้ระดับการแชร์เป็นสาธารณะ
exports_files อาจใช้เพื่อลบล้างระดับการแชร์ของไฟล์ที่สร้างขึ้นไม่ได้
สำหรับเป้าหมายไฟล์ต้นฉบับที่ไม่ได้ปรากฏในการเรียกใช้ 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
คุณเปลี่ยนลักษณะการทำงานนี้ได้โดยการปิดใช้
--incompatible_visibility_private_attributes_at_definition
เมื่อปิดใช้ ระบบจะถือว่าทรัพยากร Dependency โดยนัยเป็นทรัพยากร Dependency อื่นๆ
ซึ่งหมายความว่าเป้าหมายที่ขึ้นอยู่กับ (เช่น คอมไพเลอร์ C++) ต้องมองเห็นได้ในทุกอินสแตนซ์ของกฎ ในทางปฏิบัติ โดยปกติแล้วหมายความว่าเป้าหมาย
ต้องมีระดับการเข้าถึงแบบสาธารณะ
หากต้องการจำกัดการใช้กฎกับแพ็กเกจบางรายการ ให้ใช้ระดับการเข้าถึงการโหลดแทน
การแสดงผลการโหลด
ระดับการเข้าถึงการโหลดจะควบคุมว่าไฟล์ .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 ประกาศระดับการเข้าถึง