ส่วนขยายของโมดูล

วันที่ รายงานปัญหา ดูแหล่งที่มา ตอนกลางคืน · 7.3 · 7.2 · 7.1 · 7.0 · 6.5

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

คุณสามารถกำหนดส่วนขยายโมดูลในไฟล์ .bzl ได้เช่นเดียวกับกฎที่เก็บ คือ ไม่เรียกใช้โดยตรง แต่แต่ละโมดูลจะระบุข้อมูลที่เรียกว่าแท็ก สำหรับส่วนขยายในการอ่าน Bazel เรียกใช้ความละเอียดของโมดูลก่อนประเมิน ส่วนขยาย ส่วนขยายจะอ่านแท็กทั้งหมดที่เป็นของส่วนขยายนั้นทั้งหมด กราฟการขึ้นต่อกัน

การใช้ส่วนขยาย

ส่วนขยายจะโฮสต์อยู่ในโมดูล Bazel ด้วยตนเอง หากต้องการใช้ส่วนขยายใน ก่อนอื่นให้เพิ่ม bazel_dep ลงในโมดูลที่โฮสต์ส่วนขยาย จากนั้น เรียกใช้ฟังก์ชันในตัวของ use_extension เพื่อนำมาใช้ในขอบเขต ลองดูตัวอย่างต่อไปนี้ - ตัวอย่างข้อมูลจาก MODULE.bazel ไฟล์เพื่อใช้ "maven" ที่กำหนดไว้ใน rules_jvm_external โมดูล:

bazel_dep(name = "rules_jvm_external", version = "4.5")
maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")

วิธีนี้จะเชื่อมโยงค่าที่ use_extension แสดงผลกับตัวแปร ซึ่งทำให้ฟังก์ชัน ใช้จุด-ไวยากรณ์เพื่อระบุแท็กสำหรับส่วนขยาย แท็กต้องเป็นไปตาม สคีมาที่กำหนดโดยคลาสแท็กที่เกี่ยวข้องซึ่งระบุไว้ในแท็ก คำจำกัดความของส่วนขยาย เช่น การระบุ แท็ก maven.install และ maven.artifact:

maven.install(artifacts = ["org.junit:junit:4.13.2"])
maven.artifact(group = "com.google.guava",
               artifact = "guava",
               version = "27.0-jre",
               exclusions = ["com.google.j2objc:j2objc-annotations"])

ใช้คำสั่ง use_repo เพื่อเรียกที่เก็บ ที่สร้างขึ้นจากส่วนขยายลงในขอบเขตของโมดูลปัจจุบัน

use_repo(maven, "maven")

Repos ที่สร้างโดยส่วนขยายเป็นส่วนหนึ่งของ API ในตัวอย่างนี้ "ผู้เชี่ยวชาญ" ส่วนขยายโมดูลสัญญาว่าจะสร้างที่เก็บชื่อ maven ด้วยฟังก์ชัน ข้างต้น ส่วนขยายจะแก้ไขป้ายกำกับได้อย่างถูกต้อง เช่น @maven//:org_junit_junit เพื่อชี้ไปยังที่เก็บที่ "ผู้เชี่ยวชาญ" สร้างขึ้น ส่วนขยาย

คำจำกัดความของส่วนขยาย

คุณสามารถกำหนดส่วนขยายโมดูลได้ในลักษณะเดียวกับกฎที่เก็บ โดยใช้ module_extension อย่างไรก็ตาม ขณะที่กฎที่เก็บจะมีแอตทริบิวต์จำนวนหนึ่ง ส่วนขยายโมดูลจะมี tag_class โดยที่แต่ละรายการมีจำนวน คลาสแท็กจะกำหนดสคีมาสำหรับแท็กที่ส่วนขยายนี้ใช้ สำหรับ เช่น "ผู้เชี่ยวชาญ" ส่วนขยายข้างต้นอาจกำหนดไว้ดังต่อไปนี้

# @rules_jvm_external//:extensions.bzl

