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