Bazel รองรับการอ้างอิงภายนอก ไฟล์ต้นฉบับ (ทั้งข้อความและไบนารี) ที่ใช้ ในบิลด์ซึ่งไม่ได้มาจากพื้นที่ทำงาน เช่น อาจเป็นชุดกฎที่โฮสต์ในที่เก็บ GitHub, อาร์ติแฟกต์ Maven หรือไดเรกทอรีในเครื่องของคุณนอกพื้นที่ทำงานปัจจุบัน
เอกสารนี้จะให้ภาพรวมของระบบก่อนที่จะพิจารณาแนวคิดบางอย่างในรายละเอียดเพิ่มเติม
ภาพรวมของระบบ
ระบบการอ้างอิงภายนอกของ Bazel ทำงานบนพื้นฐานของโมดูล Bazel ซึ่งแต่ละโมดูลเป็นโปรเจ็กต์ Bazel ที่มีการควบคุมเวอร์ชัน และที่เก็บ (หรือ repo) ซึ่งเป็นโครงสร้างไดเรกทอรีที่มีไฟล์ต้นฉบับ
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 รีจิสทรีมีไฟล์MODULE.bazelของการอ้างอิง ซึ่งช่วยให้ Bazel ค้นพบกราฟการอ้างอิงแบบทรานซิทีฟทั้งหมดได้ก่อนที่จะทำการแก้ปัญหาเวอร์ชัน
หลังจากแก้ไขเวอร์ชันแล้ว ซึ่งจะมีการเลือกเวอร์ชันหนึ่งสำหรับแต่ละโมดูล Bazel จะปรึกษารีจิสทรีอีกครั้งเพื่อดูวิธีระบุที่เก็บสำหรับแต่ละโมดูล นั่นคือ วิธีดึงข้อมูลแหล่งที่มาสำหรับโมดูลการขึ้นต่อกันแต่ละรายการ ส่วนใหญ่แล้ว ไฟล์เหล่านี้เป็นเพียงไฟล์ที่ดาวน์โหลดจากอินเทอร์เน็ตและแตกไฟล์
นอกจากนี้ โมดูลยังระบุข้อมูลที่กำหนดเองซึ่งเรียกว่าแท็กได้ด้วย ซึ่งส่วนขยายโมดูลจะใช้แท็กเหล่านี้หลังจากที่โมดูลได้รับการแก้ไขแล้ว เพื่อกำหนด repo เพิ่มเติม ส่วนขยายเหล่านี้สามารถดำเนินการต่างๆ เช่น I/O ของไฟล์ และการส่งคำขอเครือข่าย ซึ่งจะช่วยให้ Bazel โต้ตอบกับระบบการจัดการแพ็กเกจอื่นๆ ได้ รวมถึงยังคงใช้กราฟการอ้างอิงที่สร้างจากโมดูล Bazel ด้วย
ที่เก็บข้อมูล 3 ประเภท ได้แก่ ที่เก็บข้อมูลหลัก (ซึ่งเป็นโครงสร้างแหล่งที่มาที่คุณกำลังทำงานอยู่) ที่เก็บข้อมูลที่แสดงโมดูลการอ้างอิงแบบทรานซิทีฟ และที่เก็บข้อมูลที่สร้างโดยส่วนขยายของโมดูล จะรวมกันเป็นพื้นที่ทำงาน
ระบบจะดึงข้อมูลที่เก็บภายนอก (ที่เก็บที่ไม่ใช่ที่เก็บหลัก) ตามต้องการ เช่น เมื่อมีการอ้างอิงที่เก็บเหล่านั้นโดยป้ายกำกับ (เช่น @repo//pkg:target) ในไฟล์ BUILD
ข้อดี
ระบบการขึ้นต่อกันภายนอกของ Bazel มีประโยชน์มากมาย
การแก้ปัญหาการขึ้นต่อกันโดยอัตโนมัติ
- การกำหนดเวอร์ชันที่แน่นอน: Bazel ใช้การกำหนดเวอร์ชันที่แน่นอน MVS เพื่อลดความขัดแย้งและแก้ปัญหาการขึ้นต่อกันแบบไดมอนด์
- การจัดการการขึ้นต่อกันที่ง่ายขึ้น:
MODULE.bazelประกาศเฉพาะการขึ้นต่อกันโดยตรง ในขณะที่การขึ้นต่อกันแบบทรานซิทีฟจะได้รับการแก้ไขโดยอัตโนมัติ ซึ่งจะให้ภาพรวมที่ชัดเจนยิ่งขึ้นของการขึ้นต่อกันของโปรเจ็กต์ - ระดับการเข้าถึงการขึ้นต่อกันอย่างเข้มงวด: เฉพาะการขึ้นต่อกันโดยตรงเท่านั้นที่มองเห็นได้ เพื่อให้มั่นใจในความถูกต้องและ ความสามารถในการคาดการณ์
การผสานรวมระบบนิเวศ
- รีจิสทรีกลางของ Bazel: ที่เก็บข้อมูลส่วนกลางสำหรับค้นหาและจัดการการอ้างอิงทั่วไปเป็นโมดูล Bazel
- การนำโปรเจ็กต์ที่ไม่ใช่ Bazel มาใช้: เมื่อมีการปรับโปรเจ็กต์ที่ไม่ใช่ Bazel (โดยปกติคือไลบรารี C++) ให้ใช้กับ Bazel และพร้อมใช้งานใน BCR ก็จะช่วยให้การผสานรวมโปรเจ็กต์ดังกล่าวเป็นไปอย่างราบรื่นสำหรับทั้งชุมชน รวมถึงช่วยลดความพยายามที่ซ้ำซ้อนและความขัดแย้งของไฟล์ BUILD ที่กำหนดเอง
- การผสานรวมแบบรวมกับเครื่องมือจัดการแพ็กเกจเฉพาะภาษา: ชุดกฎ
ช่วยลดความซับซ้อนในการผสานรวมกับเครื่องมือจัดการแพ็กเกจภายนอกสำหรับทรัพยากร Dependency ที่ไม่ใช่ Bazel
ซึ่งรวมถึงรายการต่อไปนี้
- rules_jvm_external สำหรับ Maven
- rules_python สำหรับ PyPi
- bazel-gazelle สำหรับ Go Modules
- rules_rust สำหรับ Cargo
ฟีเจอร์ขั้นสูง
- ส่วนขยายโมดูล: ฟีเจอร์
use_repo_ruleและส่วนขยายโมดูล ช่วยให้ใช้กฎที่กำหนดเองของที่เก็บและ ตรรกะการแก้ปัญหาได้อย่างยืดหยุ่นเพื่อนำเข้าการขึ้นต่อกันที่ไม่ใช่ Bazel bazel modCommand: คำสั่งย่อยมีวิธีที่มีประสิทธิภาพในการตรวจสอบทรัพยากร Dependency ภายนอก คุณทราบอย่างชัดเจนว่ามีการกำหนดการอ้างอิงภายนอกอย่างไรและมาจากที่ใด- โหมดผู้ให้บริการ: ดึงข้อมูลการอ้างอิงภายนอกที่แน่นอนล่วงหน้า ซึ่งคุณต้องใช้เพื่ออำนวยความสะดวกในการสร้างแบบออฟไลน์
- ไฟล์ล็อก: ไฟล์ล็อกช่วยปรับปรุงความสามารถในการทำซ้ำของบิลด์และ เร่งการแก้ปัญหาการขึ้นต่อกัน
- (เร็วๆ นี้) การรับรองแหล่งที่มาของ BCR: เสริมความแข็งแกร่งด้านความปลอดภัยของซัพพลายเชนด้วยการตรวจสอบแหล่งที่มาที่ยืนยันแล้วของ การอ้างอิง
แนวคิด
ส่วนนี้จะให้รายละเอียดเพิ่มเติมเกี่ยวกับแนวคิดที่เกี่ยวข้องกับการอ้างอิงภายนอก
โมดูล
โปรเจ็กต์ Bazel ที่มีได้หลายเวอร์ชัน โดยแต่ละเวอร์ชันอาจมี การอ้างอิงโมดูลอื่นๆ
ในพื้นที่ทำงาน Bazel ในเครื่อง โมดูลจะแสดงโดยที่เก็บ
ดูรายละเอียดเพิ่มเติมได้ที่โมดูล Bazel
ที่เก็บ
แผนผังไดเรกทอรีที่มีไฟล์เครื่องหมายขอบเขตที่รูท ซึ่งมีไฟล์ต้นฉบับที่ใช้ได้ในบิลด์ Bazel มักเรียกสั้นๆ ว่า repo
ไฟล์เครื่องหมายขอบเขตของ repo อาจเป็น MODULE.bazel (บ่งบอกว่า repo นี้แสดงโมดูล Bazel), REPO.bazel (ดูด้านล่าง) หรือในบริบทเดิม WORKSPACE หรือ WORKSPACE.bazel ไฟล์เครื่องหมายขอบเขตของ repo จะระบุขอบเขตของ repo โดยไฟล์ดังกล่าวจะอยู่ในไดเรกทอรีร่วมกันได้หลายไฟล์
ที่เก็บหลัก
ที่เก็บที่กำลังเรียกใช้คำสั่ง Bazel ปัจจุบัน
รูทของที่เก็บหลักยังเรียกว่ารูทของพื้นที่ทำงานด้วย
Workspace
สภาพแวดล้อมที่คำสั่ง Bazel ทั้งหมดใช้ร่วมกันจะทำงานในที่เก็บหลักเดียวกัน โดยจะครอบคลุมทั้งที่เก็บหลักและชุดที่เก็บภายนอกทั้งหมดที่กำหนด
โปรดทราบว่าที่ผ่านมาแนวคิด "ที่เก็บข้อมูล" และ "พื้นที่ทำงาน" มักใช้รวมๆ กัน คำว่า "พื้นที่ทำงาน" มักใช้เพื่ออ้างอิงถึงที่เก็บข้อมูลหลัก และบางครั้งยังใช้เป็นคำพ้องความหมายของ "ที่เก็บข้อมูล" ด้วย
ชื่อที่เก็บ Canonical
ชื่อที่ใช้ในการระบุที่เก็บเสมอ ในบริบทของเวิร์กสเปซ
ที่เก็บข้อมูลแต่ละรายการจะมีชื่อมาตรฐานเพียงชื่อเดียว เป้าหมายภายในที่เก็บ
ซึ่งมีชื่อ Canonical เป็น canonical_name สามารถระบุได้ด้วยป้ายกำกับ
@@canonical_name//package:target (โปรดสังเกต @ สองตัว)
ที่เก็บข้อมูลหลักจะมีสตริงว่างเป็นชื่อที่แน่นอนเสมอ
ชื่อที่เก็บที่ชัดเจน
ชื่อที่ใช้ในการระบุที่เก็บในบริบทของที่เก็บอื่น
คุณอาจคิดว่านี่คือ "ชื่อเล่น" ของที่เก็บ: ที่เก็บที่มีชื่อมาตรฐาน michael อาจมีชื่อที่ปรากฏ mike ในบริบทของที่เก็บ alice แต่ก็อาจมีชื่อที่ปรากฏ mickey ในบริบทของที่เก็บ bob ในกรณีนี้ เป้าหมายภายใน michael สามารถระบุได้โดยใช้ป้ายกำกับ
@mike//package:target ในบริบทของ alice (โปรดสังเกต @ เดียว)
ในทางกลับกัน คุณสามารถเข้าใจได้ว่านี่คือการแมปที่เก็บ โดยที่เก็บแต่ละรายการ จะมีการแมปจาก "ชื่อที่เก็บที่ปรากฏ" ไปยัง "ชื่อที่เก็บที่แน่นอน"
กฎที่เก็บ
สคีมาสำหรับคำจำกัดความของที่เก็บข้อมูลที่บอก Bazel ว่าจะแสดงที่เก็บข้อมูลอย่างไร เช่น อาจเป็น "ดาวน์โหลดไฟล์เก็บถาวร ZIP จาก URL หนึ่งๆ
แล้วแตกไฟล์" หรือ "ดึงข้อมูลอาร์ติแฟกต์ Maven หนึ่งๆ แล้วทำให้พร้อมใช้งานเป็น
java_import เป้าหมาย" หรือเพียงแค่ "สร้างลิงก์สัญลักษณ์ไปยังไดเรกทอรีในเครื่อง" ทุกที่เก็บจะกำหนดโดยการเรียกกฎที่เก็บด้วยจำนวนอาร์กิวเมนต์ที่เหมาะสม
ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีเขียนกฎของที่เก็บได้ที่กฎของที่เก็บ
กฎของ repo ที่พบบ่อยที่สุดคือ http_archive ซึ่งจะดาวน์โหลดไฟล์เก็บถาวรจาก URL และแตกไฟล์ และ local_repository ซึ่งจะสร้างลิงก์สัญลักษณ์ไปยังไดเรกทอรีในเครื่องที่เป็นที่เก็บ Bazel อยู่แล้ว
ดึงข้อมูลที่เก็บ
การดำเนินการทำให้ที่เก็บพร้อมใช้งานในดิสก์ในเครื่องโดยการเรียกใช้กฎที่เก็บที่เชื่อมโยง ที่เก็บที่กำหนดไว้ในพื้นที่ทำงานจะไม่พร้อมใช้งานในดิสก์ในเครื่อง ก่อนที่จะมีการดึงข้อมูล
โดยปกติแล้ว Bazel จะดึงข้อมูลที่เก็บก็ต่อเมื่อต้องการบางอย่างจากที่เก็บ และยังไม่ได้ดึงข้อมูลที่เก็บ หากดึงข้อมูลที่เก็บมาก่อนแล้ว Bazel จะดึงข้อมูลอีกครั้งก็ต่อเมื่อคำจำกัดความมีการเปลี่ยนแปลง
คำสั่ง fetch สามารถใช้เพื่อเริ่มการดึงข้อมูลล่วงหน้าสำหรับที่เก็บ
เป้าหมาย หรือที่เก็บที่จำเป็นทั้งหมดเพื่อทำการบิลด์ ความสามารถนี้
ช่วยให้สร้างแบบออฟไลน์ได้โดยใช้ตัวเลือก --nofetch
--fetch ตัวเลือกนี้ใช้เพื่อจัดการการเข้าถึงเครือข่าย ค่าเริ่มต้นคือ True
อย่างไรก็ตาม เมื่อตั้งค่าเป็น false (--nofetch) คำสั่งจะใช้เวอร์ชันที่แคชไว้ของ Dependency และหากไม่มี คำสั่งจะทำงานไม่สำเร็จ
ดูข้อมูลเพิ่มเติมเกี่ยวกับการควบคุมการดึงข้อมูลได้ที่ตัวเลือกการดึงข้อมูล
เลย์เอาต์ไดเรกทอรี
หลังจากดึงข้อมูลแล้ว คุณจะพบที่เก็บในไดเรกทอรีย่อย external ในเอาต์พุตเบสภายใต้ชื่อ Canonical
คุณเรียกใช้คำสั่งต่อไปนี้เพื่อดูเนื้อหาของที่เก็บด้วยชื่อที่แน่นอน canonical_name ได้
ls $(bazel info output_base)/external/ canonical_name ไฟล์ REPO.bazel
ไฟล์ REPO.bazel ใช้เพื่อทำเครื่องหมายขอบเขตบนสุดของโครงสร้างไดเรกทอรีที่ประกอบเป็นที่เก็บ ไฟล์นี้ไม่จำเป็นต้องมีเนื้อหาใดๆ เพื่อใช้เป็นไฟล์ขอบเขตของ repo แต่ก็สามารถใช้เพื่อระบุแอตทริบิวต์ทั่วไปบางอย่างสำหรับเป้าหมายการสร้างทั้งหมดภายใน repo ได้เช่นกัน
ไวยากรณ์ของไฟล์ REPO.bazel จะคล้ายกับไฟล์ BUILD ยกเว้นว่าจะไม่รองรับคำสั่ง
load ฟังก์ชัน repo() จะใช้อาร์กิวเมนต์เดียวกันกับฟังก์ชัน package() ในไฟล์ BUILD ในขณะที่ package()
จะระบุแอตทริบิวต์ทั่วไปสำหรับเป้าหมายการสร้างทั้งหมดภายในแพ็กเกจ repo()
จะทำเช่นเดียวกันสำหรับเป้าหมายการสร้างทั้งหมดภายในที่เก็บ
เช่น คุณสามารถระบุใบอนุญาตทั่วไปสำหรับเป้าหมายทั้งหมดในที่เก็บได้โดยมีไฟล์ REPO.bazel ดังนี้
repo(
default_package_metadata = ["//:my_license"],
)
ระบบ WORKSPACE เดิม
ใน Bazel เวอร์ชันเก่า (ก่อน 9.0) มีการนำทรัพยากร Dependency ภายนอกมาใช้โดยการกำหนด repo ในไฟล์ WORKSPACE (หรือ WORKSPACE.bazel) ไฟล์นี้มีไวยากรณ์คล้ายกับไฟล์ BUILD โดยใช้กฎ repo แทนกฎการสร้าง
ข้อมูลโค้ดต่อไปนี้เป็นตัวอย่างการใช้กฎ http_archive repo ในไฟล์
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ของทรัพยากร Dependency ใดๆ ดังนั้นต้องกำหนดทรัพยากร Dependency แบบทรานซิทีฟทั้งหมดในไฟล์WORKSPACEของที่เก็บหลัก นอกเหนือจากทรัพยากร Dependency โดยตรง - โปรเจ็กต์จึงใช้รูปแบบ "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