คำถามที่พบบ่อย

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

หน้านี้จะตอบคําถามที่พบบ่อยบางข้อเกี่ยวกับทรัพยากรภายนอกใน Bazel

MODULE.bazel

เหตุใด MODULE.bazel จึงไม่รองรับ load

ในระหว่างการแก้ไขข้อกำหนด จะมีการดึงข้อมูลไฟล์ MODULE.bazel ของข้อกำหนดภายนอกทั้งหมดที่อ้างอิงจากรีจิสทรี ในขั้นตอนนี้ ระบบยังไม่ได้ดึงข้อมูลไฟล์เก็บถาวรต้นทางของข้อกําหนดเบื้องต้น ดังนั้นหากไฟล์ MODULE.bazel loadเป็นไฟล์อื่น Bazel จะดึงข้อมูลไฟล์นั้นไม่ได้หากไม่ดึงข้อมูลไฟล์เก็บถาวรต้นทางทั้งหมด โปรดทราบว่าไฟล์ MODULE.bazel นั้นมีความพิเศษเนื่องจากโฮสต์อยู่ในรีจิสทรีโดยตรง

โดยทั่วไปแล้ว ผู้ใช้ที่ขอ load ใน MODULE.bazel จะสนใจ Use Case ต่อไปนี้ ซึ่งสามารถแก้ปัญหาได้โดยไม่ต้องใช้ load

  • ตรวจสอบว่าเวอร์ชันที่แสดงใน MODULE.bazel สอดคล้องกับข้อมูลเมตาของบิลด์ที่จัดเก็บไว้ที่อื่น เช่น ในไฟล์ .bzl ซึ่งทำได้โดยใช้เมธอด native.module_version ในไฟล์ .bzl ที่โหลดจากไฟล์ BUILD
  • การแยกไฟล์ MODULE.bazel ขนาดใหญ่มากออกเป็นส่วนๆ ที่จัดการได้ โดยเฉพาะอย่างยิ่งสำหรับโมโนรีโป: โมดูลรูทสามารถใช้คำสั่ง include เพื่อแยกไฟล์ MODULE.bazel ออกเป็นหลายส่วน include ใช้ในโมดูลที่ไม่ใช่รูทไม่ได้ด้วยเหตุผลเดียวกันกับที่เราไม่อนุญาตให้ใช้ load ในไฟล์ MODULE.bazel
  • ผู้ใช้ระบบ WORKSPACE เดิมอาจจำได้ว่าต้องประกาศรีโป จากนั้นloadจากรีโปนั้นทันทีเพื่อดำเนินการตามตรรกะที่ซับซ้อน ส่วนขยายโมดูลเข้ามาแทนที่ความสามารถนี้

ฉันจะระบุช่วง SemVer สำหรับ bazel_dep ได้ไหม

ไม่ได้ เครื่องมือจัดการแพ็กเกจอื่นๆ บางรายการ เช่น npm และ Cargo รองรับช่วงเวอร์ชัน (โดยนัยหรือโดยชัดแจ้ง) และมักต้องใช้โปรแกรมแก้ปัญหาข้อจำกัด (ทำให้ผู้ใช้คาดเดาเอาต์พุตได้ยากขึ้น) และทำให้ไม่สามารถแก้ไขเวอร์ชันซ้ำได้หากไม่มีไฟล์ล็อก

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

นอกจากนี้ เวอร์ชันโมดูล Bazel ยังเป็นเซตที่ใหญ่กว่าของ SemVer ดังนั้นสิ่งที่สมเหตุสมผลในสภาพแวดล้อม SemVer ที่เข้มงวดอาจใช้กับเวอร์ชันโมดูล Bazel ไม่ได้เสมอไป

ฉันจะรับ bazel_dep เวอร์ชันล่าสุดโดยอัตโนมัติได้ไหม

บางครั้งผู้ใช้บางรายจะขอความสามารถในการระบุ bazel_dep(name = "foo", version = "latest") เพื่อรับเวอร์ชันล่าสุดของ Dep โดยอัตโนมัติ ซึ่งคล้ายกับคำถามเกี่ยวกับช่วง SemVer และคำตอบก็คือ "ไม่ได้"

โซลูชันที่แนะนําคือให้การทำงานอัตโนมัติจัดการเรื่องนี้ ตัวอย่างเช่น Renovate รองรับโมดูล Bazel

