Bazel รองรับทรัพยากรภายนอก ซึ่งเป็นไฟล์ต้นฉบับ (ทั้งข้อความและไบนารี) ที่ใช้ในการสร้างที่ไม่ได้มาจากเวิร์กスペース เช่น อาจเป็นชุดกฎที่โฮสต์อยู่ในที่เก็บ GitHub, ออบเจ็กต์ Maven หรือไดเรกทอรีในเครื่องคอมพิวเตอร์ของคุณซึ่งอยู่นอกเวิร์กスペースปัจจุบัน
เอกสารนี้จะอธิบายภาพรวมของระบบก่อนที่จะเจาะลึกแนวคิดบางอย่างอย่างละเอียด
ภาพรวมของระบบ
ระบบการพึ่งพาภายนอกของ Bazel ทำงานตามโมดูล Bazel ซึ่งแต่ละโมดูลเป็นโปรเจ็กต์ Bazel ที่มีเวอร์ชัน และที่เก็บ (หรือที่เก็บ) ซึ่งเป็นต้นไม้ไดเรกทอรีที่มีไฟล์ต้นฉบับ
Bazel จะเริ่มต้นจากโมดูลรูท ซึ่งเป็นโปรเจ็กต์ที่คุณกำลังทําอยู่
เช่นเดียวกับโมดูลทั้งหมด โมดูลนี้ต้องมีไฟล์ MODULE.bazel
ที่รูทไดเรกทอรี ซึ่งจะประกาศข้อมูลเมตาพื้นฐานและข้อกำหนดเบื้องต้นโดยตรง ตัวอย่างเบื้องต้นมีดังนี้
module(name = "my-module", version = "1.0")
bazel_dep(name = "rules_cc", version = "0.1.1")
bazel_dep(name = "platforms", version = "0.0.11")
จากนั้น Bazel จะค้นหาโมดูลการพึ่งพาแบบทรานซิทีฟทั้งหมดในรีจิสทรี Bazel โดยค่าเริ่มต้นคือ Bazel Central รีจิสทรี รีจิสทรีจะมีไฟล์ MODULE.bazel
ของข้อกำหนด ซึ่งช่วยให้ Bazel ค้นพบกราฟข้อกำหนดแบบทรานซิทีฟทั้งหมดก่อนที่จะทำการแก้ไขเวอร์ชัน
หลังจากการแก้ไขเวอร์ชันซึ่งจะเลือกเวอร์ชันเดียวสำหรับแต่ละโมดูลแล้ว Bazel จะปรึกษารีจิสทรีอีกครั้งเพื่อดูวิธีกำหนดที่เก็บสำหรับแต่ละโมดูล นั่นคือวิธีดึงข้อมูลแหล่งที่มาสำหรับโมดูล Dependency แต่ละรายการ ส่วนใหญ่แล้วไฟล์เหล่านี้เป็นเพียงไฟล์ที่เก็บถาวรที่ดาวน์โหลดจากอินเทอร์เน็ตและแตกไฟล์
โมดูลยังระบุข้อมูลที่กำหนดเองที่เรียกว่าแท็กได้ด้วย ซึ่งส่วนขยายโมดูลจะใช้หลังจากการแก้ไขโมดูลเพื่อกำหนดที่เก็บข้อมูลเพิ่มเติม ส่วนขยายเหล่านี้สามารถดําเนินการต่างๆ เช่น I/O ของไฟล์และการส่งคําขอเครือข่าย นอกเหนือจากนี้ เครื่องมือเหล่านี้ยังช่วยให้ Bazel โต้ตอบกับระบบการจัดการแพ็กเกจอื่นๆ ได้ ขณะเดียวกันก็เคารพกราฟความเกี่ยวข้องที่สร้างขึ้นจากโมดูล Bazel ด้วย
รีโพสิทรี 3 ประเภท ได้แก่ รีโพสิทรีหลัก (ซึ่งเป็นสคีมาซอร์สโค้ดที่คุณทํางานอยู่) รีโพสิทรีที่แสดงถึงโมดูลการพึ่งพาแบบเปลี่ยนผ่าน และรีโพสิทรีที่สร้างโดยส่วนขยายโมดูล จะรวมกันเป็นเวิร์กสเปซ
ระบบจะดึงข้อมูลรีโพสภายนอก (รีโพสที่ไม่ใช่รีโพสหลัก) ตามคําขอ เช่น เมื่อมีการอ้างอิงถึงด้วยป้ายกํากับ (เช่น @repo//pkg:target
) ในไฟล์ BUILD
ประโยชน์
ระบบทรัพยากรภายนอกของ Bazel มีประโยชน์มากมาย
การแก้ไขข้อกำหนดโดยอัตโนมัติ
- การแก้ไขเวอร์ชันแบบกำหนดได้: Bazel ใช้อัลกอริทึมการแก้ไขเวอร์ชันแบบกำหนดได้ของ MVS ซึ่งจะลดความขัดแย้งและแก้ไขปัญหาการพึ่งพาแบบเพชร
- การจัดการทรัพยากร Dependency ที่ง่ายขึ้น:
MODULE.bazel
จะประกาศเฉพาะ Dependency โดยตรงเท่านั้น ขณะที่ Dependency แบบสื่อกลางจะได้รับการแก้ไขโดยอัตโนมัติ ซึ่งจะให้ภาพรวมที่ชัดเจนขึ้นเกี่ยวกับ Dependency ของโปรเจ็กต์ - ระดับการเข้าถึงทรัพยากร Dependency ที่เข้มงวด: ระบบจะแสดงเฉพาะ Dependency โดยตรงเท่านั้น เพื่อให้แน่ใจว่าถูกต้องและคาดการณ์ได้
การผสานรวมระบบนิเวศ
- รีจิสทรีส่วนกลางของ Bazel: ที่เก็บข้อมูลส่วนกลางสําหรับการค้นพบและจัดการทรัพยากรร่วมทั่วไปเป็นโมดูล Bazel
- การนำโปรเจ็กต์ที่ไม่ใช่ Bazel มาใช้: เมื่อนำโปรเจ็กต์ที่ไม่ใช่ Bazel (โดยปกติจะเป็นไลบรารี C++) มาใช้กับ Bazel และทำให้พร้อมใช้งานใน BCR จะช่วยลดความซับซ้อนในการผสานรวมสำหรับทั้งชุมชน และช่วยลดความซ้ำซ้อนและความขัดแย้งของไฟล์ BUILD ที่กําหนดเอง
- การผสานรวมแบบรวมกับเครื่องมือจัดการแพ็กเกจเฉพาะภาษา: ชุดกฎจะลดความซับซ้อนในการผสานรวมกับเครื่องมือจัดการแพ็กเกจภายนอกสำหรับข้อกำหนดที่ไม่เกี่ยวข้องกับ Bazel ซึ่งรวมถึงข้อกำหนดต่อไปนี้
- rules_jvm_external สําหรับ Maven
- rules_python สำหรับ PyPi
- bazel-gazelle สำหรับโมดูล Go
- rules_rust สำหรับ Cargo
ฟีเจอร์ขั้นสูง
- ส่วนขยายโมดูล: ฟีเจอร์
use_repo_rule
และส่วนขยายโมดูลช่วยให้ใช้กฎของที่เก็บข้อมูลที่กำหนดเองและตรรกะการแก้ไขได้อย่างยืดหยุ่นเพื่อนำข้อกำหนดที่ไม่อยู่ใน Bazel มาใช้ - คำสั่ง
bazel mod
: คำสั่งย่อยนี้ช่วยตรวจสอบทรัพยากร Dependency ภายนอกได้ คุณทราบดีว่ามีการกําหนดการพึ่งพาภายนอกอย่างไรและมาจากที่ใด - โหมดผู้ให้บริการ: ดึงข้อมูลการพึ่งพาภายนอกที่แน่นอนซึ่งคุณต้องใช้เพื่ออำนวยความสะดวกในการสร้างแบบออฟไลน์ล่วงหน้า
- ไฟล์ล็อก: ไฟล์ล็อกช่วยปรับปรุงความสามารถในการสร้างซ้ำและเร่งการแก้ไขข้อกำหนด
- (เร็วๆ นี้) การรับรองที่มาของ BCR: เพิ่มความแข็งแกร่งให้กับความปลอดภัยของซัพพลายเชนด้วยการรับรองที่มาของข้อกำหนด
แนวคิด
ส่วนนี้จะให้รายละเอียดเพิ่มเติมเกี่ยวกับแนวคิดที่เกี่ยวข้องกับการอ้างอิงภายนอก
โมดูล
โปรเจ็กต์ Bazel ที่มีได้หลายเวอร์ชัน โดยแต่ละเวอร์ชันอาจมีการพึ่งพาโมดูลอื่นๆ
ในเวิร์กスペース Bazel ในพื้นที่ โมดูลจะแสดงโดยที่เก็บ
โปรดดูรายละเอียดเพิ่มเติมที่โมดูล Bazel
ที่เก็บ
ต้นไม้ไดเรกทอรีที่มีไฟล์เครื่องหมายขอบเขตที่รูท ซึ่งมีไฟล์ต้นฉบับที่ใช้ได้ในบิลด์ Bazel มักย่อเป็น repo
ไฟล์เครื่องหมายขอบเขตของ repo อาจเป็น MODULE.bazel
(บ่งบอกว่า repo นี้แสดงโมดูล Bazel) REPO.bazel
(ดูด้านล่าง) หรือในบริบทเดิม WORKSPACE
หรือ WORKSPACE.bazel
ไฟล์เครื่องหมายขอบเขตของรีโปจะระบุขอบเขตของรีโป โดยไฟล์ดังกล่าวหลายไฟล์สามารถอยู่ร่วมกันในไดเรกทอรีได้
ที่เก็บหลัก
พื้นที่เก็บข้อมูลที่กําลังเรียกใช้คําสั่ง Bazel อยู่
รูทของที่เก็บข้อมูลหลักหรือที่เรียกว่ารูทของพื้นที่ทํางาน
Workspace
สภาพแวดล้อมที่คำสั่ง Bazel ทั้งหมดใช้ร่วมกันจะทำงานในที่เก็บข้อมูลหลักเดียวกัน ซึ่งจะรวมที่เก็บข้อมูลหลักและชุดที่เก็บข้อมูลภายนอกที่กําหนดไว้ทั้งหมด
โปรดทราบว่าที่ผ่านมาแนวคิด "ที่เก็บข้อมูล" และ "เวิร์กสเปซ" มักสับสนกัน คำว่า "เวิร์กสเปซ" มักใช้เพื่ออ้างอิงถึงที่เก็บข้อมูลหลัก และบางครั้งยังใช้เป็นคำพ้องความหมายของ "ที่เก็บข้อมูล" ด้วย
ชื่อที่เก็บ Canonical
ชื่อที่ใช้เรียกที่เก็บได้เสมอ ในบริบทของที่ทำงาน พื้นที่เก็บข้อมูลแต่ละแห่งจะมีชื่อตามหลักเกณฑ์เพียงชื่อเดียว เป้าหมายภายในที่เก็บซึ่งมีชื่อ Canonical เป็น canonical_name
จะเข้าถึงได้ด้วยป้ายกำกับ @@canonical_name//package:target
(โปรดสังเกต @
2 ตัว)
ที่เก็บหลักจะมีสตริงว่างเป็นชื่อตามแบบฉบับเสมอ
ชื่อที่เก็บที่ปรากฏ
ชื่อที่ใช้ระบุที่เก็บในบริบทของที่เก็บอื่น คุณสามารถมองชื่อนี้ว่าเป็น "ชื่อเล่น" ของรีโปได้ นั่นคือ รีโปที่มีชื่อตามหลักเกณฑ์ michael
อาจมีชื่อที่ปรากฏเป็น mike
ในบริบทของรีโป alice
แต่อาจมีชื่อที่ปรากฏเป็น mickey
ในบริบทของรีโป bob
ในกรณีนี้ เป้าหมายภายใน michael
สามารถเข้าถึงได้ด้วยป้ายกำกับ
@mike//package:target
ในบริบทของ alice
(โปรดสังเกต @
ตัวเดียว)
หรือจะเข้าใจว่าเป็นการแมปที่เก็บก็ได้ โดยที่แต่ละที่เก็บจะรักษาการแมปจาก "ชื่อที่เก็บที่ปรากฏ" ไปยัง "ชื่อที่เก็บตามหลักเกณฑ์"
กฎที่เก็บ
สคีมาสำหรับคำจำกัดความของที่เก็บข้อมูลที่บอก Bazel เกี่ยวกับวิธีสร้างที่เก็บข้อมูล เช่น "ดาวน์โหลดไฟล์ ZIP จาก URL บางรายการและแตกไฟล์" หรือ "ดึงข้อมูลอาร์ติแฟกต์ Maven บางรายการและทำให้พร้อมใช้งานเป็นเป้าหมาย java_import
" หรือเพียงแค่ "ลิงก์สัญลักษณ์ไดเรกทอรีในเครื่อง" รีโพสิทอรี่ทุกรายการจะกำหนดโดยการเรียกใช้กฎรีโพสิทอรี่ที่มีจำนวนอาร์กิวเมนต์ที่เหมาะสม
ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีเขียนกฎของที่เก็บข้อมูลของคุณเองได้ที่กฎของที่เก็บข้อมูล
กฎที่ใช้กับรีโพซิทอรีที่พบบ่อยที่สุดคือ http_archive
ซึ่งจะดาวน์โหลดไฟล์เก็บถาวรจาก URL และแตกไฟล์ และ local_repository
ซึ่งจะลิงก์ไดเรกทอรีในเครื่องที่เป็นที่เก็บข้อมูล Bazel อยู่แล้ว
ดึงข้อมูลที่เก็บ
การดำเนินการทําให้รีโปพร้อมใช้งานบนดิสก์ในเครื่องโดยการเรียกใช้กฎรีโปที่เกี่ยวข้อง รีโพซิทอรีที่กําหนดไว้ในเวิร์กสเปซจะไม่พร้อมใช้งานในดิสก์ในเครื่องก่อนที่จะมีการดึงข้อมูล
โดยปกติแล้ว Bazel จะดึงข้อมูลรีโปก็ต่อเมื่อต้องการข้อมูลจากรีโปนั้น และยังไม่ได้ดึงข้อมูลรีโปนั้น หากดึงข้อมูลรีโปไปแล้วก่อนหน้านี้ Bazel จะดึงข้อมูลอีกครั้งก็ต่อเมื่อคําจํากัดความของรีโปมีการเปลี่ยนแปลงเท่านั้น
คุณสามารถใช้คำสั่ง fetch
เพื่อเริ่มการดึงข้อมูลล่วงหน้าสำหรับที่เก็บ เป้าหมาย หรือที่เก็บที่จำเป็นทั้งหมดเพื่อทำการบิลด์ ความสามารถนี้ช่วยให้คุณสร้างแบบออฟไลน์ได้โดยใช้ตัวเลือก --nofetch
ตัวเลือก --fetch
มีไว้เพื่อจัดการการเข้าถึงเครือข่าย ค่าเริ่มต้นคือ "จริง"
อย่างไรก็ตาม เมื่อตั้งค่าเป็นเท็จ (--nofetch
) คำสั่งจะใช้เวอร์ชันของข้อกำหนดซึ่งแคชไว้ หากไม่มี คำสั่งจะดำเนินการไม่สำเร็จ
ดูข้อมูลเพิ่มเติมเกี่ยวกับการควบคุมการดึงข้อมูลได้ที่ตัวเลือกการดึงข้อมูล
เลย์เอาต์ไดเรกทอรี
หลังจากดึงข้อมูลแล้ว คุณจะเห็นที่เก็บในไดเรกทอรีย่อย external
ในฐานเอาต์พุต ภายใต้ชื่อ Canonical
คุณสามารถเรียกใช้คําสั่งต่อไปนี้เพื่อดูเนื้อหาของรีโปที่มีชื่อตามหลักเกณฑ์ canonical_name
ls $(bazel info output_base)/external/ canonical_name
ไฟล์ REPO.bazel
ระบบจะใช้ไฟล์ REPO.bazel
เพื่อทําเครื่องหมายขอบเขตด้านบนสุดของโครงสร้างไดเรกทอรีที่ประกอบกันเป็นรีโป ไฟล์นี้ไม่จำเป็นต้องมีข้อมูลใดๆ เพื่อใช้เป็นไฟล์ขอบเขตของรีโป แต่สามารถใช้เพื่อระบุแอตทริบิวต์ทั่วไปบางอย่างสำหรับเป้าหมายการสร้างทั้งหมดในรีโปได้
ไวยากรณ์ของไฟล์ REPO.bazel
คล้ายกับไฟล์ BUILD
ยกเว้นที่ไม่รองรับคำสั่ง load
ฟังก์ชัน repo()
ใช้อาร์กิวเมนต์เดียวกับฟังก์ชัน package()
ในไฟล์ BUILD
ส่วน package()
ระบุแอตทริบิวต์ทั่วไปสำหรับเป้าหมายการสร้างทั้งหมดภายในแพ็กเกจ repo()
จะทำแบบเดียวกันสำหรับเป้าหมายการสร้างทั้งหมดภายในที่เก็บ
เช่น คุณสามารถระบุใบอนุญาตทั่วไปสำหรับเป้าหมายทั้งหมดในรีโปโดยต้องมีไฟล์ REPO.bazel
ต่อไปนี้
repo(
default_package_metadata = ["//:my_license"],
)
ระบบ WORKSPACE เดิม
ใน Bazel เวอร์ชันเก่า (ก่อน 9.0) จะมีการนําทรัพยากร Dependency ภายนอกมาใช้โดยการกำหนดที่เก็บในไฟล์ WORKSPACE
(หรือ WORKSPACE.bazel
) ไฟล์นี้มีไวยากรณ์คล้ายกับไฟล์ BUILD
โดยใช้กฎของ repo แทนกฎการสร้าง
ข้อมูลโค้ดต่อไปนี้เป็นตัวอย่างการใช้กฎของที่เก็บ http_archive
ในไฟล์
WORKSPACE
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "foo",
urls = ["https://example.com/foo.zip"],
sha256 = "c9526390a7cd420fdcec2988b4f3626fe9c5b51e2959f685e8f4d170d1a9bd96",
)
ข้อมูลโค้ดจะกำหนดที่เก็บซึ่งมีชื่อ Canonical เป็น foo
ในWORKSPACE
ระบบ โดยค่าเริ่มต้น ชื่อ Canonical ของรีโปจะเป็นชื่อที่ปรากฏสำหรับรีโปอื่นๆ ทั้งหมดด้วย
ดูรายการทั้งหมดของฟังก์ชันที่ใช้ได้ในไฟล์ WORKSPACE
ข้อบกพร่องของระบบ WORKSPACE
ในช่วงหลายปีหลังจากเปิดตัวระบบ WORKSPACE
ผู้ใช้รายงานปัญหาที่พบมากมาย ซึ่งรวมถึงปัญหาต่อไปนี้
- Bazel จะไม่ประเมินไฟล์
WORKSPACE
ของข้อกําหนดใดๆ ดังนั้นคุณต้องกําหนดข้อกําหนดแบบสื่อกลางทั้งหมดในไฟล์WORKSPACE
ของที่เก็บหลัก นอกเหนือจากข้อกําหนดโดยตรง - โครงการต่างๆ จึงใช้รูปแบบ "deps.bzl" เพื่อแก้ปัญหานี้ โดยกำหนดมาโครซึ่งจะกำหนดที่เก็บหลายแห่ง และขอให้ผู้ใช้เรียกใช้มาโครนี้ในไฟล์
WORKSPACE
- วิธีนี้มีปัญหาเช่นกัน เนื่องจากมาโครไม่สามารถเข้าถึง
load
ไฟล์.bzl
อื่นๆ ดังนั้นโปรเจ็กต์เหล่านี้จึงต้องกำหนดการพึ่งพาแบบเปลี่ยนผ่านในมาโคร "deps" นี้ หรือแก้ปัญหานี้โดยให้ผู้ใช้เรียกใช้มาโคร "deps" แบบหลายเลเยอร์ - Bazel จะประเมินไฟล์
WORKSPACE
ตามลําดับ นอกจากนี้ คุณยังระบุข้อกําหนดโดยใช้http_archive
กับ URL ได้โดยไม่ต้องระบุข้อมูลเวอร์ชัน ซึ่งหมายความว่าไม่มีวิธีที่น่าเชื่อถือในการแก้ไขเวอร์ชันในกรณีที่มีการพึ่งพาแบบเพชร (A
ขึ้นอยู่กับB
และC
โดยทั้งB
และC
ขึ้นอยู่กับD
เวอร์ชันต่างๆ)
- วิธีนี้มีปัญหาเช่นกัน เนื่องจากมาโครไม่สามารถเข้าถึง
เนื่องจากข้อบกพร่องของ WORKSPACE ระบบใหม่ที่อิงตามโมดูล (ชื่อรหัส "Bzlmod") จึงค่อยๆ เข้ามาแทนที่ระบบ WORKSPACE เดิมระหว่าง Bazel 6 ถึง 9 อ่านคำแนะนำในการย้ายข้อมูล Bzlmod เกี่ยวกับวิธีย้ายข้อมูลไปยัง Bzlmod