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 ภายนอกที่รองรับ
ประเภททรัพยากร Dependency ภายนอกพื้นฐานที่นำมาใช้ได้มีดังนี้
- การพึ่งพาโปรเจ็กต์อื่นๆ ของ Bazel
- การพึ่งพาโปรเจ็กต์ที่ไม่ใช่ Bazel
- ทรัพยากร Dependency ของแพ็กเกจภายนอก
ขึ้นอยู่กับโปรเจ็กต์ Bazel อื่นๆ
หากต้องการใช้เป้าหมายจากโปรเจ็กต์ Bazel ที่สอง คุณสามารถใช้
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
โดยค่าเริ่มต้น ระบบจะดึงข้อมูลทรัพยากร Dependency ภายนอกตามความจำเป็นในช่วง bazel build
หากต้องการดึงข้อมูลล่วงหน้าที่จำเป็นสำหรับชุดเป้าหมายที่เฉพาะเจาะจง ให้ใช้ bazel fetch
หากต้องการดึงข้อมูลทรัพยากร Dependency ภายนอกทั้งหมดอย่างไม่มีเงื่อนไข ให้ใช้ bazel sync
เนื่องจากที่เก็บที่ดึงข้อมูลมาจัดเก็บไว้ในฐานเอาต์พุต การดึงข้อมูลจึงเกิดขึ้นในแต่ละพื้นที่ทำงาน
ทรัพยากร Dependency ที่ไม่มีการแก้ไข
เราขอแนะนำให้คุณมีนโยบายเวอร์ชันเดียวในโปรเจ็กต์หากเป็นไปได้ ซึ่งจำเป็นสำหรับทรัพยากร Dependency ที่คุณคอมไพล์แล้วไปอยู่ในไบนารีสุดท้าย แต่สำหรับกรณีที่ไม่เป็นความจริง อาจทำเงา Dependency ได้ พิจารณาสถานการณ์ต่อไปนี้
โปรเจ็กต์ของฉัน/พื้นที่ทำงาน
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(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 เหล่านั้นใน 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
แต่จำกัดโอกาสในการมีไลบรารี 1 รายการรวมถึง C
ที่เวอร์ชัน 1.0 และอีกไลบรารีหนึ่งรวม C
ที่ 2.0
การแคชทรัพยากร Dependency ภายนอก
โดยค่าเริ่มต้น Bazel จะดาวน์โหลดทรัพยากร Dependency ภายนอกอีกครั้งเมื่อนิยามมีการเปลี่ยนแปลงเท่านั้น การเปลี่ยนแปลงไฟล์ที่อ้างอิงในคำจำกัดความ (เช่น แพตช์หรือไฟล์ BUILD
) จะได้รับการพิจารณาด้วย Bazel
หากต้องการบังคับให้ดาวน์โหลดใหม่ ให้ใช้ bazel sync
เลย์เอาต์
ระบบจะดาวน์โหลดทรัพยากร Dependency ภายนอกทั้งหมดไปยังไดเรกทอรีภายใต้ไดเรกทอรีย่อย external
ในฐานเอาต์พุต ในกรณีที่เป็นที่เก็บในเครื่อง ระบบจะสร้างลิงก์สัญลักษณ์ขึ้นมาแทนการสร้างไดเรกทอรีใหม่
คุณดูไดเรกทอรี external
ได้โดยเรียกใช้สิ่งต่อไปนี้
ls $(bazel info output_base)/external
โปรดทราบว่าการเรียกใช้ bazel clean
จะไม่ลบไดเรกทอรีภายนอกจริงๆ หากต้องการนำอาร์ติแฟกต์ภายนอกทั้งหมดออก ให้ใช้ bazel clean --expunge
บิลด์แบบออฟไลน์
บางครั้งการสร้างงานแบบออฟไลน์ก็เป็นไปตามความต้องการหรือจำเป็น สำหรับกรณีการใช้งานง่ายๆ เช่น การเดินทางบนเครื่องบิน
การดึงข้อมูลล่วงหน้าที่เก็บที่จำเป็นด้วย bazel fetch
หรือ bazel sync
ก็อาจเพียงพอแล้ว นอกจากนี้
การใช้ตัวเลือก --nofetch
ทำให้สามารถปิดใช้การดึงข้อมูลที่เก็บเพิ่มเติมระหว่างการสร้างได้
สำหรับบิลด์ True แบบออฟไลน์ ซึ่งจะต้องจัดเตรียมไฟล์ที่จำเป็นโดยเอนทิตีที่แตกต่างจาก bazel, bazel จะรองรับตัวเลือก --distdir
เมื่อใดก็ตามที่กฎที่เก็บขอให้ Bazel ดึงไฟล์ผ่าน ctx.download
หรือ ctx.download_and_extract
และระบุแฮชผลรวมของไฟล์ที่ต้องการ Bazel จะตรวจสอบไดเรกทอรีที่ระบุโดยตัวเลือกนั้นก่อนสำหรับไฟล์ที่ตรงกับชื่อฐานของ URL แรกที่ระบุ และใช้สำเนาในเครื่องนั้นหากแฮชตรงกัน
Bazel เองก็ใช้เทคนิคนี้เพื่อเปิดเครื่องแบบออฟไลน์จากอาร์ติแฟกต์การกระจาย
ซึ่งทําโดยรวบรวมทรัพยากร Dependency ภายนอกทั้งหมดที่จําเป็นใน distdir_tar
ภายใน
อย่างไรก็ตาม bazel จะอนุญาตคำสั่งที่กำหนดเองในกฎที่เก็บ โดยไม่รู้ว่าการเรียกไปยังเครือข่ายนั้นหรือไม่ ดังนั้น Bazel จึงไม่มีตัวเลือกในการบังคับใช้บิลด์แบบออฟไลน์โดยสมบูรณ์ ดังนั้นการทดสอบว่าบิลด์ทำงานแบบออฟไลน์ได้อย่างถูกต้องหรือไม่นั้น ต้องมีการบล็อกเครือข่ายจากภายนอกเหมือนกับที่ Bazel ทำในการทดสอบบูตสแตรป
แนวทางปฏิบัติแนะนำ
กฎที่เก็บ
โดยทั่วไปกฎที่เก็บควรมีหน้าที่ต่อไปนี้
- กำลังตรวจหาการตั้งค่าระบบและเขียนลงในไฟล์
- กำลังค้นหาแหล่งข้อมูลในส่วนอื่นๆ ของระบบ
- กำลังดาวน์โหลดทรัพยากรจาก URL
- กำลังสร้างหรือ Symlink ไฟล์ 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()
ดู "พิจารณายกเลิกการผูก" สำหรับการพูดคุยถึงปัญหาและทางเลือกต่างๆ ที่ยาวนาน