โมดูล Bazel

โมดูล 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)

ด้วยเหตุนี้ Bazel จึงใช้ข้อกำหนดเวอร์ชัน SemVer ที่ยืดหยุ่นมากขึ้น โดยมีข้อแตกต่างดังนี้

  • SemVer กำหนดว่าส่วน "รีลีส" ของเวอร์ชันต้องประกอบด้วย 3 ส่วน ได้แก่ MAJOR.MINOR.PATCH ใน Bazel ข้อกำหนดนี้จะยืดหยุ่นมากขึ้นเพื่อให้มีจำนวนส่วนเท่าใดก็ได้
  • ใน SemVer ส่วนต่างๆ ในส่วน "รีลีส" ต้องเป็นตัวเลขเท่านั้น ใน Bazel ข้อกำหนดนี้จะยืดหยุ่นมากขึ้นเพื่อให้ใช้ตัวอักษรได้ด้วย และความหมายของการเปรียบเทียบจะตรงกับ "ตัวระบุ" ในส่วน "เวอร์ชันก่อนรีลีส"
  • นอกจากนี้ ระบบยังไม่บังคับใช้ความหมายของการเพิ่มเวอร์ชันหลัก เวอร์ชันย่อย และเวอร์ชันแพตช์

เวอร์ชัน SemVer ที่ถูกต้องจะเป็นเวอร์ชันโมดูล Bazel ที่ถูกต้อง นอกจากนี้ เวอร์ชัน SemVer 2 เวอร์ชัน a และ b จะเปรียบเทียบ a < b ก็ต่อเมื่อเป็นจริงเมื่อ เปรียบเทียบเป็นเวอร์ชันโมดูล Bazel

สุดท้ายนี้ หากต้องการดูข้อมูลเพิ่มเติมเกี่ยวกับการกำหนดเวอร์ชันโมดูล โปรดดูMODULE.bazel คำถามที่พบบ่อย

การเลือกเวอร์ชัน

ลองพิจารณาปัญหาทรัพยากร Dependency แบบไดมอนด์ ซึ่งเป็นปัญหาหลักในการจัดการทรัพยากร Dependency ที่กำหนดเวอร์ชัน สมมติว่าคุณมีกราฟทรัพยากร Dependency ดังนี้

       A 1.0
      /     \
   B 1.0    C 1.1
     |        |
   D 1.0    D 1.1

ควรใช้ D เวอร์ชันใด Bazel ใช้ การเลือกเวอร์ชันขั้นต่ำ (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 รองรับการลบล้างที่ไม่ใช่รีจิสทรีต่อไปนี้

โปรดทราบว่าการตั้งค่าค่าเวอร์ชันใน MODULE.bazel ของไฟล์เก็บถาวรต้นทางอาจมีข้อเสียเมื่อมีการลบล้างโมดูลด้วยการลบล้างที่ไม่ใช่รีจิสทรี ดูข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ได้ที่ คำถามที่พบบ่อยMODULE.bazel

กำหนด repo ที่ไม่ได้แสดงโมดูล Bazel

bazel_dep ช่วยให้คุณกำหนด repo ที่แสดงโมดูล Bazel อื่นๆ ได้ บางครั้งคุณอาจต้องกำหนด repo ที่ ไม่ได้ แสดงโมดูล Bazel เช่น repo ที่มีไฟล์ JSON ธรรมดาที่จะอ่านเป็นข้อมูล

ในกรณีนี้ คุณสามารถใช้คำสั่ง use_repo_rule directive เพื่อกำหนด repo โดยตรง โดยการเรียกใช้กฎของ 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 เพิ่มเติม มาไว้ในขอบเขตที่มองเห็นได้ของโมดูลด้วย