_install = tag_class(attrs = {"artifacts": attr.string_list(), ...})
_artifact = tag_class(attrs = {"group": attr.string(), "artifact": attr.string(), ...})
maven = module_extension(
  implementation = _maven_impl,
  tag_classes = {"install": _install, "artifact": _artifact},
)

ประกาศเหล่านี้แสดงให้เห็นว่าแท็ก maven.install และ maven.artifact ต่อไปนี้ได้ ที่ระบุโดยใช้สคีมาแอตทริบิวต์ที่ระบุ

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

# @rules_jvm_external//:extensions.bzl

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_file")  # a repo rule
def _maven_impl(ctx):
  # This is a fake implementation for demonstration purposes only

  # collect artifacts from across the dependency graph
  artifacts = []
  for mod in ctx.modules:
    for install in mod.tags.install:
      artifacts += install.artifacts
    artifacts += [_to_artifact(artifact) for artifact in mod.tags.artifact]

  # call out to the coursier CLI tool to resolve dependencies
  output = ctx.execute(["coursier", "resolve", artifacts])
  repo_attrs = _process_coursier_output(output)

  # call repo rules to generate repos
  for attrs in repo_attrs:
    http_file(**attrs)
  _generate_hub_repo(name = "maven", repo_attrs)

ข้อมูลระบุตัวตนของส่วนขยาย

ระบบจะระบุส่วนขยายโมดูลโดยใช้ชื่อและไฟล์ .bzl ที่ปรากฏ ในการโทรถึง use_extension ในตัวอย่างต่อไปนี้ ส่วนขยาย maven ถูกระบุโดยไฟล์ .bzl @rules_jvm_external//:extension.bzl และ ชื่อ maven:

maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")

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

ในฐานะผู้เขียนส่วนขยาย คุณควรตรวจสอบว่าผู้ใช้จะใช้ จากหนึ่งไฟล์ .bzl เพียงไฟล์เดียว

ชื่อและระดับการเข้าถึงที่เก็บ

Repos ที่สร้างโดยส่วนขยายมีชื่อ Canonical ในรูปแบบ module_repo_canonical_name~extension_name~repo_name สำหรับส่วนขยายที่โฮสต์ใน โมดูลราก module_repo_canonical_name ส่วนคือ แทนที่ด้วยสตริง _main โปรดทราบว่ารูปแบบของชื่อ Canonical ไม่ใช่ API ที่คุณควรใช้ แต่อาจมีการเปลี่ยนแปลงได้ตลอดเวลา

นโยบายการตั้งชื่อนี้หมายความว่าส่วนขยายแต่ละรายการจะมี "เนมสเปซที่เก็บ" ของตนเอง สอง ส่วนขยายที่แตกต่างกัน แต่ละส่วนขยายจะสามารถกำหนดที่เก็บที่มีชื่อเดียวกันได้โดยไม่ต้องเสี่ยง การชน และยังหมายความว่า repository_ctx.name รายงานชื่อ Canonical ด้วย ของที่เก็บ ซึ่งไม่เหมือนกับชื่อที่ระบุในกฎที่เก็บ การโทร

โดยพิจารณาจาก Repos ที่สร้างโดยส่วนขยายโมดูล มี กฎการเปิดเผยที่เก็บหลายกฎ ได้แก่

  • ที่เก็บโมดูล Bazel จะเห็นที่เก็บทั้งหมดที่แนะนำในไฟล์ MODULE.bazel ผ่าน bazel_dep และ use_repo
  • ที่เก็บที่สร้างโดยส่วนขยายโมดูลสามารถดูที่เก็บทั้งหมดที่แสดงต่อ ที่โฮสต์ส่วนขยาย และที่เก็บอื่นๆ ทั้งหมดที่สร้างขึ้นโดย ส่วนขยายโมดูลเดียวกัน (ใช้ชื่อที่ระบุในการเรียกใช้กฎที่เก็บเป็น )
    • ซึ่งอาจทำให้เกิดข้อขัดแย้ง หากที่เก็บโมดูลเห็นที่เก็บที่มี ชื่อที่ปรากฏ foo และส่วนขยายจะสร้างที่เก็บที่มี ชื่อที่ระบุ foo แล้วสำหรับที่เก็บทั้งหมดที่สร้างโดยส่วนขยายนั้น foo หมายถึงอันแรก

