Bazel รองรับ การขึ้นต่อกันภายนอก ไฟล์ต้นฉบับ (ทั้งข้อความและไบนารี) ที่ใช้ ในการบิลด์ซึ่งไม่ได้มาจากพื้นที่ทำงาน เช่น อาจเป็นชุดกฎที่โฮสต์ในที่เก็บ GitHub, อาร์ติแฟกต์ Maven หรือไดเรกทอรีในเครื่องของคุณนอกพื้นที่ทำงานปัจจุบัน
ตั้งแต่ Bazel 6.0 เป็นต้นมา คุณสามารถจัดการทรัพยากร Dependency ภายนอกด้วย Bazel ได้ 2 วิธี ได้แก่
ระบบ WORKSPACE แบบดั้งเดิมที่เน้นที่เก็บข้อมูล และ
ระบบ MODULE.bazel ใหม่ที่เน้นโมดูล (ชื่อรหัส Bzlmod,
และเปิดใช้ด้วยแฟล็ก --enable_bzlmod) คุณสามารถใช้ระบบทั้งสองร่วมกันได้
แต่ Bzlmod จะมาแทนที่ระบบ WORKSPACE ใน Bazel เวอร์ชันต่อๆ ไป
โปรดดูคำแนะนำในการย้ายข้อมูล Bzlmod เกี่ยวกับวิธีย้ายข้อมูล
เอกสารนี้จะอธิบายแนวคิดเกี่ยวกับการจัดการทรัพยากร Dependency ภายนอกใน Bazel ก่อนที่จะลงรายละเอียดเพิ่มเติมเกี่ยวกับระบบทั้งสองตามลำดับ
แนวคิด
ที่เก็บ
แผนผังไดเรกทอรีที่มีไฟล์เครื่องหมายขอบเขตที่รูท ซึ่งมีไฟล์ต้นฉบับที่ใช้ได้ในบิลด์ Bazel มักเรียกสั้นๆ ว่า repo
ไฟล์เครื่องหมายขอบเขตของ repo อาจเป็น MODULE.bazel (บ่งบอกว่า repo นี้แสดงโมดูล Bazel), REPO.bazel (ดู ด้านล่าง) หรือในบริบทเดิม WORKSPACE หรือ WORKSPACE.bazel ไฟล์เครื่องหมายขอบเขตของ repo จะระบุขอบเขตของ repo โดยไฟล์ดังกล่าวจะอยู่ในไดเรกทอรีร่วมกันได้หลายไฟล์
ที่เก็บหลัก
ที่เก็บที่กำลังเรียกใช้คำสั่ง Bazel ปัจจุบัน
รูทของที่เก็บหลักเรียกอีกอย่างว่า รูทพื้นที่ทำงาน
พื้นที่ทำงาน
สภาพแวดล้อมที่คำสั่ง Bazel ทั้งหมดใช้ร่วมกันจะทำงานจากที่เก็บหลักเดียวกัน ซึ่งครอบคลุมที่เก็บหลักและชุดที่เก็บภายนอกทั้งหมดที่กำหนดไว้
โปรดทราบว่าที่ผ่านมาแนวคิด "ที่เก็บข้อมูล" และ "พื้นที่ทำงาน" มักใช้รวมๆ กัน คำว่า "พื้นที่ทำงาน" มักใช้เพื่ออ้างอิงถึงที่เก็บข้อมูลหลัก และบางครั้งยังใช้เป็นคำพ้องความหมายของ "ที่เก็บข้อมูล" ด้วย
ชื่อที่เก็บ Canonical
ชื่อ Canonical ที่ใช้ระบุที่เก็บ ในบริบทของพื้นที่ทำงาน ที่เก็บแต่ละแห่งจะมีชื่อ Canonical เดียว เป้าหมายภายในที่เก็บ
ที่มีชื่อ Canonical เป็น canonical_name สามารถระบุได้ด้วยป้ายกำกับ
@@canonical_name//package:target (โปรดสังเกต @ 2 ตัว)
ที่เก็บหลักจะมีสตริงว่างเป็นชื่อ Canonical เสมอ
ชื่อที่เก็บที่ปรากฏ
ชื่อที่ใช้ระบุที่เก็บในบริบทของที่เก็บอื่น
คุณอาจคิดว่าชื่อนี้เป็น "ชื่อเล่น" ของที่เก็บได้ เช่น ที่เก็บที่มีชื่อ Canonical เป็น michael อาจมีชื่อที่ปรากฏเป็น mike ในบริบทของที่เก็บ alice แต่มีชื่อที่ปรากฏเป็น mickey ในบริบทของที่เก็บ bob ในกรณีนี้ เป้าหมายภายใน michael สามารถระบุได้ด้วยป้ายกำกับ
@mike//package:target ในบริบทของ alice (โปรดสังเกต @ ตัวเดียว)
ในทางกลับกัน คุณอาจเข้าใจได้ว่าชื่อนี้เป็นการแมปที่เก็บ โดยที่เก็บแต่ละแห่ง เก็บรักษาการแมปจาก "ชื่อที่เก็บที่ปรากฏ" ไปยัง "ชื่อที่เก็บ Canonical"
กฎของที่เก็บ
สคีมาสำหรับคำจำกัดความของที่เก็บข้อมูลที่บอก Bazel ว่าจะแสดงที่เก็บข้อมูลอย่างไร เช่น "ดาวน์โหลดไฟล์เก็บถาวร zip จาก URL ที่ระบุและแตกไฟล์" หรือ "ดึงข้อมูลอาร์ติแฟกต์ Maven ที่ระบุและทำให้พร้อมใช้งานเป็นเป้าหมาย java_import" หรือเพียง "สร้างลิงก์สัญลักษณ์ของไดเรกทอรีในเครื่อง" ทุกที่เก็บจะกำหนด โดยการเรียกใช้กฎของที่เก็บด้วยจำนวนอาร์กิวเมนต์ที่เหมาะสม
ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีเขียน กฎของที่เก็บของคุณเองได้ที่กฎของที่เก็บ
กฎของที่เก็บที่ใช้กันมากที่สุดคือ
http_archive ซึ่งดาวน์โหลดไฟล์เก็บถาวร
จาก URL และแตกไฟล์ และ
local_repository ซึ่งสร้างลิงก์สัญลักษณ์ของ
ไดเรกทอรีในเครื่องที่เป็นที่เก็บ Bazel อยู่แล้ว
ดึงข้อมูลที่เก็บ
การดำเนินการทำให้ที่เก็บพร้อมใช้งานในดิสก์ในเครื่องโดยการเรียกใช้กฎของที่เก็บที่เชื่อมโยง ที่เก็บที่กำหนดไว้ในพื้นที่ทำงานจะไม่พร้อมใช้งานในดิสก์ในเครื่องจนกว่าจะมีการดึงข้อมูล
โดยปกติแล้ว Bazel จะดึงข้อมูลที่เก็บก็ต่อเมื่อต้องการบางอย่างจากที่เก็บนั้น และยังไม่ได้ดึงข้อมูลที่เก็บ หากมีการดึงข้อมูลที่เก็บไปแล้วก่อนหน้านี้ Bazel จะดึงข้อมูลอีกครั้งก็ต่อเมื่อคำจำกัดความของที่เก็บมีการเปลี่ยนแปลง
คุณสามารถใช้คำสั่ง fetch เพื่อเริ่มการดึงข้อมูลล่วงหน้าสำหรับที่เก็บ เป้าหมาย หรือที่เก็บที่จำเป็นทั้งหมดเพื่อทำการบิลด์ ความสามารถนี้ช่วยให้สามารถทำการบิลด์แบบออฟไลน์ได้โดยใช้ตัวเลือก --nofetch
ตัวเลือก --fetch มีไว้เพื่อจัดการการเข้าถึงเครือข่าย ค่าเริ่มต้นคือ True
อย่างไรก็ตาม เมื่อตั้งค่าเป็น False (--nofetch) คำสั่งจะใช้เวอร์ชันที่แคชไว้ของทรัพยากร Dependency และหากไม่มี คำสั่งจะส่งผลให้เกิดข้อผิดพลาด
ดูข้อมูลเพิ่มเติมเกี่ยวกับการควบคุมการดึงข้อมูลได้ที่ ตัวเลือกการดึงข้อมูล
เลย์เอาต์ไดเรกทอรี
หลังจากดึงข้อมูลแล้ว คุณจะพบที่เก็บในไดเรกทอรีย่อย external ใน
เอาต์พุตเบสภายใต้ชื่อ Canonical
คุณสามารถเรียกใช้คำสั่งต่อไปนี้เพื่อดูเนื้อหาของที่เก็บที่มีชื่อ Canonical เป็น canonical_name
ls $(bazel info output_base)/external/ canonical_name ไฟล์ REPO.bazel
ไฟล์ REPO.bazel ใช้เพื่อทำเครื่องหมายขอบเขตบนสุดของแผนผังไดเรกทอรีที่เป็นที่เก็บ ไฟล์นี้ไม่จำเป็นต้องมีเนื้อหาใดๆ เพื่อใช้เป็นไฟล์ขอบเขตของที่เก็บ แต่คุณยังใช้ไฟล์นี้เพื่อระบุแอตทริบิวต์ทั่วไปบางอย่างสำหรับเป้าหมายการบิลด์ทั้งหมดภายในที่เก็บได้ด้วย
ไวยากรณ์ของไฟล์ REPO.bazel จะคล้ายกับไฟล์ BUILD ยกเว้นว่าจะไม่รองรับคำสั่ง load และมีเพียงฟังก์ชันเดียวคือ repo() ที่พร้อมใช้งาน repo() จะใช้อาร์กิวเมนต์เดียวกับ package()
ฟังก์ชัน ในไฟล์ BUILD โดยที่ package()
จะระบุแอตทริบิวต์ทั่วไปสำหรับเป้าหมายการบิลด์ทั้งหมดภายในแพ็กเกจ ส่วน repo()
จะทำเช่นเดียวกันสำหรับเป้าหมายการบิลด์ทั้งหมดภายในที่เก็บ
ตัวอย่างเช่น คุณระบุใบอนุญาตทั่วไปสำหรับเป้าหมายทั้งหมดในที่เก็บได้โดยใช้ไฟล์ REPO.bazel ต่อไปนี้
repo(
default_package_metadata = ["//:my_license"],
)
จัดการการขึ้นต่อกันภายนอกด้วย Bzlmod
Bzlmod ซึ่งเป็นระบบย่อยใหม่สำหรับทรัพยากร Dependency ภายนอกจะไม่ทำงานกับคำจำกัดความของที่เก็บโดยตรง แต่จะสร้างกราฟการขึ้นต่อกันจาก โมดูล เรียกใช้ ส่วนขยาย ที่ด้านบนของกราฟ และกำหนดที่เก็บตามนั้น
โมดูล Bazel คือโปรเจ็กต์ Bazel ที่มีหลาย
เวอร์ชัน โดยแต่ละเวอร์ชันจะเผยแพร่ข้อมูลเมตาเกี่ยวกับโมดูลอื่นๆ ที่ขึ้นต่อกัน
โมดูลต้องมีไฟล์ MODULE.bazel ที่รูทของที่เก็บข้างไฟล์ WORKSPACE ไฟล์นี้เป็นไฟล์ 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")
โมดูลต้องแสดงรายการเฉพาะการขึ้นต่อกันโดยตรง ซึ่ง Bzlmod จะค้นหาใน
รีจิสทรี Bazel ซึ่งโดยค่าเริ่มต้นคือ รีจิสทรีกลาง
ของ Bazel รีจิสทรีจะให้ไฟล์ MODULE.bazel ของทรัพยากร Dependency ซึ่งช่วยให้ Bazel ค้นพบกราฟทรัพยากร Dependency แบบทรานซิทีฟทั้งหมดก่อนที่จะทำการแก้ปัญหาเวอร์ชัน
หลังจากแก้ปัญหาเวอร์ชันแล้ว ซึ่งจะมีการเลือกเวอร์ชันเดียวสำหรับแต่ละโมดูล Bazel จะปรึกษาข้อมูลรีจิสทรีอีกครั้งเพื่อดูวิธีกำหนดที่เก็บสำหรับแต่ละโมดูล (ในกรณีส่วนใหญ่จะใช้ http_archive)
โมดูลยังระบุข้อมูลที่กำหนดเองที่เรียกว่า แท็ก ได้ด้วย ซึ่ง ส่วนขยายโมดูล จะใช้แท็กเหล่านี้หลังจากแก้ปัญหาโมดูล เพื่อกำหนดที่เก็บเพิ่มเติม ส่วนขยายเหล่านี้มีความสามารถคล้ายกับกฎของที่เก็บ ซึ่งช่วยให้ดำเนินการต่างๆ เช่น I/O ของไฟล์และการส่งคำขอเครือข่ายได้ นอกจากนี้ ส่วนขยายยังช่วยให้ Bazel โต้ตอบกับระบบการจัดการแพ็กเกจอื่นๆ ได้ในขณะที่ยังคงพิจารณากราฟทรัพยากร Dependency ที่สร้างจากโมดูล Bazel
ลิงก์ภายนอกใน Bzlmod
- ตัวอย่างการใช้งาน Bzlmod ใน bazelbuild/examples
- Bazel External Dependencies Overhaul (เอกสารการออกแบบ Bzlmod ต้นฉบับ)
- การบรรยายเรื่อง Bzlmod ใน BazelCon 2021
- การบรรยายเรื่อง Bzlmod ใน Bazel Community Day
กำหนดที่เก็บด้วย WORKSPACE
ในอดีต คุณสามารถจัดการการขึ้นต่อกันภายนอกได้โดยการกำหนดที่เก็บในไฟล์
WORKSPACE (หรือ WORKSPACE.bazel) ไฟล์นี้มีไวยากรณ์คล้ายกับไฟล์ BUILD โดยใช้กฎของที่เก็บแทนกฎการบิลด์
ข้อมูลโค้ดต่อไปนี้เป็นตัวอย่างการใช้กฎของที่เก็บ 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 เวอร์ชันต่อๆ ไป โปรดอ่านคู่มือการย้ายข้อมูล Bzlmodเกี่ยวกับวิธีย้ายข้อมูลไปยัง Bzlmod