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