แนวทางปฏิบัติแนะนำ

ส่วนนี้จะอธิบายแนวทางปฏิบัติแนะนำในการเขียนส่วนขยายเพื่อให้ ใช้งานง่าย บำรุงรักษาได้ และปรับเปลี่ยนได้ดีตามการเปลี่ยนแปลงเมื่อเวลาผ่านไป

ใส่ส่วนขยายแต่ละรายการในไฟล์แยกต่างหาก

เมื่อส่วนขยายอยู่ในไฟล์ที่ต่างกัน ส่วนขยายหนึ่งจะทำให้ส่วนขยายหนึ่งโหลดได้ ที่เก็บที่สร้างโดยส่วนขยายอื่น แม้ว่าคุณจะไม่ได้ใช้สิ่งนี้ ให้แยกเป็นคนละไฟล์กันเผื่อกรณีที่ต้องการ ขอแนะนำให้ใส่ ฟังก์ชันต่างๆ ไว้ ในภายหลัง เพราะการระบุส่วนขยายนั้นอิงกับไฟล์ ดังนั้นการย้าย ส่วนขยายลงในไฟล์อื่นในภายหลังจะเปลี่ยน API สาธารณะของคุณและเป็นการย้อนกลับ การเปลี่ยนแปลงที่เข้ากันไม่ได้กับผู้ใช้

ระบุระบบปฏิบัติการและสถาปัตยกรรม

หากส่วนขยายต้องใช้ระบบปฏิบัติการหรือประเภทสถาปัตยกรรม อย่าลืมระบุข้อมูลนี้ในคำจำกัดความส่วนขยายโดยใช้ os_dependent และแอตทริบิวต์บูลีน arch_dependent รายการ ซึ่งทำให้ Bazel ทราบว่า ต้องได้รับการประเมินซ้ำหากมีการเปลี่ยนแปลงอย่างใดอย่างหนึ่ง

เฉพาะโมดูลรูทเท่านั้นที่จะมีผลต่อชื่อที่เก็บโดยตรง

โปรดทราบว่าเมื่อส่วนขยายสร้างที่เก็บ จะมีการสร้างที่เก็บขึ้นภายใน Namespace ของส่วนขยาย ซึ่งหมายความว่าการชนอาจเกิดขึ้นหากไม่เหมือนกัน โมดูลใช้ส่วนขยายเดียวกันและจบลงด้วยการสร้างที่เก็บที่มี ชื่อ ซึ่งมักจะแสดงเป็น tag_class ของส่วนขยายโมดูลที่มี name ที่ส่งผ่านเป็นค่า name ของกฎที่เก็บ

ตัวอย่างเช่น สมมติว่าโมดูลราก A ขึ้นอยู่กับโมดูล B ทั้ง 2 โมดูล ขึ้นอยู่กับโมดูล mylang หากโทรทั้ง A และ B mylang.toolchain(name="foo") ทั้งคู่จะพยายามสร้างที่เก็บชื่อ foo ภายในโมดูล mylang และมีข้อผิดพลาดเกิดขึ้น

คุณหลีกเลี่ยงปัญหานี้ได้ด้วยการนำความสามารถในการตั้งชื่อที่เก็บโดยตรงออก หรืออนุญาตเฉพาะโมดูลรูทเท่านั้น คุณสามารถอนุญาตโมดูลรูท ความสามารถเพราะ ไม่มีอะไร ขึ้นอยู่กับความสามารถนั้น คุณจึงไม่ต้องกังวลเกี่ยวกับ โมดูลอื่นที่สร้างชื่อที่ขัดแย้งกัน