บางครั้งผู้ใช้ที่ถามคำถามนี้ต้องการวิธีทําซ้ำอย่างรวดเร็วระหว่างการพัฒนาในเครื่อง ซึ่งทำได้โดยใช้ local_path_override

เหตุใดจึงมีuse_repo ทั้งหมดนี้

การใช้ส่วนขยายโมดูลในไฟล์ MODULE.bazel บางครั้งมาพร้อมกับคำสั่ง use_repo ขนาดใหญ่ ตัวอย่างเช่น การใช้งานทั่วไปของส่วนขยาย go_deps จาก gazelle อาจมีลักษณะดังนี้

go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps")
go_deps.from_file(go_mod = "//:go.mod")
use_repo(
    go_deps,
    "com_github_gogo_protobuf",
    "com_github_golang_mock",
    "com_github_golang_protobuf",
    "org_golang_x_net",
    ...  # potentially dozens of lines...
)

คำสั่ง use_repo แบบยาวอาจดูซ้ำซ้อน เนื่องจากข้อมูลดังกล่าวอยู่ในไฟล์ go.mod ที่อ้างอิงอยู่แล้ว

สาเหตุที่ Bazel ต้องใช้คำสั่ง use_repo นี้เนื่องจากจะเรียกใช้ส่วนขยายของข้อบังคับแบบเลื่อนเวลา กล่าวคือ ระบบจะเรียกใช้ส่วนขยายโมดูลก็ต่อเมื่อมีการตรวจพบผลลัพธ์ของส่วนขยายเท่านั้น เนื่องจาก "เอาต์พุต" ของส่วนขยายโมดูลคือคําจํากัดความของที่เก็บ หมายความว่าเราจะเรียกใช้ส่วนขยายโมดูลก็ต่อเมื่อมีคําขอที่เก็บที่ส่วนขยายนั้นกําหนด (เช่น หากมีการบิลด์ @org_golang_x_net//:foo เป้าหมายในตัวอย่างข้างต้น) อย่างไรก็ตาม เราจะไม่ทราบว่าส่วนขยายโมดูลจะกำหนดที่เก็บใดจนกว่าจะหลังจากเรียกใช้ คำสั่ง use_repo จะใช้ในกรณีนี้ โดยผู้ใช้สามารถบอก Bazel ว่าต้องการให้สร้างส่วนขยายจากรีโพสิทอรี่ใด จากนั้น Bazel จะเรียกใช้ส่วนขยายก็ต่อเมื่อมีการใช้รีโพสิทอรี่ที่เฉพาะเจาะจงเหล่านี้เท่านั้น

ส่วนขยายโมดูลสามารถแสดงผลออบเจ็กต์ extension_metadata จากฟังก์ชันการใช้งานเพื่อช่วยดูแลรักษาคำสั่ง use_repo นี้ ผู้ใช้สามารถเรียกใช้คำสั่ง bazel mod tidy เพื่ออัปเดตคำสั่ง use_repo สำหรับส่วนขยายโมดูลเหล่านี้

การย้ายข้อมูล Bzlmod

ระบบจะประเมิน MODULE.bazel หรือ WORKSPACE ก่อน

เมื่อตั้งค่าทั้ง --enable_bzlmod และ --enable_workspace แล้ว คุณอาจสงสัยว่าระบบใดจะได้รับการปรึกษาก่อน คำตอบสั้นๆ คือ ระบบจะประเมิน MODULE.bazel (Bzlmod) ก่อน

คำตอบแบบละเอียดคือ "รายการใดจะประเมินก่อน" ไม่ใช่คำถามที่ถูกต้อง แต่คำถามที่ถูกต้องคือ ในบริบทของรีโปที่มีชื่อตามหลักเกณฑ์ @@foo ชื่อรีโปที่ปรากฏ @bar จะเปลี่ยนเป็นอะไร หรือจะถามเป็นการแมปรีโปของ @@base ก็ได้

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

จากนั้นใช้ตาราง"repository visibility" ในคู่มือการย้ายข้อมูลเพื่อดูว่าชื่อที่ปรากฏจะนำไปยังที่เก็บข้อมูลใด ทั้งนี้ขึ้นอยู่กับที่เก็บข้อมูลตามบริบท

  • หากที่เก็บรีพอสิทเป็นรีพอสิทหลัก (@@) ให้ทำดังนี้
    1. หาก bar เป็นชื่อรีโปที่ชัดเจนซึ่งแสดงโดยไฟล์ MODULE.bazel ของโมดูลรูท (ผ่านไฟล์ bazel_dep, use_repo, module หรือ use_repo_rule) @bar จะเปลี่ยนเป็นค่าที่ไฟล์ MODULE.bazel อ้างอิง
    2. หรือหาก bar เป็นรีโปที่กําหนดไว้ใน WORKSPACE (ซึ่งหมายความว่าชื่อที่เป็นทางการคือ @@bar) @bar จะเปลี่ยนเป็น @@bar
    3. มิเช่นนั้น @bar จะเปลี่ยนเป็นรูปแบบอย่าง @@[unknown repo 'bar' requested from @@] ซึ่งท้ายที่สุดแล้วจะทำให้มีข้อผิดพลาด
  • หากที่เก็บข้อมูลบริบทเป็นที่เก็บข้อมูล Bzlmod-world (กล่าวคือ สอดคล้องกับโมดูล Bazel ที่ไม่ใช่รูท หรือสร้างขึ้นโดยส่วนขยายโมดูล) ที่เก็บข้อมูลดังกล่าวจะเห็นเฉพาะที่เก็บข้อมูล Bzlmod-world อื่นๆ เท่านั้น และจะไม่พบที่เก็บข้อมูล WORKSPACE-world
    • โปรดทราบว่าการดำเนินการนี้รวมถึงรีพอสิที่เปิดตัวในส่วนขยายโมดูล non_module_deps-like ในโมดูลรูท หรือการสร้างอินสแตนซ์ use_repo_rule ในโมดูลรูท
  • หากกำหนดที่เก็บรีพอสิทของบริบทใน WORKSPACE ให้ทำดังนี้
    1. ก่อนอื่น ให้ตรวจสอบว่าคําจํากัดความของที่เก็บรีพอซีตมีแอตทริบิวต์ repo_mapping หรือไม่ หากใช่ ให้ดูการแมปก่อน (สําหรับที่เก็บข้อมูลที่กําหนดด้วย repo_mapping = {"@bar": "@baz"} เราจะดูที่ @baz ด้านล่าง)
    2. หาก bar เป็นชื่อรีโปที่ชัดเจนซึ่งแสดงโดยไฟล์ MODULE.bazel ของโมดูลรูท @bar จะแสดงผลเป็นค่าที่ไฟล์ MODULE.bazel อ้างอิง (การดำเนินการนี้เหมือนกับรายการที่ 1 ในกรณีของรีโปหลัก)
    3. มิเช่นนั้น @bar จะเปลี่ยนเป็น @@bar ซึ่งส่วนใหญ่จะชี้ไปยังรีโพสิทอรี่ bar ที่กําหนดไว้ใน WORKSPACE หากไม่ได้กําหนดรีโพสิทอรี่ดังกล่าว Bazel จะแสดงข้อผิดพลาด

สำหรับเวอร์ชันที่กระชับยิ่งขึ้น

  • รีโพสิทอรี่ Bzlmod-world (ยกเว้นรีโพสิทอรี่หลัก) จะมองเห็นเฉพาะรีโพสิทอรี่ Bzlmod-world
  • รีโพซิทอรี WORKSPACE-world (รวมถึงรีโพซิทอรีหลัก) จะดูว่าโมดูลรูทในโลก Bzlmod กำหนดอะไรไว้ก่อน จากนั้นจึงเปลี่ยนไปดูรีโพซิทอรี WORKSPACE-world

โปรดทราบว่าระบบจะถือว่าป้ายกำกับในบรรทัดคำสั่งของ Bazel (รวมถึง Flag ของ Starlark, ค่า Flag ที่เป็นประเภทป้ายกำกับ และรูปแบบเป้าหมายการสร้าง/ทดสอบ) มีที่เก็บข้อมูลหลักเป็นที่เก็บข้อมูลบริบท

อื่นๆ

ฉันจะเตรียมและเรียกใช้บิลด์แบบออฟไลน์ได้อย่างไร

ใช้คำสั่ง bazel fetch เพื่อโหลดรีโปล่วงหน้า คุณสามารถใช้ Flag --repo (เช่น bazel fetch --repo @foo) เพื่อดึงข้อมูลเฉพาะที่เก็บ @foo (แก้ไขในบริบทของที่เก็บหลัก ดูคำถามด้านบน) หรือใช้รูปแบบเป้าหมาย (เช่น bazel fetch @foo//:bar) เพื่อดึงข้อมูล Dependency แบบทรานซิทีฟทั้งหมดของ @foo//:bar (เทียบเท่ากับ bazel build --nobuild @foo//:bar)

หากต้องการให้ไม่มีการดึงข้อมูลระหว่างการสร้าง ให้ใช้ --nofetch กล่าวอย่างเจาะจงคือ การดำเนินการใดๆ ก็ตามเพื่อเรียกใช้กฎที่เก็บข้อมูลภายนอกจะไม่สำเร็จ

หากต้องการดึงข้อมูลรีโพสและแก้ไขเพื่อทดสอบในเครื่อง ให้ลองใช้คำสั่ง bazel vendor

ฉันจะใช้พร็อกซี HTTP ได้อย่างไร

Bazel จะใช้ตัวแปรสภาพแวดล้อม http_proxy และ HTTPS_PROXY ที่โปรแกรมอื่นๆ ยอมรับโดยทั่วไป เช่น curl

How do I make Bazel prefer IPv6 in dual-stack IPv4/IPv6 setups?

ในเครื่องที่ใช้ IPv6 เท่านั้น Bazel จะดาวน์โหลดทรัพยากรที่เกี่ยวข้องได้โดยไม่ต้องเปลี่ยนแปลง อย่างไรก็ตาม ในเครื่องแบบ Dual Stack IPv4/IPv6 Bazel จะเป็นไปตามรูปแบบเดียวกับ Java โดยจะใช้ IPv4 เป็นหลักหากเปิดใช้ ในบางกรณี เช่น เมื่อเครือข่าย IPv4 ไม่สามารถแก้ไข/เข้าถึงที่อยู่ภายนอกได้ อาจทำให้เกิดข้อยกเว้น Network unreachable และการสร้างไม่สำเร็จ ในกรณีเหล่านี้ คุณสามารถลบล้างลักษณะการทํางานของ Bazel เพื่อใช้ IPv6 เป็นหลักได้โดยใช้java.net.preferIPv6Addresses=true พร็อพเพอร์ตี้ของระบบ ดังนี้

  • ใช้--host_jvm_args=-Djava.net.preferIPv6Addresses=true startup option เช่น เพิ่มบรรทัดต่อไปนี้ในไฟล์ .bazelrc

    startup --host_jvm_args=-Djava.net.preferIPv6Addresses=true

  • เมื่อเรียกใช้เป้าหมายการสร้าง Java ที่ต้องเชื่อมต่ออินเทอร์เน็ต (เช่น สําหรับการทดสอบการผสานรวม) ให้ใช้--jvmopt=-Djava.net.preferIPv6Addresses=true flag ของเครื่องมือ เช่น ใส่ข้อมูลต่อไปนี้ใน.bazelrc ไฟล์

    build --jvmopt=-Djava.net.preferIPv6Addresses

  • หากคุณใช้ rules_jvm_external ในการแก้ไขเวอร์ชันของข้อกำหนด ให้เพิ่ม -Djava.net.preferIPv6Addresses=true ลงในตัวแปรสภาพแวดล้อม COURSIER_OPTS เพื่อระบุตัวเลือก JVM สำหรับ Coursier ด้วย

กฎของ repo ทำงานจากระยะไกลด้วยการดำเนินการจากระยะไกลได้ไหม

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

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

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

เรามีแนวคิดเบื้องต้นในการแก้ปัญหานี้ด้วยการจินตนาการกฎของ repo ใหม่เป็นกฎการสร้าง ซึ่งจะทำให้สามารถเรียกใช้จากระยะไกลได้ แต่ในทางกลับกันก็อาจทำให้เกิดข้อกังวลด้านสถาปัตยกรรมใหม่ (เช่น คำสั่ง query อาจต้องเรียกใช้การดำเนินการ ซึ่งทำให้การออกแบบมีความซับซ้อน)

ดูการสนทนาก่อนหน้านี้เพิ่มเติมเกี่ยวกับหัวข้อนี้ได้ที่วิธีรองรับที่เก็บซึ่งต้องใช้ Bazel ในการดึงข้อมูล