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 ภายนอกได้ 2-3 ประเภท
- การขึ้นต่อกันบนโปรเจ็กต์อื่นๆ ของ Bazel
- การขึ้นต่อกันบนโปรเจ็กต์ที่ไม่ใช่ Bazel
- การขึ้นต่อกันกับแพ็กเกจภายนอก
ขึ้นอยู่กับโปรเจ็กต์ Bazel อื่นๆ
หากต้องการใช้เป้าหมายจากโปรเจ็กต์ Bazel ที่ 2 ให้ใช้
local_repository
,
git_repository
หรือ http_archive
เพื่อเชื่อมโยงโปรเจ็กต์จากระบบไฟล์ในเครื่อง อ้างอิงที่เก็บ Git หรือดาวน์โหลดโปรเจ็กต์ (ตามลำดับ)
ตัวอย่างเช่น สมมติว่าคุณทำงานในโปรเจ็กต์ my-project/
และคุณต้องการอิงตามเป้าหมายจากโปรเจ็กต์ coworkers-project/
ของเพื่อนร่วมงาน ทั้ง 2 โปรเจ็กต์ใช้ Bazel คุณจึงสามารถเพิ่มโปรเจ็กต์ของเพื่อนร่วมงานเป็นแบบพึ่งพิงภายนอกได้ แล้วใช้เป้าหมายที่เพื่อนร่วมงานได้กำหนดไว้จากไฟล์ 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 และทำให้ใช้งานได้เป็นแบบอ้างอิงของ Java
กำลังดึงข้อมูลการอ้างอิง
โดยค่าเริ่มต้น ระบบจะดึงข้อมูลทรัพยากร Dependency ภายนอกตามต้องการในช่วง bazel build
หากต้องการดึงข้อมูลทรัพยากร Dependency ที่จำเป็นสำหรับชุดเป้าหมายที่เฉพาะเจาะจงล่วงหน้า ให้ใช้ bazel fetch
หากต้องการดึงข้อมูลทรัพยากร Dependency ภายนอกทั้งหมดอย่างไม่มีเงื่อนไข ให้ใช้ bazel sync
เนื่องจากที่เก็บที่ดึงข้อมูลจัดเก็บไว้ในฐานเอาต์พุต การดึงข้อมูลจะเกิดขึ้นต่อพื้นที่ทำงาน
การซ่อนทรัพยากร Dependency
หากเป็นไปได้ เราขอแนะนำให้มีนโยบายเวอร์ชันเดียวในโปรเจ็กต์ ซึ่งจำเป็นสำหรับทรัพยากร Dependency ที่คุณคอมไพล์และนำมารวมกับไบนารีสุดท้าย แต่ในกรณีที่ไม่จริง ก็อาจซ่อนทรัพยากร Dependency ได้ ลองพิจารณาสถานการณ์ต่อไปนี้
โปรเจ็กต์ของฉัน/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 อย่างนี้จะชนกันเองเพราะมีชื่อเดียวกัน หากต้องการประกาศทรัพยากร Dependency ทั้งคู่ ให้อัปเดต 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 เหล่านั้นจะเข้าร่วมใน 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 แบบ 2 สแต็ก 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 สำหรับความละเอียดของเวอร์ชันทรัพยากร 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
บิลด์แบบออฟไลน์
ในบางครั้ง อาจจำเป็นหรือจำเป็นต้องเรียกใช้บิลด์ในรูปแบบออฟไลน์ สำหรับกรณีการใช้งานที่เรียบง่าย เช่น ขณะเดินทางบนเครื่องบิน การดึงข้อมูลล่วงหน้าที่เก็บที่ต้องการด้วย bazel fetch
หรือ bazel sync
ก็เพียงพอแล้ว นอกจากนี้ การใช้ตัวเลือก --nofetch
จะเป็นการปิดใช้การดึงข้อมูลที่เก็บเพิ่มเติมในระหว่างบิลด์
สำหรับบิลด์แบบออฟไลน์ที่แท้จริง ซึ่งการมอบไฟล์ที่จำเป็นต้องทำโดยเอนทิตีที่แตกต่างจาก Bayel ส่วน Bazel จะรองรับตัวเลือก --distdir
เมื่อใดก็ตามที่กฎที่เก็บขอให้ Bazel ดึงข้อมูลไฟล์ผ่าน ctx.download
หรือ ctx.download_and_extract
และให้ผลรวมแฮชของไฟล์ที่ต้องการ อันดับแรก Bazel จะดูไดเรกทอรีที่ระบุโดยตัวเลือกนั้นสำหรับไฟล์ที่ตรงกับชื่อพื้นฐานของ URL แรกที่ระบุ และใช้สำเนาในเครื่องนั้นหากแฮชตรงกัน
Bazel ใช้เทคนิคนี้เพื่อเปิดระบบออฟไลน์จากอาร์ติแฟกต์การจัดจำหน่าย
โดยรวบรวมการพึ่งพาภายนอกทั้งหมดที่จำเป็นในdistdir_tar
ภายใน
อย่างไรก็ตาม bazel จะช่วยให้ใช้คำสั่งที่กำหนดเองในกฎที่เก็บได้ โดยไม่ต้องทราบว่าระบบเรียกใช้เครือข่ายหรือไม่ ดังนั้น Bazel จึงไม่มีตัวเลือกในการบังคับให้บิลด์ออฟไลน์โดยสมบูรณ์ ดังนั้น การทดสอบว่าบิลด์ทำงานแบบออฟไลน์ได้อย่างถูกต้องหรือไม่นั้น จำเป็นต้องมีการบล็อกเครือข่ายจากภายนอก ดังเช่นที่ Bazel ทำในการทดสอบ Bootstrapped
แนวทางปฏิบัติแนะนำ
กฎที่เก็บ
โดยทั่วไป กฎที่เก็บควรประกอบด้วยส่วนต่อไปนี้
- การตรวจหาการตั้งค่าระบบและการเขียนไฟล์ลงในไฟล์
- ค้นหาแหล่งข้อมูลจากที่อื่นในระบบ
- กำลังดาวน์โหลดทรัพยากรจาก 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()
ดู "พิจารณานำการเชื่อมโยงออก" ที่มีการพูดถึงปัญหาและทางเลือกอื่นเป็นเวลานาน