Bazel รองรับทรัพยากร Dependency ภายนอก ไฟล์แหล่งที่มา (ทั้งข้อความและไบนารี) ที่ใช้ในบิลด์ที่ไม่ได้มาจากพื้นที่ทำงานของคุณ เช่น อาจเป็นชุดกฎที่โฮสต์อยู่ในที่เก็บ GitHub, อาร์ติแฟกต์ Maven หรือไดเรกทอรีบนเครื่องภายในนอกพื้นที่ทำงานปัจจุบัน
สำหรับ Bazel 6.0 คุณสามารถจัดการทรัพยากร Dependency ภายนอกด้วย Bazel ได้ 2 วิธี ได้แก่ ระบบWORKSPACE
แบบดั้งเดิมที่เน้นที่เก็บและMODULE.bazel
ระบบแบบใหม่ที่เน้นโมดูล (ใช้โค้ดชื่อ Bzlmod และเปิดใช้ด้วยแฟล็ก --enable_bzlmod
) คุณสามารถใช้ทั้ง 2 ระบบร่วมกันได้ แต่ Bzlmod จะมาแทนที่ระบบ WORKSPACE
ในการย้ายข้อมูลจาก Bazl{/0 ในอนาคต โดย Bzlmod}จะเข้ามาแทนที่ระบบ WORKSPACE
ในการย้ายข้อมูล Bazl{/0 ในอนาคต
เอกสารนี้จะอธิบายแนวคิดเกี่ยวกับการจัดการทรัพยากร Dependency ภายนอกใน Bazel ก่อนจะลงลึกรายละเอียดเพิ่มเติมเกี่ยวกับทั้ง 2 ระบบ
แนวคิด
ที่เก็บ
แผนผังไดเรกทอรีที่มีไฟล์ตัวทำเครื่องหมายขอบเขตที่ราก ซึ่งมีไฟล์ต้นทางที่สามารถใช้ในบิลด์ Bazel มักถูกย่อให้เหลือเพียงที่เก็บ
ไฟล์ตัวทำเครื่องหมายขอบเขตที่เก็บอาจเป็น MODULE.bazel
(บ่งบอกว่าที่เก็บนี้แสดงโมดูล Bazel), REPO.bazel
(ดูด้านล่าง) หรือในบริบทเดิม WORKSPACE
หรือ WORKSPACE.bazel
ไฟล์ตัวทำเครื่องหมายขอบเขตที่เก็บจะแสดงขอบเขตของที่เก็บ โดยไฟล์หลายๆ ไฟล์สามารถอยู่ร่วมกันในไดเรกทอรีได้
ที่เก็บหลัก
ที่เก็บที่คำสั่ง Bazel ปัจจุบันกำลังทำงาน
รูทของที่เก็บหลักเรียกอีกอย่างว่ารูทของพื้นที่ทำงาน
Workspace
สภาพแวดล้อมที่แชร์โดยคำสั่ง Bazel ทั้งหมดจะทำงานในที่เก็บหลักเดียวกัน ซึ่งรวมที่เก็บหลักและชุดที่เก็บภายนอกที่กำหนดไว้ทั้งหมด
โปรดทราบว่าในอดีต แนวคิดของ "ที่เก็บ" และ "พื้นที่ทำงาน" นั้นมีความขัดแย้งกัน คำว่า "พื้นที่ทำงาน" มักจะหมายถึงที่เก็บหลัก และบางครั้งอาจใช้เป็นคำพ้องความหมายของ "ที่เก็บ"
ชื่อที่เก็บ Canonical
Canonical Name (CNAME) ที่ที่เก็บจะแก้ไขได้ ในบริบทของพื้นที่ทำงาน ที่เก็บแต่ละรายการจะมีชื่อ Canonical เพียงชื่อเดียว เป้าหมายภายในที่เก็บซึ่งมีชื่อ Canonical canonical_name
สามารถระบุได้ด้วยป้ายกำกับ
@@canonical_name//pac/kage:target
(โปรดสังเกตว่า@
)
ที่เก็บหลักจะมีสตริงว่างเป็นชื่อ Canonical เสมอ
ชื่อที่เก็บที่ปรากฏ
ชื่อของที่เก็บจะแก้ไขได้โดยบริบทของที่เก็บอื่น
ซึ่งอาจถือได้ว่าเป็น "ชื่อเล่น" ของที่เก็บ โดยที่เก็บที่มีชื่อ Canonical michael
อาจมีชื่อที่ชัดแจ้ง mike
ในบริบทของที่เก็บ alice
แต่อาจมีชื่อที่ชัดเจนว่า mickey
ในบริบทของที่เก็บ
bob
ในกรณีนี้ ป้ายกำกับ @mike//pac/kage:target
จะระบุเป้าหมายภายใน michael
ได้ในบริบทของ alice
(โปรดสังเกต @
รายการเดียว)
ในทางตรงกันข้าม คุณเข้าใจลักษณะนี้เป็นการแมปที่เก็บได้ กล่าวคือที่เก็บแต่ละรายการจะยังคงมีการแมปจาก "ชื่อที่เก็บที่ชัดเจน" ไปจนถึง "ชื่อที่เก็บ Canonical"
กฎของที่เก็บ
สคีมาของคำจำกัดความของที่เก็บซึ่งบอก Bazel เกี่ยวกับวิธีทำให้ที่เก็บเป็นรูปธรรม เช่น อาจเป็น "ดาวน์โหลดไฟล์ ZIP จาก URL ที่เจาะจงและแตกข้อมูล" หรือ "ดึงข้อมูลอาร์ติแฟกต์ Maven ที่กำหนดและทำให้พร้อมใช้งานเป็นเป้าหมาย java_import
" หรือแค่ "ลิงก์ไดเรกทอรีในเครื่อง" ที่เก็บทั้งหมดจะกำหนดโดยการเรียกใช้กฎที่เก็บที่มีอาร์กิวเมนต์จำนวนที่เหมาะสม
ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีเขียนกฎที่เก็บของคุณเองได้ที่กฎที่เก็บ
กฎที่เก็บที่พบบ่อยที่สุดในขณะนี้คือ http_archive
ซึ่งดาวน์โหลดที่เก็บถาวรจาก URL และแยกออกมา และ local_repository
ซึ่งลิงก์กับไดเรกทอรีภายในที่เป็นที่เก็บของ Bazel อยู่แล้ว
ดึงข้อมูลที่เก็บ
การดำเนินการสร้างที่เก็บที่ใช้ได้บนดิสก์ในเครื่องโดยเรียกใช้กฎที่เก็บที่เกี่ยวข้อง ที่เก็บซึ่งกำหนดในพื้นที่ทำงานจะไม่พร้อมใช้งานบนดิสก์ในเครื่องก่อนที่จะมีการดึงข้อมูล
โดยปกติแล้ว Bazel จะดึงเฉพาะที่เก็บที่ต้องการจากที่เก็บนั้น และยังไม่มีการดึงข้อมูลที่เก็บดังกล่าว หากมีการดึงข้อมูลที่เก็บมาก่อนแล้ว Bazel จะดึงข้อมูลอีกครั้งก็ต่อเมื่อมีการเปลี่ยนแปลงคำจำกัดความเท่านั้น
คำสั่ง fetch
สามารถใช้เพื่อเริ่มการดึงข้อมูลล่วงหน้าสำหรับที่เก็บ กำหนดเป้าหมาย หรือที่เก็บที่จำเป็นทั้งหมดเพื่อดำเนินการบิลด์ ความสามารถนี้จะเปิดใช้บิลด์ออฟไลน์โดยใช้ตัวเลือก --nofetch
ตัวเลือก --fetch
ทำหน้าที่จัดการการเข้าถึงเครือข่าย ค่าเริ่มต้นคือ "จริง"
แต่เมื่อตั้งค่าเป็น "เท็จ" (--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"],
)
จัดการทรัพยากร Dependency ภายนอกด้วย Bzlmod
Bzlmod ซึ่งเป็นระบบย่อยของทรัพยากร Dependency ภายนอกใหม่จะใช้งานกับคำจำกัดความของที่เก็บไม่ได้โดยตรง แต่จะสร้างกราฟการอ้างอิงจากโมดูล เรียกใช้ส่วนขยายที่ด้านบนของกราฟ และกำหนด Repos ตามความเหมาะสม
โมดูล Bazel คือโปรเจ็กต์ Bazel ที่มีได้หลายเวอร์ชัน โดยแต่ละเวอร์ชันจะเผยแพร่ข้อมูลเมตาเกี่ยวกับโมดูลอื่นๆ ที่ขึ้นอยู่กับโมดูล โมดูลต้องมีไฟล์ MODULE.bazel
ที่รูทของที่เก็บข้างไฟล์ WORKSPACE
ไฟล์นี้คือไฟล์ Manifest ของโมดูล โดยประกาศชื่อ เวอร์ชัน รายการทรัพยากร Dependency รวมถึงข้อมูลอื่นๆ ต่อไปนี้เป็นตัวอย่างพื้นฐาน
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 ค้นพบกราฟทรัพยากร Dependency แบบชั่วคราวทั้งหมดก่อนทำการแปลงเวอร์ชัน
หลังจากแก้ไขเวอร์ชันแล้ว ซึ่งมีการเลือกเวอร์ชันเดียวสำหรับแต่ละโมดูล
Bazel จะปรึกษาองค์กรจัดการข้อมูลโดเมนอีกครั้งเพื่อดูวิธีกำหนดที่เก็บสำหรับแต่ละโมดูล
(ในกรณีส่วนใหญ่ ให้ใช้ http_archive
)
โมดูลยังระบุส่วนของข้อมูลที่ปรับแต่งแล้วที่เรียกว่าแท็ก ซึ่งใช้ส่วนขยายโมดูลหลังจากการแปลงโมดูลเพื่อกำหนดที่เก็บเพิ่มเติมได้ด้วย ส่วนขยายเหล่านี้มีความสามารถที่คล้ายกับกฎที่เก็บ ซึ่งช่วยให้ดำเนินการต่างๆ เช่น I/O ไฟล์และส่งคำขอเครือข่ายได้ เครื่องมือเหล่านี้ช่วยให้ Bazel โต้ตอบกับระบบการจัดการแพ็กเกจอื่นๆ ได้ และในขณะเดียวกันก็ยังปฏิบัติตามกราฟการอ้างอิงที่สร้างขึ้นจากโมดูล Bazel ด้วย
ลิงก์ภายนอกใน Bzlmod
- ตัวอย่างการใช้ Bzlmod ใน bazelbuild/ตัวอย่าง
- ยกเครื่องการขึ้นต่อกันภายนอกของ Bazel (เอกสารการออกแบบ Bzlmod ต้นฉบับ)
- BazelCon 2021 พูดถึง Bzlmod
- ทอล์กโชว์ในวันชุมชน Bazel ทาง Bzlmod
กำหนดที่เก็บด้วย WORKSPACE
ก่อนหน้านี้ คุณสามารถจัดการทรัพยากร Dependency ภายนอกได้โดยกำหนด Repos ในไฟล์ 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
ของทรัพยากร Dependency ใดก็ตาม จึงต้องกําหนดทรัพยากร Dependency แบบสับเปลี่ยนทั้งหมดในไฟล์WORKSPACE
ของที่เก็บหลัก นอกเหนือจากทรัพยากร Dependency โดยตรง - ในการแก้ปัญหานี้ โปรเจ็กต์ได้ใช้รูปแบบ "deps.bzl" ซึ่งเป็นการกำหนดมาโครซึ่งจะต้องกำหนดที่เก็บหลายรายการ และขอให้ผู้ใช้เรียกมาโครนี้ในไฟล์
WORKSPACE
ของตน- ปัญหานี้เกิดขึ้นเอง คือมาโครไม่สามารถ
load
ไฟล์.bzl
อื่นๆ ได้ ดังนั้นโปรเจ็กต์เหล่านี้จึงต้องกำหนดทรัพยากร Dependency แบบชั่วคราวในมาโคร "deps" นี้ หรือแก้ปัญหาโดยให้ผู้ใช้เรียกมาโคร "deps" หลายเลเยอร์ได้ - Bazel ประเมินไฟล์
WORKSPACE
ตามลำดับ นอกจากนี้ จะมีการระบุทรัพยากร Dependency โดยใช้http_archive
กับ URL แบบไม่มีข้อมูลเวอร์ชัน ซึ่งหมายความว่าไม่มีวิธีที่เชื่อถือได้ในการแก้ไขเวอร์ชันในกรณีของทรัพยากร Dependency แบบไดมอนด์ (A
ขึ้นอยู่กับB
และC
เนื่องจากB
และC
ต่างก็ขึ้นอยู่กับD
เวอร์ชันที่แตกต่างกัน)
- ปัญหานี้เกิดขึ้นเอง คือมาโครไม่สามารถ
เนื่องจากข้อบกพร่องของ WORKSPACE ทำให้ Bzlmod จะมาแทนที่ระบบ WorkSPACE เดิมในรุ่น Bazel รุ่นต่อๆ ไป โปรดอ่านคำแนะนำในการย้ายข้อมูล Bzlmod เกี่ยวกับวิธีย้ายข้อมูลไปยัง Bzlmod