ภาพรวมของทรัพยากร Dependency ภายนอก

รายงานปัญหา ดูซอร์ส รุ่น Nightly · 8.2 · 8.1 · 8.0 · 7.6 · 7.5

Bazel รองรับทรัพยากรภายนอก ซึ่งเป็นไฟล์ต้นฉบับ (ทั้งข้อความและไบนารี) ที่ใช้ในการสร้างที่ไม่ได้มาจากเวิร์กスペース เช่น อาจเป็นชุดกฎที่โฮสต์อยู่ในที่เก็บ GitHub, ออบเจ็กต์ Maven หรือไดเรกทอรีในเครื่องคอมพิวเตอร์ของคุณซึ่งอยู่นอกเวิร์กスペースปัจจุบัน

เอกสารนี้จะอธิบายภาพรวมของระบบก่อนที่จะเจาะลึกแนวคิดบางอย่างอย่างละเอียด

ภาพรวมของระบบ

ระบบการพึ่งพาภายนอกของ Bazel ทำงานตามโมดูล Bazel ซึ่งแต่ละโมดูลเป็นโปรเจ็กต์ Bazel ที่มีเวอร์ชัน และที่เก็บ (หรือที่เก็บ) ซึ่งเป็นต้นไม้ไดเรกทอรีที่มีไฟล์ต้นฉบับ

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 Central รีจิสทรี รีจิสทรีจะมีไฟล์ MODULE.bazel ของข้อกําหนด ซึ่งช่วยให้ Bazel ค้นพบกราฟข้อกําหนดแบบทรานซิทีฟทั้งหมดก่อนที่จะทำการแก้ไขเวอร์ชัน

หลังจากการแก้ไขเวอร์ชันซึ่งจะเลือกเวอร์ชันเดียวสำหรับแต่ละโมดูลแล้ว Bazel จะปรึกษารีจิสทรีอีกครั้งเพื่อดูวิธีกำหนดที่เก็บสำหรับแต่ละโมดูล นั่นคือวิธีดึงข้อมูลแหล่งที่มาสำหรับโมดูล Dependency แต่ละรายการ ส่วนใหญ่แล้วไฟล์เหล่านี้เป็นเพียงไฟล์ที่เก็บถาวรที่ดาวน์โหลดจากอินเทอร์เน็ตและแตกไฟล์

โมดูลยังระบุข้อมูลที่กำหนดเองที่เรียกว่าแท็กได้ด้วย ซึ่งส่วนขยายโมดูลจะใช้หลังจากการแก้ไขโมดูลเพื่อกำหนดที่เก็บข้อมูลเพิ่มเติม ส่วนขยายเหล่านี้สามารถดําเนินการต่างๆ เช่น I/O ของไฟล์และการส่งคําขอเครือข่าย นอกเหนือจากนี้ เครื่องมือเหล่านี้ยังช่วยให้ Bazel โต้ตอบกับระบบการจัดการแพ็กเกจอื่นๆ ได้ ขณะเดียวกันก็เคารพกราฟการพึ่งพาซึ่งสร้างขึ้นจากโมดูล Bazel ด้วย

