โมดูล 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 เพิ่มเติม มาไว้ในขอบเขตที่มองเห็นได้ของโมดูลด้วย