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

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

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

การจัดการทรัพยากร Dependency ภายนอกด้วย Bazel จาก Bazel 6.0 มีอยู่ 2 วิธีด้วยกัน ได้แก่ ระบบ WORKSPACE แบบดั้งเดิมที่มุ่งเน้นที่เก็บ และระบบ MODULE.bazel แบบใหม่ที่เน้นโมดูล (รหัสชื่อว่า Bzlmod และเปิดใช้ด้วยแฟล็ก --enable_bzlmod) คุณสามารถใช้ทั้ง 2 ระบบร่วมกันได้ แต่ Bzlmod} จะมาแทนที่ระบบ WORKSPACE ใน Bazel ในอนาคต {/1

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

แนวคิด

ที่เก็บ

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

ไฟล์ตัวทำเครื่องหมายขอบเขตของที่เก็บอาจ MODULE.bazel (เป็นสัญญาณว่าที่เก็บนี้แทนโมดูล Bazel), REPO.bazel (ดูด้านล่าง) หรือในบริบทเดิม WORKSPACE หรือ WORKSPACE.bazel ไฟล์ตัวทำเครื่องหมายขอบเขตที่เก็บใดก็ตามจะแสดงขอบเขตของที่เก็บ โดยไฟล์เหล่านี้หลายๆ ไฟล์สามารถอยู่ร่วมกันได้ในไดเรกทอรี

ที่เก็บหลัก

ที่เก็บที่มีการเรียกใช้คำสั่ง Bazel ปัจจุบัน

รูทของที่เก็บหลักเรียกอีกอย่างว่ารูทของพื้นที่ทำงาน

Workspace

สภาพแวดล้อมที่แชร์โดยคำสั่ง Bazel ทั้งหมดจะทำงานในที่เก็บหลักเดียวกัน ซึ่งประกอบด้วยที่เก็บหลักและชุดของที่เก็บภายนอกที่กำหนดไว้ทั้งหมด

โปรดทราบว่าที่ผ่านมาแนวคิดของ "ที่เก็บ" และ "พื้นที่ทำงาน" จะรวมอยู่ด้วยกัน คำว่า "พื้นที่ทำงาน" มักใช้เพื่ออ้างถึงที่เก็บหลัก และบางครั้งยังใช้เป็นคำพ้องความหมายของ "ที่เก็บ" ด้วย

ชื่อที่เก็บ Canonical

ชื่อ Canonical ที่ที่เก็บระบุที่อยู่ได้ ภายในบริบทของพื้นที่ทำงาน ที่เก็บแต่ละรายการจะมีชื่อ Canonical ชื่อเดียว เป้าหมายภายในที่เก็บที่ชื่อ Canonical คือ canonical_name จะระบุด้วยป้ายกำกับ @@canonical_name//package:target ได้ (โปรดสังเกต @ คู่)

ที่เก็บหลักจะมีสตริงว่างเป็นชื่อ Canonical เสมอ

ชื่อที่เก็บที่ชัดเจน

ชื่อที่เก็บระบุที่อยู่ได้ในบริบทของที่เก็บอื่น อาจคิดว่าเป็น "ชื่อเล่น" ของที่เก็บ ที่เก็บที่มีชื่อ Canonical michael อาจมีชื่อที่เห็นได้ชัดเป็น mike ในบริบทของที่เก็บ alice แต่อาจมีชื่อที่ชัดเจนว่า mickey ในบริบทของที่เก็บ bob ในกรณีนี้ เป้าหมายภายใน michael จะแก้ไขได้ด้วยป้ายกำกับ @mike//package:target ในบริบทของ 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 ภายนอกแบบใหม่ไม่ทำงานกับคำจำกัดความของที่เก็บโดยตรง แต่จะสร้างกราฟทรัพยากร 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 โต้ตอบกับระบบจัดการแพ็กเกจอื่นๆ ขณะเดียวกันก็เคารพกราฟทรัพยากร Dependency ที่สร้างจากโมดูล Bazel ด้วย

กำหนดที่เก็บด้วย WORKSPACE

ก่อนหน้านี้ คุณจัดการทรัพยากร Dependency ภายนอกได้โดยกำหนดที่เก็บในไฟล์ 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 ของที่เก็บหลัก นอกเหนือจากการขึ้นต่อกันโดยตรง
  • ในการแก้ปัญหานี้ โปรเจ็กต์ได้ใช้รูปแบบ "deps.bzl" ซึ่งจะกำหนดมาโครซึ่งจะระบุที่เก็บหลายรายการและขอให้ผู้ใช้เรียกมาโครนี้ในไฟล์ WORKSPACE
    • ซึ่งก็มีปัญหาของตัวเอง กล่าวคือ มาโครไม่สามารถloadไฟล์ .bzl อื่นๆ ได้ โปรเจ็กต์เหล่านี้จึงต้องกำหนดทรัพยากร Dependency แบบทรานซิทีฟในมาโคร "deps" นี้ หรือเลี่ยงปัญหานี้โดยให้ผู้ใช้เรียกใช้มาโคร "deps" หลายชั้น
    • Bazel ประเมินไฟล์ WORKSPACE ตามลำดับ นอกจากนี้ การระบุการขึ้นต่อกันโดยใช้ http_archive ด้วย URL โดยไม่มีข้อมูลเวอร์ชันใดๆ ซึ่งหมายความว่าจะไม่มีวิธีที่เชื่อถือได้ในการแปลงเวอร์ชันในกรณีที่เป็น Diamond Dependency (A ขึ้นอยู่กับ B และ C ขณะที่ทั้ง B และ C ต่างก็ขึ้นอยู่กับ D เวอร์ชันที่แตกต่างกัน)

เนื่องจาก WORKSPACE ขาดแคลน Bzlmod จะมาแทนที่ระบบ WORKSPACE เดิมใน Bazel รุ่นต่อๆ ไป โปรดอ่านคำแนะนำในการย้ายข้อมูล Bzlmod เกี่ยวกับวิธีย้ายข้อมูลไปยัง Bzlmod