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 ภายนอกที่จำเป็นทั้งหมด
ไว้ใน
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" เพื่ออ่านการสนทนาอย่างละเอียดเกี่ยวกับปัญหาและทางเลือกอื่นๆ