โมดูล Bazel คือโปรเจ็กต์ Bazel ที่มีได้หลายเวอร์ชัน โดยแต่ละเวอร์ชัน จะเผยแพร่ข้อมูลเมตาเกี่ยวกับโมดูลอื่นๆ ที่ขึ้นอยู่กับโมดูลนั้น ซึ่งคล้ายกับแนวคิดที่คุ้นเคยในระบบการจัดการทรัพยากร Dependency อื่นๆ เช่น Artifact ของ Maven, Package ของ npm, Module ของ Go หรือ Crate ของ Cargo
โมดูลต้องมีไฟล์ MODULE.bazel ที่รูทของ repo ไฟล์นี้คือ Manifest ของโมดูล ซึ่งประกาศชื่อ เวอร์ชัน รายการการอ้างอิงโดยตรง และข้อมูลอื่นๆ ตัวอย่างพื้นฐานมีดังนี้
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 ของการขึ้นต่อกันจากรีจิสทรี Bazel ซ้ำๆ จนกว่าจะค้นพบกราฟการขึ้นต่อกันทั้งหมด
โดยค่าเริ่มต้น Bazel จะเลือกโมดูลแต่ละเวอร์ชัน เพื่อใช้ Bazel จะแสดงแต่ละโมดูลด้วย repo และจะปรึกษา Registry อีกครั้งเพื่อดูวิธีกำหนด repo แต่ละรายการ
รูปแบบเวอร์ชัน
Bazel มีระบบนิเวศที่หลากหลายและโปรเจ็กต์ต่างๆ ใช้รูปแบบการกำหนดเวอร์ชันที่แตกต่างกัน SemVer เป็นรูปแบบที่ได้รับความนิยมมากที่สุด แต่ก็มีโปรเจ็กต์ที่โดดเด่นซึ่งใช้รูปแบบอื่นด้วย เช่น Abseil ซึ่งมีเวอร์ชันที่อิงตามวันที่ เช่น 20210324.2)
ด้วยเหตุนี้ Bazel จึงใช้ข้อกำหนด SemVer ในเวอร์ชันที่ผ่อนปรนมากขึ้น โดย ความแตกต่างมีดังนี้
- SemVer กำหนดว่าส่วน "รุ่น" ของเวอร์ชันต้องประกอบด้วย 3
ส่วน:
MAJOR.MINOR.PATCHใน Bazel ข้อกำหนดนี้จะผ่อนปรนเพื่อให้ อนุญาตให้มีจำนวนกลุ่มเท่าใดก็ได้ - ใน SemVer แต่ละส่วนในส่วน "รุ่น" ต้องเป็นตัวเลขเท่านั้น ใน Bazel จะมีการผ่อนปรนให้ใช้ตัวอักษรได้ด้วย และความหมายของการเปรียบเทียบจะตรงกับ "ตัวระบุ" ในส่วน "รุ่นก่อนเปิดตัว"
- นอกจากนี้ ระบบจะไม่บังคับใช้ความหมายของการเพิ่มเวอร์ชันหลัก เวอร์ชันย่อย และเวอร์ชันแพตช์ อย่างไรก็ตาม โปรดดูระดับความเข้ากันได้เพื่อดูรายละเอียดเกี่ยวกับวิธีที่เราระบุความเข้ากันได้แบบย้อนหลัง
เวอร์ชัน SemVer ที่ถูกต้องจะเป็นเวอร์ชันโมดูล Bazel ที่ถูกต้อง นอกจากนี้ เวอร์ชัน SemVer 2 รายการ a และ b จะเปรียบเทียบกันได้a < b ก็ต่อเมื่อเป็นไปตามเงื่อนไขเดียวกันเมื่อเปรียบเทียบเป็นเวอร์ชันโมดูล Bazel
สุดท้ายนี้ หากต้องการดูข้อมูลเพิ่มเติมเกี่ยวกับการกำหนดเวอร์ชันโมดูล โปรดดูMODULE.bazel
คำถามที่พบบ่อย
การเลือกเวอร์ชัน
พิจารณาปัญหาการขึ้นต่อกันแบบไดมอนด์ ซึ่งเป็นปัญหาหลักในพื้นที่การจัดการการขึ้นต่อกันแบบเวอร์ชัน สมมติว่าคุณมีกราฟทรัพยากร Dependency ดังนี้
A 1.0
/ \
B 1.0 C 1.1
| |
D 1.0 D 1.1
ควรใช้ D เวอร์ชันใด Bazel ใช้
การเลือกเวอร์ชันขั้นต่ำ
(MVS) ซึ่งเป็นอัลกอริทึมที่เปิดตัวในระบบโมดูล Go เพื่อตอบคำถามนี้ MVS จะถือว่าโมดูลเวอร์ชันใหม่ทั้งหมด
สามารถใช้งานร่วมกับเวอร์ชันก่อนหน้าได้ จึงเลือกเวอร์ชันสูงสุด
ที่ระบุโดยโมดูลที่ขึ้นต่อกัน (D 1.1 ในตัวอย่างของเรา) เราเรียกเวอร์ชันนี้ว่า "ขั้นต่ำ"
เนื่องจาก D 1.1 เป็นเวอร์ชันแรกสุดที่ตรงตามข้อกำหนดของเรา
แม้ว่าจะมี D 1.2 หรือเวอร์ชันที่ใหม่กว่า เราก็จะไม่เลือก การใช้ MVS จะสร้างกระบวนการเลือกเวอร์ชันที่มีความเที่ยงตรงสูงและทำซ้ำได้
เวอร์ชันที่ถูกยกเลิก
รีจิสทรีสามารถประกาศว่าเวอร์ชันหนึ่งๆ เป็นเวอร์ชันที่ถูกยกเลิกได้หากควรหลีกเลี่ยง
(เช่น เนื่องจากมีช่องโหว่ด้านความปลอดภัย) Bazel จะแสดงข้อผิดพลาดเมื่อเลือกโมดูลเวอร์ชันที่ถูกยกเลิก
หากต้องการแก้ไขข้อผิดพลาดนี้ ให้อัปเกรดเป็นเวอร์ชันที่ใหม่กว่า
ซึ่งไม่ได้ถูกยกเลิก หรือใช้แฟล็ก
--allow_yanked_versions
เพื่ออนุญาตเวอร์ชันที่ถูกยกเลิกอย่างชัดเจน
ระดับความเข้ากันได้
ใน Go สมมติฐานของ MVS เกี่ยวกับการรองรับเวอร์ชันก่อนหน้าใช้ได้เนื่องจากถือว่าโมดูลเวอร์ชันที่ไม่รองรับเวอร์ชันก่อนหน้าเป็นโมดูลแยกต่างหาก ในแง่ของ SemVer นั่นหมายความว่า A 1.x และ A 2.x ถือเป็นโมดูลที่แตกต่างกัน และสามารถอยู่ร่วมกันในกราฟการอ้างอิงที่แก้ไขแล้ว ซึ่งเป็นไปได้เนื่องจาก
การเข้ารหัสเวอร์ชันหลักในเส้นทางแพ็กเกจใน Go จึงไม่มี
ความขัดแย้งในเวลาคอมไพล์หรือเวลาลิงก์ อย่างไรก็ตาม Bazel ไม่สามารถรับประกันดังกล่าวได้เนื่องจากใช้SemVer เวอร์ชันที่ผ่อนปรน
ดังนั้น Bazel จึงต้องมีหมายเลขเวอร์ชันหลักของ SemVer ที่เทียบเท่าเพื่อตรวจหาเวอร์ชันที่เข้ากันไม่ได้แบบย้อนหลัง ("การเปลี่ยนแปลงที่ทำให้ใช้งานร่วมกันไม่ได้") หมายเลขนี้เรียกว่าระดับความเข้ากันได้ และจะระบุโดยเวอร์ชันโมดูลแต่ละเวอร์ชันในคำสั่ง module() ข้อมูลนี้จะช่วยให้ Bazel แสดงข้อผิดพลาดได้หากตรวจพบว่ามีโมดูลเดียวกันที่มีระดับความเข้ากันได้แตกต่างกันอยู่ในกราฟการอ้างอิงที่แก้ไขแล้ว
สุดท้ายนี้ การเพิ่มระดับความเข้ากันได้อาจส่งผลกระทบต่อผู้ใช้
ดูข้อมูลเพิ่มเติมเกี่ยวกับเวลาและวิธีเพิ่มหมายเลขเวอร์ชันได้ที่คำถามที่พบบ่อยMODULE.bazel
ลบล้าง
ระบุการลบล้างในไฟล์ MODULE.bazel เพื่อเปลี่ยนลักษณะการทำงานของการแก้ปัญหาโมดูล Bazel
เฉพาะการลบล้างของโมดูลรูทเท่านั้นที่จะมีผล หากใช้โมดูลเป็นทรัพยากร Dependency ระบบจะไม่สนใจการลบล้างของโมดูลนั้น
การลบล้างแต่ละรายการจะระบุชื่อโมดูลหนึ่งๆ ซึ่งส่งผลต่อเวอร์ชันทั้งหมดของโมดูลนั้นในกราฟการอ้างอิง แม้ว่าจะมีเพียงการลบล้างของโมดูลรูทเท่านั้นที่มีผล แต่การลบล้างดังกล่าวอาจมีไว้สำหรับทรัพยากร Dependency แบบทรานซิทีฟที่โมดูลรูทไม่ได้ขึ้นอยู่กับทรัพยากรนั้นโดยตรง
การลบล้างเวอร์ชันเดียว
single_version_override
มีวัตถุประสงค์หลายประการ ดังนี้
- แอตทริบิวต์
versionช่วยให้คุณปักหมุดการอ้างอิงไว้กับเวอร์ชันที่เฉพาะเจาะจงได้ ไม่ว่ากราฟการอ้างอิงจะร้องขอการอ้างอิงเวอร์ชันใดก็ตาม - แอตทริบิวต์
registryช่วยให้คุณบังคับให้การอ้างอิงนี้มาจากรีจิสทรีที่เฉพาะเจาะจงได้ แทนที่จะทำตามกระบวนการการเลือกรีจิสทรีปกติ - แอตทริบิวต์
patch*ช่วยให้คุณระบุชุดแพตช์ที่จะใช้กับโมดูลที่ดาวน์โหลดได้
แอตทริบิวต์เหล่านี้เป็นแอตทริบิวต์ที่ไม่บังคับทั้งหมด และสามารถนำมาใช้ร่วมกันได้
การลบล้างหลายเวอร์ชัน
คุณระบุ multiple_version_override
เพื่ออนุญาตให้โมดูลเดียวกันหลายเวอร์ชันอยู่ร่วมกันใน
กราฟการอ้างอิงที่แก้ไขแล้วได้
คุณสามารถระบุรายการเวอร์ชันที่อนุญาตอย่างชัดเจนสำหรับโมดูล ซึ่งต้อง มีทั้งหมดในกราฟการอ้างอิงก่อนการแก้ไข โดยต้องมี การอ้างอิงแบบทรานซิทีฟบางอย่างซึ่งขึ้นอยู่กับเวอร์ชันที่อนุญาตแต่ละเวอร์ชัน หลังจาก การแก้ไขแล้ว จะเหลือเฉพาะโมดูลเวอร์ชันที่อนุญาตเท่านั้น ส่วน Bazel จะอัปเกรดโมดูลเวอร์ชันอื่นๆ เป็นเวอร์ชันที่อนุญาตที่สูงกว่าที่ใกล้ที่สุดในระดับความเข้ากันได้เดียวกัน หากไม่มีเวอร์ชันที่อนุญาตที่สูงกว่าในระดับความเข้ากันได้เดียวกัน Bazel จะแสดงข้อผิดพลาด
เช่น หากมีเวอร์ชัน 1.1, 1.3, 1.5, 1.7 และ 2.0 ใน
กราฟการอ้างอิงก่อนการแก้ไข และเวอร์ชันหลักคือระดับความเข้ากันได้
- การลบล้างหลายเวอร์ชันที่อนุญาต
1.3,1.7และ2.0จะส่งผลให้1.1อัปเกรดเป็น1.3,1.5อัปเกรดเป็น1.7และเวอร์ชันอื่นๆ ยังคงเหมือนเดิม - การลบล้างหลายเวอร์ชันที่อนุญาต
1.5และ2.0จะทําให้เกิดข้อผิดพลาด เนื่องจาก1.7ไม่มีเวอร์ชันที่สูงกว่าในระดับความเข้ากันได้เดียวกันเพื่ออัปเกรด - การลบล้างหลายเวอร์ชันที่อนุญาต
1.9และ2.0จะทำให้เกิดข้อผิดพลาด เนื่องจาก1.9ไม่ได้อยู่ในกราฟการอ้างอิงก่อนการแก้ไข
นอกจากนี้ ผู้ใช้ยังลบล้างรีจิสทรีได้โดยใช้registry
แอตทริบิวต์เช่นเดียวกับการลบล้างแบบเวอร์ชันเดียว
การลบล้างที่ไม่ใช่รีจิสทรี
การลบล้างที่ไม่ใช่รีจิสทรีจะนำโมดูลออกจากความละเอียดของเวอร์ชันโดยสมบูรณ์ Bazel
ไม่ได้ขอMODULE.bazelไฟล์เหล่านี้จากรีจิสทรี แต่ขอจาก
ที่เก็บเอง
Bazel รองรับการลบล้างที่ไม่ใช่รีจิสทรีต่อไปนี้
โปรดทราบว่าการตั้งค่าเวอร์ชันในที่เก็บต้นทาง MODULE.bazel อาจมีข้อเสีย
เมื่อมีการลบล้างโมดูลด้วยการลบล้างที่ไม่ใช่รีจิสทรี ดูข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ได้ที่คำถามที่พบบ่อยMODULE.bazel
กำหนดที่เก็บที่ไม่ใช่โมดูล Bazel
bazel_dep ช่วยให้คุณกำหนด repo ที่แสดงโมดูล Bazel อื่นๆ ได้
บางครั้งคุณอาจต้องกำหนดที่เก็บที่ไม่แสดงโมดูล Bazel
เช่น ที่เก็บที่มีไฟล์ JSON ธรรมดาที่จะอ่านเป็นข้อมูล
ในกรณีนี้ คุณสามารถใช้use_repo_rule
คำสั่งเพื่อกำหนดรีโปโดยตรง
ด้วยการเรียกใช้กฎรีโป โดยที่รีโปนี้จะมองเห็นได้เฉพาะในโมดูลที่กำหนดไว้เท่านั้น
เบื้องหลังแล้ว ฟีเจอร์นี้จะใช้กลไกเดียวกันกับ module extensions ซึ่งช่วยให้คุณกำหนดที่เก็บได้อย่างยืดหยุ่นมากขึ้น
ชื่อที่เก็บและ Strict Deps
ชื่อที่ชัดเจนของที่เก็บที่สนับสนุนโมดูลไปยังโมดูลที่ขึ้นต่อกันโดยตรงจะตั้งค่าเริ่มต้นเป็นชื่อโมดูล เว้นแต่แอตทริบิวต์ repo_name ของคำสั่ง bazel_dep
จะระบุไว้เป็นอย่างอื่น โปรดทราบว่าการดำเนินการนี้หมายความว่าโมดูลจะค้นหาได้เฉพาะการอ้างอิงโดยตรง
เท่านั้น ซึ่งจะช่วยป้องกันไม่ให้เกิดการหยุดทำงานโดยไม่ตั้งใจเนื่องจากการเปลี่ยนแปลงใน
การอ้างอิงแบบทรานซิทีฟ
ชื่อ Canonical ของรีโปที่สนับสนุนโมดูล
คือ module_name+version (เช่น bazel_skylib+1.0.3) หรือ module_name+ (เช่น bazel_features+) ขึ้นอยู่กับว่ามีโมดูลหลายเวอร์ชันในกราฟการขึ้นต่อกันทั้งหมดหรือไม่ (ดู multiple_version_override)
โปรดทราบว่ารูปแบบชื่อ Canonical ไม่ใช่ API ที่คุณควรใช้ และอาจมีการเปลี่ยนแปลงได้ทุกเมื่อ แทนที่จะเขียนโค้ด Canonical Name แบบฮาร์ดโค้ด ให้
ใช้วิธีที่รองรับเพื่อรับชื่อดังกล่าวจาก Bazel โดยตรง
- ในไฟล์ BUILD และ
.bzlให้ใช้Label.repo_nameในอินสแตนซ์Labelที่สร้างจากสตริงป้ายกำกับซึ่งกำหนดโดยชื่อที่ชัดเจนของที่เก็บ เช่น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 สำหรับชุดที่เก็บที่กำหนด
ส่วนขยายโมดูลยังสามารถนำที่เก็บข้อมูลเพิ่มเติม มาไว้ในขอบเขตที่มองเห็นได้ของโมดูลด้วย