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 มาพร้อมกับกฎของที่เก็บในตัวและชุดกฎของที่เก็บ Starlark ที่ฝังไว้ นอกจากนี้ ผู้ใช้ยังเขียนกฎที่เก็บข้อมูลที่กำหนดเองเพื่อให้ได้ลักษณะการทำงานที่ซับซ้อนยิ่งขึ้นได้ด้วย
ประเภททรัพยากร Dependency ภายนอกที่รองรับ
คุณใช้การอ้างอิงภายนอกประเภทพื้นฐานได้ 2-3 ประเภท ดังนี้
- การขึ้นต่อกันของโปรเจ็กต์ 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/
เป็นทรัพยากร Dependency โปรเจ็กต์ของเพื่อนร่วมงานใช้ 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
โดยค่าเริ่มต้น ระบบจะดึงข้อมูลการอ้างอิงภายนอกตามต้องการในระหว่าง bazel build
หากต้องการดึงข้อมูลล่วงหน้าของทรัพยากร Dependency ที่จำเป็นสำหรับชุดเป้าหมายที่เฉพาะเจาะจง ให้ใช้
bazel fetch
หากต้องการดึงข้อมูลการอ้างอิงภายนอกทั้งหมดโดยไม่มีเงื่อนไข ให้ใช้
bazel sync
เนื่องจากระบบจัดเก็บที่เก็บที่ดึงข้อมูลไว้ในฐานเอาต์พุต การดึงข้อมูลจึงเกิดขึ้นต่อพื้นที่ทำงาน
การซ่อนทรัพยากร 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
ไม่ได้ แต่เครื่องมือเหล่านี้จะขัดแย้งกันเนื่องจากมีชื่อเดียวกัน หากต้องการประกาศทั้ง 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
มีการอ้างอิงเดียวกันแต่เรียกด้วยชื่อที่ต่างกัน คุณก็สามารถรวมการอ้างอิงเหล่านั้นได้ใน myproject/WORKSPACE
การลบล้างที่เก็บจากบรรทัดคำสั่ง
หากต้องการลบล้างที่เก็บที่ประกาศด้วยที่เก็บในเครื่องจากบรรทัดคำสั่ง
ให้ใช้ Flag
--override_repository
การใช้แฟล็กนี้จะเปลี่ยนเนื้อหาของที่เก็บภายนอกโดยไม่ต้อง
เปลี่ยนซอร์สโค้ด
เช่น หากต้องการลบล้าง @foo
เป็นไดเรกทอรีในเครื่อง /path/to/local/foo
ให้ส่งแฟล็ก --override_repository=foo=/path/to/local/foo
กรณีการใช้งานบางส่วนมีดังนี้
- การแก้ไขข้อบกพร่อง เช่น คุณสามารถลบล้างที่เก็บ
http_archive
ไปยังไดเรกทอรีในเครื่องเพื่อให้ทำการเปลี่ยนแปลงได้ง่ายขึ้น - Vendoring หากอยู่ในสภาพแวดล้อมที่โทรผ่านเครือข่ายไม่ได้ ให้ ลบล้างกฎที่เก็บตามเครือข่ายเพื่อชี้ไปยังไดเรกทอรีในเครื่อง แทน
การใช้พร็อกซี
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
แฟล็กเครื่องมือด้วย เช่น โดยมีบรรทัดต่อไปนี้ในไฟล์.bazelrc
build --jvmopt=-Djava.net.preferIPv6Addresses
หากคุณใช้ rules_jvm_external เช่น เพื่อการแก้ปัญหาเวอร์ชันการขึ้นต่อกัน ให้เพิ่ม
-Djava.net.preferIPv6Addresses=true
ลงในตัวแปรสภาพแวดล้อมCOURSIER_OPTS
เพื่อระบุตัวเลือก JVM สำหรับ Coursier ด้วย
ทรัพยากร Dependency แบบทรานซิทีฟ
Bazel จะอ่านเฉพาะการอ้างอิงที่ระบุไว้ในไฟล์ WORKSPACE
หากโปรเจ็กต์ (A
) ของคุณขึ้นอยู่กับโปรเจ็กต์อื่น (B
) ซึ่งแสดงรายการการอ้างอิงในโปรเจ็กต์ที่สาม (C
) ในไฟล์ WORKSPACE
คุณจะต้องเพิ่มทั้ง B
และ C
ลงในไฟล์ WORKSPACE
ของโปรเจ็กต์ ข้อกำหนดนี้อาจทำให้WORKSPACE
มีขนาดไฟล์ใหญ่ขึ้น แต่จะจำกัดโอกาสที่จะมีไลบรารีหนึ่ง
รวม C
ที่เวอร์ชัน 1.0 และอีกไลบรารีรวม C
ที่เวอร์ชัน 2.0
การแคชทรัพยากร Dependency ภายนอก
โดยค่าเริ่มต้น Bazel จะดาวน์โหลดการอ้างอิงภายนอกอีกครั้งก็ต่อเมื่อคำจำกัดความมีการเปลี่ยนแปลง
Bazel จะพิจารณาการเปลี่ยนแปลงไฟล์ที่อ้างอิงในคำจำกัดความด้วย (เช่น ไฟล์แพตช์
หรือ BUILD
)
หากต้องการบังคับให้ดาวน์โหลดอีกครั้ง ให้ใช้ bazel sync
เลย์เอาต์
ระบบจะดาวน์โหลดทรัพยากร Dependency ภายนอกทั้งหมดไปยังไดเรกทอรีภายใต้ไดเรกทอรีย่อย
external
ในเอาต์พุตฐาน ในกรณีของที่เก็บข้อมูลในเครื่อง ระบบจะสร้าง Symlink
ที่นั่นแทนที่จะสร้างไดเรกทอรีใหม่
คุณดูไดเรกทอรี 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 เองก็ใช้เทคนิคนี้เพื่อเริ่มต้นแบบออฟไลน์จากอาร์ติแฟกต์การจัดจำหน่าย
โดยจะรวบรวมการอ้างอิงภายนอกที่จำเป็นทั้งหมด
ไว้ใน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 และไม่มีการขึ้นต่อกันของระบบ http_archive
รองรับรายการurls
เป็นมิเรอร์ และgit_repository
รองรับเฉพาะremote
รายการเดียวhttp_archive
ใช้ได้กับแคชที่เก็บ แต่ใช้ไม่ได้กับgit_repository
ดูข้อมูลเพิ่มเติมได้ที่ #5116
อย่าใช้ bind()
ดู "พิจารณานำ
bind ออก" เพื่อดูการอภิปรายอย่างละเอียดเกี่ยวกับปัญหาและทางเลือกอื่นๆ