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

รายงานปัญหา ดูแหล่งที่มา

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 ด้วย

กำหนดที่เก็บด้วย 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