Bazel รองรับการขึ้นต่อกันภายนอก ไฟล์ต้นฉบับ (ทั้งข้อความและไบนารี) ที่ใช้ ในบิลด์ซึ่งไม่ได้มาจากพื้นที่ทำงาน เช่น อาจเป็นชุดกฎที่โฮสต์ในที่เก็บ GitHub, อาร์ติแฟกต์ Maven หรือไดเรกทอรีในเครื่องของคุณนอกพื้นที่ทำงานปัจจุบัน
ตั้งแต่ Bazel 6.0 เป็นต้นไป คุณจะจัดการการขึ้นต่อกันภายนอกด้วย Bazel ได้ 2 วิธี ได้แก่
WORKSPACEระบบแบบเดิมที่เน้นที่เก็บ และ
MODULE.bazelระบบใหม่ที่เน้นโมดูล (มีชื่อรหัสว่า Bzlmod
และเปิดใช้ด้วยแฟล็ก --enable_bzlmod) คุณใช้ทั้ง 2 ระบบร่วมกันได้ แต่ Bzlmod จะแทนที่ระบบ WORKSPACE ใน Bazel รุ่นต่อๆ ไป โปรดดูคู่มือการย้ายข้อมูล Bzlmod เกี่ยวกับวิธีย้ายข้อมูล
เอกสารนี้อธิบายแนวคิดเกี่ยวกับการจัดการทรัพยากร Dependency ภายนอกใน Bazel ก่อนที่จะลงรายละเอียดเกี่ยวกับระบบทั้ง 2 ระบบตามลำดับ
แนวคิด
ที่เก็บ
แผนผังไดเรกทอรีที่มีไฟล์เครื่องหมายขอบเขตที่รูท ซึ่งมีไฟล์ต้นฉบับที่ใช้ได้ในบิลด์ Bazel มักเรียกสั้นๆ ว่า repo
ไฟล์เครื่องหมายขอบเขตของ repo อาจเป็น MODULE.bazel (บ่งบอกว่า repo นี้แสดงโมดูล Bazel), REPO.bazel (ดูด้านล่าง) หรือในบริบทเดิม WORKSPACE หรือ WORKSPACE.bazel ไฟล์เครื่องหมายขอบเขตของ repo จะระบุขอบเขตของ repo โดยไฟล์ดังกล่าวจะอยู่ในไดเรกทอรีร่วมกันได้หลายไฟล์
ที่เก็บหลัก
ที่เก็บที่กำลังเรียกใช้คำสั่ง Bazel ปัจจุบัน
รูทของที่เก็บหลักเรียกอีกอย่างว่ารูทของพื้นที่ทำงาน
Workspace
สภาพแวดล้อมที่คำสั่ง Bazel ทั้งหมดใช้ร่วมกันจะทำงานในที่เก็บหลักเดียวกัน โดยจะครอบคลุมทั้งที่เก็บหลักและชุดที่เก็บภายนอกทั้งหมดที่กำหนดไว้
โปรดทราบว่าที่ผ่านมาแนวคิด "ที่เก็บข้อมูล" และ "พื้นที่ทำงาน" มักใช้รวมๆ กัน คำว่า "พื้นที่ทำงาน" มักใช้เพื่ออ้างอิงถึงที่เก็บข้อมูลหลัก และบางครั้งยังใช้เป็นคำพ้องความหมายของ "ที่เก็บข้อมูล" ด้วย
ชื่อที่เก็บ Canonical
ชื่อ 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 เป้าหมาย" หรือเพียงแค่ "สร้างลิงก์สัญลักษณ์ไปยังไดเรกทอรีในเครื่อง" ทุกที่เก็บจะกำหนดโดยการเรียกใช้กฎที่เก็บพร้อมอาร์กิวเมนต์จำนวนที่เหมาะสม
ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีเขียน กฎของที่เก็บได้ที่กฎของที่เก็บ
กฎของ 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.bazel จะคล้ายกับไฟล์ BUILD ยกเว้นว่าจะไม่รองรับคำสั่ง load และใช้ได้เฉพาะฟังก์ชันเดียวคือ repo() repo() มีอาร์กิวเมนต์เดียวกันกับpackage()
ฟังก์ชันในไฟล์ BUILD ในขณะที่ package()
ระบุแอตทริบิวต์ทั่วไปสำหรับเป้าหมายการสร้างทั้งหมดภายในแพ็กเกจ repo()
จะทำเช่นเดียวกันสำหรับเป้าหมายการสร้างทั้งหมดภายในที่เก็บ
เช่น คุณสามารถระบุใบอนุญาตทั่วไปสำหรับเป้าหมายทั้งหมดในที่เก็บได้โดย
มีไฟล์ REPO.bazel ดังนี้
repo(
default_package_metadata = ["//:my_license"],
)
จัดการทรัพยากร Dependency ภายนอกด้วย Bzlmod
Bzlmod ซึ่งเป็นระบบย่อยการอ้างอิงภายนอกใหม่จะใช้กับคำจำกัดความของที่เก็บโดยตรงไม่ได้ แต่จะสร้างกราฟการขึ้นต่อกันจากโมดูล เรียกใช้ส่วนขยายที่ด้านบนของกราฟ และกำหนด repo ตามนั้น
โมดูล 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")
โมดูลต้องแสดงเฉพาะทรัพยากร Dependency โดยตรง ซึ่ง Bzlmod จะค้นหาในรีจิสทรี Bazel โดยค่าเริ่มต้นคือ Bazel Central
Registry รีจิสทรีมีไฟล์MODULE.bazelของการอ้างอิง ซึ่งช่วยให้ Bazel ค้นพบกราฟการอ้างอิงแบบทรานซิทีฟทั้งหมดได้ก่อนที่จะทำการแก้ปัญหาเวอร์ชัน
หลังจากแก้ไขเวอร์ชันแล้ว ซึ่งจะมีการเลือกเวอร์ชันหนึ่งสำหรับแต่ละโมดูล
Bazel จะปรึกษารีจิสทรีอีกครั้งเพื่อดูวิธีระบุที่เก็บสำหรับแต่ละโมดูล
(ในกรณีส่วนใหญ่จะใช้ http_archive)
นอกจากนี้ โมดูลยังระบุข้อมูลที่กำหนดเองซึ่งเรียกว่าแท็กได้ด้วย ซึ่งส่วนขยายโมดูลจะใช้แท็กเหล่านี้หลังจากที่โมดูลได้รับการแก้ไขแล้ว เพื่อกำหนด repo เพิ่มเติม ส่วนขยายเหล่านี้มีความสามารถคล้ายกับกฎของ repo ซึ่งช่วยให้ดำเนินการต่างๆ เช่น I/O ของไฟล์และการส่งคำขอเครือข่ายได้ ซึ่งช่วยให้ Bazel โต้ตอบกับระบบการจัดการแพ็กเกจอื่นๆ ได้ในขณะที่ยังคงใช้กราฟการขึ้นต่อกันที่สร้างขึ้นจากโมดูล Bazel
ลิงก์ภายนอกใน Bzlmod
- ตัวอย่างการใช้งาน Bzlmod ใน bazelbuild/examples
- การยกเครื่องการอ้างอิงภายนอกของ Bazel (เอกสารการออกแบบ Bzlmod ต้นฉบับ)
- การพูดคุยเกี่ยวกับ Bzlmod ใน BazelCon 2021
- การพูดคุยในวันชุมชน Bazel เกี่ยวกับ Bzlmod
กำหนดที่เก็บด้วย WORKSPACE
ในอดีต คุณสามารถจัดการการขึ้นต่อกันภายนอกได้โดยการกำหนดที่เก็บข้อมูลในไฟล์
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 รุ่นต่อๆ ไป โปรดอ่านคำแนะนำในการย้ายข้อมูล Bzlmod เกี่ยวกับวิธีย้ายข้อมูลไปยัง Bzlmod