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