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