Bazel สามารถขึ้นอยู่กับเป้าหมายจากโปรเจ็กต์อื่นๆ ได้ เราเรียกทรัพยากร Dependency จากโปรเจ็กต์อื่นๆ เหล่านี้ว่า ทรัพยากร Dependency ภายนอก
ไฟล์ WORKSPACE (หรือไฟล์ WORKSPACE.bazel) ใน
ไดเรกทอรีพื้นที่ทำงาน
จะบอก Bazel ถึงวิธีรับซอร์สโค้ดของโปรเจ็กต์อื่นๆ โปรเจ็กต์อื่นๆ เหล่านี้อาจมีไฟล์ BUILD อย่างน้อย 1 ไฟล์ที่มีเป้าหมายของตัวเอง ไฟล์ BUILD ภายในโปรเจ็กต์หลักสามารถขึ้นอยู่กับเป้าหมายภายนอกเหล่านี้ได้โดยใช้ชื่อจากไฟล์ WORKSPACE
ตัวอย่างเช่น สมมติว่ามี 2 โปรเจ็กต์ในระบบ
/
home/
user/
project1/
WORKSPACE
BUILD
srcs/
...
project2/
WORKSPACE
BUILD
my-libs/
หาก project1 ต้องการขึ้นอยู่กับเป้าหมาย :foo ที่กำหนดไว้ใน
/home/user/project2/BUILD ก็สามารถระบุได้ว่าที่เก็บชื่อ
project2 อยู่ที่ /home/user/project2 จากนั้นเป้าหมายใน /home/user/project1/BUILD ก็สามารถขึ้นอยู่กับ @project2//:foo ได้
ไฟล์ WORKSPACE ช่วยให้ผู้ใช้ขึ้นอยู่กับเป้าหมายจากส่วนอื่นๆ ของระบบไฟล์หรือดาวน์โหลดจากอินเทอร์เน็ตได้ โดยใช้ไวยากรณ์เดียวกับไฟล์ BUILD แต่มีกฎที่แตกต่างกันซึ่งเรียกว่า กฎที่เก็บ (บางครั้งก็เรียกว่า กฎพื้นที่ทำงาน) Bazel มาพร้อมกับกฎที่เก็บในตัว 2-3 ข้อ
และชุดกฎที่เก็บ Starlark ที่ฝังไว้
ผู้ใช้ยังเขียนกฎที่เก็บที่กำหนดเอง
เพื่อรับลักษณะการทำงานที่ซับซ้อนมากขึ้นได้ด้วย
ประเภททรัพยากร Dependency ภายนอกที่รองรับ
คุณใช้ทรัพยากร Dependency ภายนอกประเภทพื้นฐานบางประเภทได้ ดังนี้
- ทรัพยากร Dependency ในโปรเจ็กต์ Bazel อื่นๆ
- ทรัพยากร Dependency ในโปรเจ็กต์ที่ไม่ใช่ Bazel
- ทรัพยากร Dependency ในแพ็กเกจภายนอก
การขึ้นอยู่กับโปรเจ็กต์ Bazel อื่นๆ
หากต้องการใช้เป้าหมายจากโปรเจ็กต์ Bazel ที่ 2 คุณสามารถ
ใช้
local_repository,
git_repository
หรือ http_archive
เพื่อสร้างลิงก์สัญลักษณ์จากระบบไฟล์ในเครื่อง อ้างอิงที่เก็บ Git หรือดาวน์โหลด (ตามลำดับ)
ตัวอย่างเช่น สมมติว่าคุณกำลังทำงานในโปรเจ็กต์ my-project/ และต้องการขึ้นอยู่กับเป้าหมายจากโปรเจ็กต์ของเพื่อนร่วมงาน coworkers-project/ ทั้ง 2 โปรเจ็กต์ใช้ Bazel ดังนั้นคุณจึงเพิ่มโปรเจ็กต์ของเพื่อนร่วมงานเป็นทรัพยากร Dependency ภายนอก แล้วใช้เป้าหมายใดก็ได้ที่เพื่อนร่วมงานกำหนดไว้จากไฟล์ BUILD ของคุณเอง คุณจะต้องเพิ่มข้อมูลต่อไปนี้ลงใน my_project/WORKSPACE
local_repository(
name = "coworkers_project",
path = "/path/to/coworkers-project",
)
หากเพื่อนร่วมงานมีเป้าหมาย //foo:bar โปรเจ็กต์ของคุณจะอ้างอิงเป้าหมายดังกล่าวเป็น
@coworkers_project//foo:bar ชื่อโปรเจ็กต์ภายนอกต้องเป็น
ชื่อพื้นที่ทำงานที่ถูกต้อง
การขึ้นอยู่กับโปรเจ็กต์ที่ไม่ใช่ Bazel
กฎที่ขึ้นต้นด้วย new_ เช่น
new_local_repository,
ช่วยให้คุณสร้างเป้าหมายจากโปรเจ็กต์ที่ไม่ได้ใช้ Bazel ได้
ตัวอย่างเช่น สมมติว่าคุณกำลังทำงานในโปรเจ็กต์ my-project/ และต้องการขึ้นอยู่กับโปรเจ็กต์ของเพื่อนร่วมงาน coworkers-project/ โปรเจ็กต์ของเพื่อนร่วมงานใช้ make ในการสร้าง แต่คุณต้องการขึ้นอยู่กับไฟล์ .so ไฟล์ใดไฟล์หนึ่งที่โปรเจ็กต์สร้างขึ้น หากต้องการทำเช่นนั้น ให้เพิ่มข้อมูลต่อไปนี้ลงใน my_project/WORKSPACE
new_local_repository(
name = "coworkers_project",
path = "/path/to/coworkers-project",
build_file = "coworker.BUILD",
)
build_file จะระบุไฟล์ BUILD ที่จะซ้อนทับในโปรเจ็กต์ที่มีอยู่ เช่น
cc_library(
name = "some-lib",
srcs = glob(["**"]),
visibility = ["//visibility:public"],
)
จากนั้นคุณจะขึ้นอยู่กับ @coworkers_project//:some-lib จากไฟล์ BUILD ของโปรเจ็กต์ได้
การขึ้นอยู่กับแพ็กเกจภายนอก
อาร์ติแฟกต์และที่เก็บ Maven
ใช้ชุดกฎ rules_jvm_external
เพื่อดาวน์โหลดอาร์ติแฟกต์จากที่เก็บ Maven และทำให้พร้อมใช้งานเป็นทรัพยากร Dependency ของ Java
การดึงทรัพยากร Dependency
โดยค่าเริ่มต้น ระบบจะดึงทรัพยากร Dependency ภายนอกตามความจำเป็นระหว่าง bazel build หาก
ต้องการดึงทรัพยากร Dependency ที่จำเป็นสำหรับเป้าหมายชุดหนึ่งล่วงหน้า ให้ใช้
bazel fetch
หากต้องการดึงทรัพยากร Dependency ภายนอกทั้งหมดโดยไม่มีเงื่อนไข ให้ใช้
bazel sync
เนื่องจากระบบจะจัดเก็บที่เก็บที่ดึงมาในฐานเอาต์พุต การดึงจึงเกิดขึ้นต่อพื้นที่ทำงาน
การซ่อนทรัพยากร Dependency
เราขอแนะนำให้ใช้นโยบายเวอร์ชันเดียวในโปรเจ็กต์ทุกครั้งที่เป็นไปได้ ซึ่งจำเป็นสำหรับทรัพยากร Dependency ที่คุณคอมไพล์ด้วยและจบลงด้วยไบนารีสุดท้าย แต่ในกรณีที่ไม่ได้เป็นเช่นนั้น คุณสามารถซ่อนทรัพยากร Dependency ได้ พิจารณาสถานการณ์ต่อไปนี้
myproject/WORKSPACE
workspace(name = "myproject")
local_repository(
name = "A",
path = "../A",
)
local_repository(
name = "B",
path = "../B",
)
A/WORKSPACE
workspace(name = "A")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "testrunner",
urls = ["https://github.com/testrunner/v1.zip"],
sha256 = "...",
)
B/WORKSPACE
workspace(name = "B")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "testrunner",
urls = ["https://github.com/testrunner/v2.zip"],
sha256 = "..."
)
ทั้งทรัพยากร Dependency A และ B ขึ้นอยู่กับ testrunner แต่ขึ้นอยู่กับ testrunner เวอร์ชันต่างๆ ไม่มีเหตุผลที่ตัวทดสอบเหล่านี้จะอยู่ร่วมกันอย่างราบรื่นภายใน myproject ไม่ได้ แต่จะขัดแย้งกันเนื่องจากมีชื่อเดียวกัน หากต้องการประกาศทรัพยากร Dependency ทั้ง 2 รายการ ให้อัปเดต myproject/WORKSPACE ดังนี้
workspace(name = "myproject")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "testrunner-v1",
urls = ["https://github.com/testrunner/v1.zip"],
sha256 = "..."
)
http_archive(
name = "testrunner-v2",
urls = ["https://github.com/testrunner/v2.zip"],
sha256 = "..."
)
local_repository(
name = "A",
path = "../A",
repo_mapping = {"@testrunner" : "@testrunner-v1"}
)
local_repository(
name = "B",
path = "../B",
repo_mapping = {"@testrunner" : "@testrunner-v2"}
)
นอกจากนี้ กลไกนี้ยังใช้เพื่อรวมไดมอนด์ได้ด้วย เช่น หาก A และ B มีทรัพยากร Dependency เดียวกันแต่เรียกทรัพยากร Dependency นั้นด้วยชื่อต่างๆ กัน คุณสามารถรวมทรัพยากร Dependency เหล่านั้นใน myproject/WORKSPACE ได้
การลบล้างที่เก็บจากบรรทัดคำสั่ง
หากต้องการลบล้างที่เก็บที่ประกาศไว้ด้วยที่เก็บในเครื่องจากบรรทัดคำสั่ง
ให้ใช้
--override_repository
แฟล็ก การใช้แฟล็กนี้จะเปลี่ยนเนื้อหาของที่เก็บภายนอกโดยไม่เปลี่ยนซอร์สโค้ด
ตัวอย่างเช่น หากต้องการลบล้าง @foo เป็นไดเรกทอรีในเครื่อง /path/to/local/foo,
ให้ส่งแฟล็ก --override_repository=foo=/path/to/local/foo
กรณีการใช้งานบางส่วน ได้แก่
- การแก้ไขข้อบกพร่อง เช่น คุณสามารถลบล้างที่เก็บ
http_archiveเป็นไดเรกทอรีในเครื่องที่คุณทำการเปลี่ยนแปลงได้ง่ายขึ้น - เวนเดอร์ริง หากคุณอยู่ในสภาพแวดล้อมที่ทำการเรียกเครือข่ายไม่ได้ ให้ลบล้างกฎที่เก็บตามเครือข่ายเพื่อชี้ไปยังไดเรกทอรีในเครื่องแทน
การใช้พร็อกซี
Bazel จะเลือกที่อยู่พร็อกซีจากตัวแปรสภาพแวดล้อม HTTPS_PROXY และ HTTP_PROXY แล้วใช้ที่อยู่เหล่านี้เพื่อดาวน์โหลดไฟล์ HTTP/HTTPS (หากระบุไว้)
การรองรับ IPv6
ในเครื่องที่ใช้ IPv6 เท่านั้น Bazel จะดาวน์โหลดทรัพยากร Dependency ได้โดยไม่มีการเปลี่ยนแปลง อย่างไรก็ตาม ในเครื่องที่ใช้ IPv4/IPv6 แบบ Dual-stack Bazel จะใช้กฎเดียวกันกับ Java นั่นคือ หากเปิดใช้ IPv4 ระบบจะเลือกใช้ IPv4 ในบางสถานการณ์ เช่น เมื่อเครือข่าย IPv4 ไม่สามารถแก้ปัญหา/เข้าถึงที่อยู่ภายนอกได้ กรณีนี้อาจทำให้เกิดข้อยกเว้น Network unreachable และการสร้างล้มเหลว
ในกรณีดังกล่าว คุณสามารถลบล้างลักษณะการทำงานของ Bazel เพื่อเลือกใช้ IPv6
โดยใช้ java.net.preferIPv6Addresses=true พร็อพเพอร์ตี้ระบบ
ดังนี้
ใช้
--host_jvm_args=-Djava.net.preferIPv6Addresses=trueตัวเลือกการเริ่มต้น, เช่น โดยการเพิ่มบรรทัดต่อไปนี้ในไฟล์.bazelrc:startup --host_jvm_args=-Djava.net.preferIPv6Addresses=trueหากคุณเรียกใช้เป้าหมายบิลด์ Java ที่ต้องเชื่อมต่ออินเทอร์เน็ต ด้วย (บางครั้งการทดสอบการผสานรวมก็จำเป็นต้องใช้) ให้ใช้
--jvmopt=-Djava.net.preferIPv6Addresses=trueแฟล็กเครื่องมือด้วย เช่น โดยการเพิ่ม บรรทัดต่อไปนี้ในไฟล์.bazelrcbuild --jvmopt=-Djava.net.preferIPv6Addressesหากคุณใช้ rules_jvm_external เช่น เพื่อการแก้ปัญหาเวอร์ชันทรัพยากร Dependency ให้เพิ่ม
-Djava.net.preferIPv6Addresses=trueลงในCOURSIER_OPTSตัวแปรสภาพแวดล้อม เพื่อ ระบุตัวเลือก JVM สำหรับ Coursier
ทรัพยากร Dependency แบบส่งผ่าน
Bazel จะอ่านเฉพาะทรัพยากร Dependency ที่ระบุไว้ในไฟล์ WORKSPACE หากโปรเจ็กต์
(A) ขึ้นอยู่กับโปรเจ็กต์อื่น (B) ซึ่งระบุทรัพยากร Dependency ในโปรเจ็กต์ที่ 3
โปรเจ็กต์ (C) ในไฟล์ WORKSPACE คุณจะต้องเพิ่มทั้ง B
และ C ลงในไฟล์ WORKSPACE ของโปรเจ็กต์ ข้อกำหนดนี้อาจทำให้ขนาดไฟล์
WORKSPACEใหญ่ขึ้น แต่จะจำกัดโอกาสที่ไลบรารีหนึ่งจะ
รวม C เวอร์ชัน 1.0 และอีกไลบรารีหนึ่งจะรวม C เวอร์ชัน 2.0
การแคชทรัพยากร Dependency ภายนอก
โดยค่าเริ่มต้น Bazel จะดาวน์โหลดทรัพยากร Dependency ภายนอกอีกครั้งก็ต่อเมื่อมีการเปลี่ยนแปลงคำจำกัดความ Bazel จะพิจารณาการเปลี่ยนแปลงไฟล์ที่อ้างอิงในคำจำกัดความ (เช่น แพตช์หรือไฟล์ BUILD)
หากต้องการบังคับให้ดาวน์โหลดอีกครั้ง ให้ใช้ bazel sync
เลย์เอาต์
ระบบจะดาวน์โหลดทรัพยากร Dependency ภายนอกทั้งหมดลงในไดเรกทอรีภายใต้ไดเรกทอรีย่อย
external ใน ฐานเอาต์พุต ในกรณีของที่เก็บในเครื่อง ระบบจะสร้างลิงก์สัญลักษณ์ที่นั่นแทนการสร้างไดเรกทอรีใหม่
คุณดูไดเรกทอรี external ได้โดยเรียกใช้คำสั่งต่อไปนี้
ls $(bazel info output_base)/externalโปรดทราบว่าการเรียกใช้ bazel clean จะไม่ลบไดเรกทอรีภายนอก หากต้องการนำอาร์ติแฟกต์ภายนอกทั้งหมดออก ให้ใช้ bazel clean --expunge
การสร้างแบบออฟไลน์
บางครั้งคุณอาจต้องการหรือจำเป็นต้องเรียกใช้บิลด์แบบออฟไลน์ สำหรับ กรณีการใช้งานง่ายๆ เช่น การเดินทางบนเครื่องบิน prefetchingที่เก็บที่จำเป็นด้วย bazel fetch หรือ bazel sync อาจเพียงพอ นอกจากนี้ คุณยังปิดใช้การดึงที่เก็บเพิ่มเติมระหว่างการบิลด์ได้ โดยใช้ตัวเลือก --nofetch
สำหรับการสร้างแบบออฟไลน์อย่างแท้จริง ซึ่งหน่วยงานอื่นที่ไม่ใช่ Bazel จะเป็นผู้จัดหาไฟล์ที่จำเป็น Bazel รองรับตัวเลือก --distdir เมื่อใดก็ตามที่กฎที่เก็บขอให้ Bazel ดึงไฟล์ผ่าน
ctx.download หรือ
ctx.download_and_extract
และระบุผลรวมแฮชของไฟล์
ที่จำเป็น Bazel จะค้นหาไฟล์ที่ตรงกับชื่อไฟล์ของ URL แรกที่ระบุไว้ในไดเรกทอรีที่ระบุโดยตัวเลือกนั้นก่อน และใช้สำเนาในเครื่อง
หากแฮชตรงกัน
Bazel เองก็ใช้เทคนิคนี้เพื่อเริ่มต้นแบบออฟไลน์จากอาร์ติแฟกต์
การเผยแพร่
โดยรวบรวมทรัพยากร Dependency ภายนอกที่จำเป็นทั้งหมดไว้ใน ทรัพยากร Dependency ภายนอกที่จำเป็นทั้งหมด
ทรัพยากร Dependency
ใน
distdir_tar ภายใน
อย่างไรก็ตาม Bazel อนุญาตให้เรียกใช้คำสั่งที่กำหนดเองในกฎที่เก็บโดยไม่ทราบว่าคำสั่งเหล่านั้นจะเรียกเครือข่ายหรือไม่ ดังนั้น Bazel จึงไม่มีตัวเลือกในการบังคับให้การสร้างเป็นแบบออฟไลน์อย่างสมบูรณ์ การทดสอบว่าบิลด์ทำงานแบบออฟไลน์ได้อย่างถูกต้องหรือไม่จึงต้องมีการบล็อกเครือข่ายภายนอก เช่นเดียวกับที่ Bazel ทำในการทดสอบการเริ่มต้น
แนวทางปฏิบัติแนะนำ
กฎที่เก็บ
โดยทั่วไปกฎที่เก็บควรมีหน้าที่รับผิดชอบในเรื่องต่อไปนี้
- การตรวจหาการตั้งค่าระบบและการเขียนการตั้งค่าเหล่านั้นลงในไฟล์
- การค้นหาทรัพยากรที่อื่นในระบบ
- การดาวน์โหลดทรัพยากรจาก URL
- การสร้างหรือสร้างลิงก์สัญลักษณ์ไฟล์ BUILD ลงในไดเรกทอรีที่เก็บภายนอก
หลีกเลี่ยงการใช้ repository_ctx.execute เมื่อเป็นไปได้ ตัวอย่างเช่น เมื่อใช้ไลบรารี C++ ที่ไม่ใช่ Bazel ซึ่งมีการสร้างโดยใช้ Make คุณควรใช้ repository_ctx.download() แล้วเขียนไฟล์ BUILD ที่สร้างไลบรารีนั้น แทนการเรียกใช้ ctx.execute(["make"])
ควรใช้ http_archive แทน git_repository และ
new_git_repository เนื่องจากเหตุผลต่อไปนี้
- กฎที่เก็บ Git ขึ้นอยู่กับ
git(1)ของระบบ ในขณะที่ตัวดาวน์โหลด HTTP สร้างขึ้นใน Bazel และไม่มีทรัพยากร Dependency ของระบบ http_archiveรองรับรายการurlsเป็นมิเรอร์ และgit_repositoryรองรับremoteรายการเดียวเท่านั้นhttp_archiveทำงานร่วมกับแคชที่เก็บ แต่ไม่ทำงานgit_repositoryดูข้อมูลเพิ่มเติมได้ที่ #5116
อย่าใช้ bind() ดู "พิจารณานำ
bind" เพื่ออ่านการสนทนาอย่างละเอียดเกี่ยวกับปัญหาและทางเลือกอื่นๆ