โมดูล Bazel คือโปรเจ็กต์ Bazel ที่มีหลายเวอร์ชัน ซึ่งแต่ละเวอร์ชันจะเผยแพร่ข้อมูลเมตาเกี่ยวกับโมดูลอื่นๆ ที่โมดูลนั้นขึ้นอยู่ด้วย ซึ่งคล้ายกับแนวคิดที่คุ้นเคยในระบบการจัดการทรัพยากร Dependency อื่นๆ เช่น อาร์ติแฟกต์ของ Maven, แพ็กเกจของ npm, โมดูลของ Go หรือ เครตของ Cargo
โมดูลต้องมีไฟล์ MODULE.bazel ที่รูทของ repo ไฟล์นี้คือไฟล์ Manifest ของโมดูล ซึ่งประกาศชื่อ เวอร์ชัน รายการทรัพยากร Dependency โดยตรง และข้อมูลอื่นๆ ตัวอย่างพื้นฐาน
module(name = "my-module", version = "1.0")
bazel_dep(name = "rules_cc", version = "0.0.1")
bazel_dep(name = "protobuf", version = "3.19.0")
ดูรายการคำสั่งทั้งหมดที่พร้อมใช้งานใน
MODULE.bazelไฟล์
หากต้องการทำการแก้ปัญหาโมดูล Bazel จะเริ่มต้นด้วยการอ่านไฟล์
MODULE.bazel ของโมดูลรูท แล้วขอไฟล์
MODULE.bazel ของทรัพยากร Dependency จากรีจิสทรี Bazel ซ้ำๆ จนกว่าจะ
ค้นพบกราฟทรัพยากร Dependency ทั้งหมด
โดยค่าเริ่มต้น Bazel จะเลือกเวอร์ชันของแต่ละโมดูล ที่จะใช้ Bazel จะแสดงโมดูลแต่ละรายการด้วย repo และปรึกษาข้อมูลรีจิสทรีอีกครั้งเพื่อดูวิธีกำหนด repo แต่ละรายการ
รูปแบบเวอร์ชัน
Bazel มีระบบนิเวศที่หลากหลายและโปรเจ็กต์ต่างๆ ใช้รูปแบบการกำหนดเวอร์ชันที่แตกต่างกัน รูปแบบที่ได้รับความนิยมมากที่สุดคือ SemVer แต่ก็มีโปรเจ็กต์ที่โดดเด่นซึ่งใช้รูปแบบอื่นด้วย เช่น Abseil ซึ่งเวอร์ชันจะอิงตามวันที่ เช่น 20210324.2)
ด้วยเหตุนี้ Bzlmod จึงใช้ข้อกำหนดเวอร์ชัน SemVer ที่ยืดหยุ่นมากขึ้น โดยมีข้อแตกต่างดังนี้
- SemVer กำหนดว่าส่วน "รีลีส" ของเวอร์ชันต้องประกอบด้วย 3 ส่วน ได้แก่
MAJOR.MINOR.PATCHใน Bazel ข้อกำหนดนี้จะยืดหยุ่นมากขึ้นเพื่อให้มีจำนวนส่วนเท่าใดก็ได้ - ใน SemVer ส่วนต่างๆ ในส่วน "รีลีส" ต้องเป็นตัวเลขเท่านั้น ใน Bazel ข้อกำหนดนี้จะยืดหยุ่นมากขึ้นเพื่อให้ใช้ตัวอักษรได้ด้วย และความหมายของการเปรียบเทียบจะตรงกับ "ตัวระบุ" ในส่วน "เวอร์ชันก่อนรีลีส"
- นอกจากนี้ ระบบยังไม่ได้บังคับใช้ความหมายของการเพิ่มเวอร์ชันหลัก เวอร์ชันย่อย และเวอร์ชันแพตช์
เวอร์ชัน SemVer ที่ถูกต้องจะเป็นเวอร์ชันโมดูล Bazel ที่ถูกต้อง นอกจากนี้ เวอร์ชัน SemVer 2 เวอร์ชัน
a และ b จะเปรียบเทียบ a < b ก็ต่อเมื่อเป็นจริงเมื่อ
เปรียบเทียบเป็นเวอร์ชันโมดูล Bazel
การเลือกเวอร์ชัน
พิจารณาปัญหาทรัพยากร Dependency แบบไดมอนด์ ซึ่งเป็นปัญหาหลักในการจัดการทรัพยากร Dependency ที่กำหนดเวอร์ชัน สมมติว่าคุณมีกราฟทรัพยากร Dependency ดังนี้
A 1.0
/ \
B 1.0 C 1.1
| |
D 1.0 D 1.1
ควรใช้ D เวอร์ชันใด Bzlmod ใช้
การเลือกเวอร์ชันต่ำสุด
(MVS) ซึ่งเป็นอัลกอริทึมที่แนะนำในระบบโมดูล Go เพื่อแก้ปัญหานี้ MVS สันนิษฐานว่าโมดูลเวอร์ชันใหม่ทั้งหมดเข้ากันได้กับเวอร์ชันก่อนหน้า จึงเลือกเวอร์ชันสูงสุดที่ระบุโดยทรัพยากร Dependency (D 1.1 ในตัวอย่างของเรา) โดยเรียกว่า "ต่ำสุด" เนื่องจาก D 1.1 เป็นเวอร์ชันแรกสุดที่ตรงตามข้อกำหนดของเรา แม้ว่าจะมี D 1.2 หรือใหม่กว่า เราก็จะไม่เลือก การใช้ MVS จะสร้างกระบวนการเลือกเวอร์ชันที่มี ความแม่นยำสูงและ ทำซ้ำได้
เวอร์ชันที่ถูกยกเลิก
รีจิสทรีสามารถประกาศเวอร์ชันบางเวอร์ชันเป็น ยกเลิกหากควรหลีกเลี่ยง (เช่น เวอร์ชันที่มีช่องโหว่ด้านความปลอดภัย) Bazel จะแสดงข้อผิดพลาดเมื่อเลือกโมดูลเวอร์ชันที่ถูกยกเลิก หากต้องการแก้ไขข้อผิดพลาดนี้ ให้อัปเกรดเป็นเวอร์ชันใหม่กว่า
ที่ไม่ได้ถูกยกเลิก หรือใช้
--allow_yanked_versions
แฟล็กเพื่ออนุญาตเวอร์ชันที่ถูกยกเลิกอย่างชัดเจน
ลบล้าง
ระบุการลบล้างในไฟล์ MODULE.bazel เพื่อเปลี่ยนลักษณะการทำงานของการแก้ปัญหาโมดูล Bazel การลบล้างของโมดูลรูทเท่านั้นที่จะมีผล หากใช้โมดูลเป็นทรัพยากร Dependency ระบบจะละเว้นการลบล้างของโมดูลนั้น
การลบล้างแต่ละรายการจะระบุไว้สำหรับชื่อโมดูลหนึ่งๆ ซึ่งจะส่งผลต่อโมดูลทุกเวอร์ชันในกราฟทรัพยากร Dependency แม้ว่าการลบล้างของโมดูลรูทเท่านั้นที่จะมีผล แต่การลบล้างนั้นอาจมีไว้สำหรับทรัพยากร Dependency แบบทรานซิทีฟที่โมดูลรูทไม่ได้ขึ้นอยู่ด้วยโดยตรง
การลบล้างเวอร์ชันเดียว
single_version_override
มีไว้เพื่อวัตถุประสงค์หลายประการ ดังนี้
- แอตทริบิวต์
versionช่วยให้คุณตรึงทรัพยากร Dependency ไว้ที่เวอร์ชันหนึ่งๆ ได้ ไม่ว่าเวอร์ชันใดของทรัพยากร Dependency จะมีการขอในกราฟทรัพยากร Dependency - แอตทริบิวต์
registryช่วยให้คุณบังคับให้ทรัพยากร Dependency นี้มาจากรีจิสทรีหนึ่งๆ ได้ แทนที่จะทำตามกระบวนการเลือกรีจิสทรีตามปกติ - แอตทริบิวต์
patch*ช่วยให้คุณระบุชุดแพตช์ที่จะใช้กับโมดูลที่ดาวน์โหลดได้
แอตทริบิวต์เหล่านี้เป็นแอตทริบิวต์ที่ไม่บังคับทั้งหมด และสามารถใช้ร่วมกันได้
การลบล้างหลายเวอร์ชัน
คุณระบุ multiple_version_override
เพื่ออนุญาตให้โมดูลเดียวกันหลายเวอร์ชันอยู่ร่วมกันใน
กราฟทรัพยากร Dependency ที่แก้ปัญหาแล้วได้
หากมีโมดูลเดียวกันหลายเวอร์ชันเหลืออยู่ในกราฟทรัพยากร Dependency Bazel จะเลือกเวอร์ชันที่สูงกว่าเวอร์ชันที่ใกล้ที่สุดที่อนุญาตสำหรับทรัพยากร Dependency แต่ละรายการ
ตัวอย่างเช่น หากมีเวอร์ชัน 1.1, 1.3, 1.5, 1.7 และ 2.0 อยู่ในกราฟทรัพยากร Dependency ก่อนการแก้ปัญหา
- การลบล้างหลายเวอร์ชันที่อนุญาต
1.3,1.7และ2.0จะส่งผลให้1.1อัปเกรดเป็น1.3,1.5อัปเกรดเป็น1.7และเวอร์ชันอื่นๆ ยังคงเหมือนเดิม - การลบล้างหลายเวอร์ชันที่อนุญาต
1.9และ2.0จะส่งผลให้เกิดข้อผิดพลาด เนื่องจาก1.9ไม่ได้อยู่ในกราฟทรัพยากร Dependency ก่อนการแก้ปัญหา
นอกจากนี้ ผู้ใช้ยังลบล้างรีจิสทรีได้โดยใช้แอตทริบิวต์ registry ซึ่งคล้ายกับการลบล้างเวอร์ชันเดียว
การลบล้างที่ไม่ใช่รีจิสทรี
การลบล้างที่ไม่ใช่รีจิสทรีจะนำโมดูลออกจากกระบวนการแก้ปัญหาเวอร์ชันโดยสมบูรณ์ Bazel จะไม่ขอไฟล์ MODULE.bazel เหล่านี้จากรีจิสทรี แต่จะขอจาก repo เอง
Bazel รองรับการลบล้างที่ไม่ใช่รีจิสทรีต่อไปนี้
กำหนด repo ที่ไม่ได้แสดงโมดูล Bazel
bazel_dep ช่วยให้คุณกำหนด repo ที่แสดงโมดูล Bazel อื่นๆ ได้
บางครั้งคุณอาจต้องกำหนด repo ที่ ไม่ได้แสดงโมดูล Bazel เช่น repo ที่มีไฟล์ JSON ธรรมดาที่จะอ่านเป็นข้อมูล
ในกรณีนี้ คุณสามารถใช้คำสั่ง use_repo_rule
directive เพื่อกำหนด repo โดยตรง
โดยการเรียกใช้กฎของ repo repo นี้จะมองเห็นได้เฉพาะโมดูลที่กำหนดไว้เท่านั้น
เบื้องหลังแล้ว ระบบจะใช้กลไกเดียวกับส่วนขยาย โมดูล ซึ่งช่วยให้คุณกำหนด repo ได้อย่างยืดหยุ่นมากขึ้น
ชื่อที่เก็บและทรัพยากร Dependency ที่เข้มงวด
ชื่อที่ปรากฏของ repo ที่รองรับ
โมดูลสำหรับทรัพยากร Dependency โดยตรงจะเป็นชื่อโมดูลโดยค่าเริ่มต้น เว้นแต่
repo_name แอตทริบิวต์ของคำสั่งbazel_dep
จะระบุไว้เป็นอย่างอื่น โปรดทราบว่าการดำเนินการนี้หมายความว่าโมดูลจะค้นหาได้เฉพาะทรัพยากร Dependency โดยตรงเท่านั้น ซึ่งจะช่วยป้องกันการหยุดทำงานโดยไม่ตั้งใจเนื่องจากการเปลี่ยนแปลงในทรัพยากร Dependency แบบทรานซิทีฟ
ชื่อ Canonical ของ repo ที่รองรับ
โมดูลคือ module_name+version (เช่น bazel_skylib+1.0.3) หรือ module_name+ (เช่น bazel_features+) ทั้งนี้ขึ้นอยู่กับว่ามี
โมดูลหลายเวอร์ชันในกราฟทรัพยากร Dependency ทั้งหมดหรือไม่ (ดู
multiple_version_override)
โปรดทราบว่า รูปแบบชื่อ Canonical ไม่ใช่ API ที่คุณควรใช้ และ
อาจมีการเปลี่ยนแปลงได้ทุกเมื่อ ให้ใช้รูปแบบที่รองรับเพื่อรับชื่อ Canonical จาก Bazel โดยตรงแทนการฮาร์ดโค้ดชื่อ Canonical
- ในไฟล์ BUILD และ
.bzlให้ใช้Label.repo_nameในอินสแตนซ์Labelที่สร้างจากสตริงป้ายกำกับที่กำหนดโดยชื่อที่ปรากฏของ repo เช่นLabel("@bazel_skylib").repo_name - เมื่อค้นหาไฟล์ที่เรียกใช้ ให้ใช้
$(rlocationpath ...)หรือไลบรารีไฟล์ที่เรียกใช้รายการใดรายการหนึ่งใน@bazel_tools//tools/{bash,cpp,java}/runfilesหรือสำหรับชุดกฎrules_foo, ใน@rules_foo//foo/runfiles - เมื่อโต้ตอบกับ Bazel จากเครื่องมือภายนอก เช่น IDE หรือเซิร์ฟเวอร์ภาษา
ให้ใช้คำสั่ง
bazel mod dump_repo_mappingเพื่อรับการแมปจาก ชื่อที่ปรากฏไปยังชื่อ Canonical สำหรับชุดที่เก็บข้อมูลที่กำหนด
ส่วนขยายโมดูลยังสามารถนำ repo เพิ่มเติม มาไว้ในขอบเขตที่มองเห็นได้ของโมดูลด้วย