หน้านี้ครอบคลุมระบบการมองเห็น 2 ระบบของ Bazel คือ การเปิดเผยเป้าหมายและการเปิดเผยการโหลด
ระดับการเข้าถึงทั้ง 2 ประเภทช่วยให้นักพัฒนาซอฟต์แวร์คนอื่นๆ แยกความแตกต่างระหว่าง API สาธารณะของไลบรารีกับรายละเอียดการใช้งานได้ ทั้งยังช่วยบังคับใช้โครงสร้างเมื่อพื้นที่ทำงานของคุณเติบโตขึ้น นอกจากนี้ คุณยังสามารถใช้การเปิดเผยเมื่อเลิกใช้งาน API สาธารณะเพื่ออนุญาตผู้ใช้ปัจจุบันในขณะที่ปฏิเสธ API ใหม่ได้ด้วย
ระดับการเข้าถึงเป้าหมาย
ระดับการเข้าถึงเป้าหมายจะควบคุมผู้ที่อาจอิงตามเป้าหมายของคุณ กล่าวคือ ผู้ที่อาจใช้ป้ายกำกับของเป้าหมายในแอตทริบิวต์ เช่น deps
A
เป้าหมายจะมองเห็นได้ต่อ B
เป้าหมายหากอยู่ในแพ็กเกจเดียวกัน หรือหาก A
ให้ระดับการเข้าถึงแพ็กเกจของ B
ดังนั้น แพ็กเกจคือหน่วยของรายละเอียดในการตัดสินใจว่าจะอนุญาตการเข้าถึงหรือไม่ หาก B
ขึ้นอยู่กับ 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
ของแต่ละเป้าหมาย ซึ่งจะช่วยเพิ่มความอ่านง่ายและป้องกันไม่ให้รายการซิงค์กัน
ระดับการเข้าถึงเป้าหมายของกฎ
ระดับการเข้าถึงของเป้าหมายกฎคือ
ค่าของแอตทริบิวต์
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
:
หากตั้งค่าไว้ ระดับการแชร์จะเป็นแบบส่วนตัว
หรือไม่เช่นนั้น ระบบจะใช้ลักษณะการทำงานเดิม กล่าวคือ ระดับการแชร์จะเหมือนกับ
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 สถานะ ได้แก่
--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 โดยนัย
กฎบางอย่างมีทรัพยากร Dependency โดยนัย ซึ่งเป็นทรัพยากร Dependency ที่ไม่ได้สะกดในไฟล์ BUILD
แต่มีอยู่ในทุกอินสแตนซ์ของกฎนั้น เช่น กฎ cc_library
อาจสร้างทรัพยากร Dependency โดยนัยจากเป้าหมายกฎแต่ละข้อไปยังเป้าหมายปฏิบัติการซึ่งเป็นตัวแทนของคอมไพเลอร์ C++
ระดับการเข้าถึงของทรัพยากร Dependency โดยนัยดังกล่าวจะได้รับการตรวจสอบในส่วนที่เกี่ยวข้องกับแพ็กเกจที่มีไฟล์ .bzl
ซึ่งมีการกำหนดกฎ (หรือสัดส่วนภาพ) ไว้ ในตัวอย่างของเรา คอมไพเลอร์ C++ อาจเป็นแบบส่วนตัวได้ตราบใดที่อยู่ในแพ็กเกจเดียวกับคำจำกัดความของกฎ cc_library
เป็นทางเลือก หากไม่พบ Dependency โดยนัยจากคําจํากัดความ ระบบจะตรวจสอบความสอดคล้องกับเป้าหมาย 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
ของคุณได้ แต่ไม่ช่วยให้โหลดสัญลักษณ์ที่ไม่ใช่เครื่องหมายขีดล่างได้
โชคดีที่คุณสามารถรวมคุณลักษณะทั้งสองนี้เข้าด้วยกันเพื่อให้เป็นการควบคุมแบบละเอียด
# //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
Lint บิลด์การมองเห็น bzl
มี Buildifier lint ที่แสดงคำเตือนหากผู้ใช้โหลดไฟล์จากไดเรกทอรีชื่อ internal
หรือ private
เมื่อไฟล์ของผู้ใช้ไม่ได้อยู่ใต้ระดับบนสุดของไดเรกทอรีนั้น ไฟล์ Lint นี้สร้างขึ้นก่อนฟีเจอร์ระดับการเข้าถึงการโหลดและไม่จำเป็นในพื้นที่ทำงานที่ไฟล์ .bzl
ประกาศระดับการเข้าถึง