รีโพสิทรี 3 ประเภท ได้แก่ รีโพสิทรีหลัก (ซึ่งเป็นสคีมาซอร์สโค้ดที่คุณทํางานอยู่) รีโพสิทรีที่แสดงถึงโมดูลการพึ่งพาแบบเปลี่ยนผ่าน และรีโพสิทรีที่สร้างโดยส่วนขยายโมดูล จะรวมกันเป็นเวิร์กสเปซ ระบบจะดึงข้อมูลรีโพสภายนอก (รีโพสที่ไม่ใช่รีโพสหลัก) ตามคําขอ เช่น เมื่อมีการอ้างอิงถึงด้วยป้ายกํากับ (เช่น @repo//pkg:target) ในไฟล์ BUILD

ข้อดี

ระบบทรัพยากรภายนอกของ Bazel มีประโยชน์มากมาย

การแก้ไขข้อกำหนดโดยอัตโนมัติ

  • การแก้ไขเวอร์ชันแบบกำหนดได้: Bazel ใช้อัลกอริทึมการแก้ไขเวอร์ชันแบบกำหนดได้ของ MVS ซึ่งจะลดความขัดแย้งและแก้ไขปัญหาการพึ่งพาแบบเพชร
  • การจัดการทรัพยากร Dependency ที่ง่ายขึ้น: MODULE.bazel จะประกาศเฉพาะ Dependency โดยตรง ส่วน Dependency แบบสื่อกลางจะได้รับการแก้ไขโดยอัตโนมัติ ซึ่งจะให้ภาพรวมที่ชัดเจนขึ้นเกี่ยวกับ Dependency ของโปรเจ็กต์
  • ระดับการเข้าถึงทรัพยากร Dependency ที่เข้มงวด: ระบบจะแสดงเฉพาะ Dependency โดยตรงเท่านั้น เพื่อให้แน่ใจว่าถูกต้องและคาดการณ์ได้

การผสานรวมระบบนิเวศ

  • รีจิสทรีส่วนกลางของ Bazel: ที่เก็บข้อมูลส่วนกลางสําหรับการค้นพบและจัดการทรัพยากรร่วมทั่วไปเป็นโมดูล Bazel
  • การนำโปรเจ็กต์ที่ไม่ใช่ Bazel มาใช้: เมื่อโปรเจ็กต์ที่ไม่ใช่ Bazel (โดยปกติจะเป็นไลบรารี C++) ได้รับการปรับให้ใช้กับ Bazel และพร้อมใช้งานใน BCR จะช่วยให้การผสานรวมมีประสิทธิภาพมากขึ้นสำหรับทั้งชุมชน และช่วยลดความซ้ำซ้อนและความขัดแย้งของไฟล์ BUILD ที่กําหนดเอง
  • การผสานรวมแบบรวมกับเครื่องมือจัดการแพ็กเกจเฉพาะภาษา: ชุดกฎจะลดความซับซ้อนในการผสานรวมกับเครื่องมือจัดการแพ็กเกจภายนอกสำหรับข้อกำหนดที่ไม่เกี่ยวข้องกับ Bazel ซึ่งรวมถึงข้อกำหนดต่อไปนี้

ฟีเจอร์ขั้นสูง

  • ส่วนขยายโมดูล: ฟีเจอร์ use_repo_rule และส่วนขยายโมดูลช่วยให้ใช้กฎของที่เก็บข้อมูลที่กำหนดเองและตรรกะการแก้ไขได้อย่างยืดหยุ่นเพื่อนำข้อกำหนดที่ไม่อยู่ใน Bazel มาใช้
  • คำสั่ง bazel mod: คำสั่งย่อยนี้ช่วยตรวจสอบทรัพยากร Dependency ภายนอกได้ คุณทราบดีว่ามีการกําหนดการพึ่งพาภายนอกอย่างไรและมาจากที่ใด
  • โหมดผู้ให้บริการ: ดึงข้อมูลการอ้างอิงภายนอกที่แน่นอนซึ่งคุณต้องใช้เพื่ออำนวยความสะดวกในการสร้างแบบออฟไลน์ล่วงหน้า
  • Lockfile: ไฟล์ล็อกช่วยปรับปรุงความสามารถในการสร้างซ้ำและเร่งการแก้ไขข้อกำหนด
  • (เร็วๆ นี้) การรับรองแหล่งที่มาของ BCR: เพิ่มความแข็งแกร่งให้กับความปลอดภัยของซัพพลายเชนด้วยการรับรองแหล่งที่มาที่ยืนยันแล้วของข้อกำหนด

แนวคิด

ส่วนนี้จะให้รายละเอียดเพิ่มเติมเกี่ยวกับแนวคิดที่เกี่ยวข้องกับการพึ่งพาภายนอก

โมดูล

โปรเจ็กต์ Bazel ที่มีได้หลายเวอร์ชัน โดยแต่ละเวอร์ชันอาจมีการพึ่งพาโมดูลอื่นๆ

ในเวิร์กスペース Bazel ในพื้นที่ โมดูลจะแสดงโดยที่เก็บ

โปรดดูรายละเอียดเพิ่มเติมที่โมดูล Bazel

ที่เก็บ

ต้นไม้ไดเรกทอรีที่มีไฟล์เครื่องหมายขอบเขตที่รูท ซึ่งมีไฟล์ต้นฉบับที่ใช้ได้ในบิลด์ 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() ใช้อาร์กิวเมนต์เดียวกับฟังก์ชัน package() ในไฟล์ BUILD ส่วน package() ระบุแอตทริบิวต์ทั่วไปสำหรับเป้าหมายการสร้างทั้งหมดภายในแพ็กเกจ repo() จะทำในทำนองเดียวกันสำหรับเป้าหมายการสร้างทั้งหมดภายในที่เก็บ

เช่น คุณสามารถระบุใบอนุญาตทั่วไปสำหรับเป้าหมายทั้งหมดในรีโปโดยต้องมีไฟล์ REPO.bazel ต่อไปนี้

repo(
    default_package_metadata = ["//:my_license"],
)

ระบบ WORKSPACE เดิม

ใน Bazel เวอร์ชันเก่า (ก่อน 9.0) จะมีการนําทรัพยากร Dependency ภายนอกมาใช้โดยการกำหนดที่เก็บในไฟล์ 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",
)

ข้อมูลโค้ดจะกำหนดที่เก็บซึ่งมีชื่อตามหลักเกณฑ์เป็น 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 6 ถึง 9 อ่านคำแนะนำในการย้ายข้อมูล Bzlmod เกี่ยวกับวิธีย้ายข้อมูลไปยัง Bzlmod