Bazel สร้างและทดสอบโค้ดบนฮาร์ดแวร์ ระบบปฏิบัติการ และการกำหนดค่าระบบต่างๆ ได้โดยใช้เครื่องมือสร้างเวอร์ชันต่างๆ มากมาย เช่น Linker และคอมไพเลอร์ เพื่อช่วยจัดการความซับซ้อนนี้ Bazel มีแนวคิดเกี่ยวกับข้อจำกัดและแพลตฟอร์ม ข้อจำกัดคือมิติข้อมูลที่สภาพแวดล้อมบิลด์หรือเวอร์ชันที่ใช้งานจริงอาจแตกต่างกันไป เช่น สถาปัตยกรรม CPU, การมีหรือไม่มี GPU หรือเวอร์ชันของคอมไพเลอร์ที่ติดตั้งโดยระบบ แพลตฟอร์มคือกลุ่มตัวเลือกที่มีชื่อสำหรับข้อจำกัดเหล่านี้ โดยจะแสดงทรัพยากรเฉพาะที่มีอยู่ในสภาพแวดล้อมบางอย่าง
การประมาณสภาพแวดล้อมเป็นแพลตฟอร์มช่วยให้ Bazel เลือกเครื่องมือเชนที่เหมาะสมสำหรับการดำเนินการบิลด์ได้โดยอัตโนมัติ คุณยังใช้แพลตฟอร์มร่วมกับกฎ config_setting เพื่อเขียนแอตทริบิวต์ที่กำหนดค่าได้ได้อีกด้วย
Bazel ตระหนักถึง 3 บทบาทที่แพลตฟอร์มอาจให้บริการ ดังนี้
- โฮสต์ - แพลตฟอร์มที่ Bazel ใช้งาน
- การดำเนินการ - แพลตฟอร์มที่เครื่องมือการสร้างดำเนินการกับการดำเนินการของบิลด์เพื่อสร้างเอาต์พุตระดับกลางและสุดท้าย
- เป้าหมาย - แพลตฟอร์มที่มีและส่งออกเอาต์พุตขั้นสุดท้าย
Bazel รองรับแพลตฟอร์มต่างๆ ในบิลด์ต่อไปนี้
บิลด์แพลตฟอร์มเดียว (ค่าเริ่มต้น) - แพลตฟอร์มโฮสต์ การดำเนินการ และแพลตฟอร์มเป้าหมายจะเหมือนกัน เช่น การสร้างไฟล์ปฏิบัติการ Linux บน Ubuntu ที่ใช้ CPU ของ Intel x64
บิลด์ข้ามการคอมไพล์ - แพลตฟอร์มโฮสต์และการดำเนินการเหมือนกัน แต่แพลตฟอร์มเป้าหมายต่างกัน เช่น การสร้างแอป iOS บน macOS ที่ทำงานใน MacBook Pro
บิลด์หลายแพลตฟอร์ม - แพลตฟอร์มโฮสต์ การดำเนินการ และแพลตฟอร์มเป้าหมายล้วนแตกต่างกัน
การกำหนดข้อจำกัดและแพลตฟอร์ม
ระบบจะกำหนดช่องว่างของตัวเลือกที่เป็นไปได้สำหรับแพลตฟอร์มโดยใช้กฎ constraint_setting
และ constraint_value
ภายในไฟล์ BUILD
constraint_setting
สร้างมิติข้อมูลใหม่ ในขณะที่ constraint_value
จะสร้างค่าใหม่สำหรับมิติข้อมูลที่ระบุ ซึ่งร่วมกันกำหนดค่า enum และค่าที่เป็นไปได้ได้อย่างมีประสิทธิภาพ เช่น ข้อมูลโค้ดต่อไปนี้ของไฟล์ BUILD
ทำให้เกิดข้อจำกัดสำหรับเวอร์ชัน glibc ของระบบโดยมีค่าที่เป็นไปได้ 2 ค่า
constraint_setting(name = "glibc_version")
constraint_value(
name = "glibc_2_25",
constraint_setting = ":glibc_version",
)
constraint_value(
name = "glibc_2_26",
constraint_setting = ":glibc_version",
)
โดยระบบอาจกำหนดข้อจำกัดและค่าของข้อจำกัดในแพ็กเกจต่างๆ ในพื้นที่ทำงาน การอ้างอิงเหล่านี้จะมีป้ายกำกับตามป้ายกำกับและอยู่ภายใต้การควบคุมการแสดงผลตามปกติ หากระดับการเข้าถึงอนุญาต คุณอาจขยายการตั้งค่าข้อจำกัดที่มีอยู่ได้โดยกำหนดมูลค่าสำหรับข้อจำกัดนั้นเอง
กฎ platform
จะแนะนำแพลตฟอร์มใหม่ที่มีตัวเลือกค่าจำกัดบางตัวเลือก ตัวอย่างต่อไปนี้สร้างแพลตฟอร์มชื่อ linux_x86
และระบุว่าแพลตฟอร์มนั้นอธิบายสภาพแวดล้อมใดๆ ที่เรียกใช้ระบบปฏิบัติการ Linux บนสถาปัตยกรรม x86_64 ด้วย glibc เวอร์ชัน 2.25 (ดูข้อมูลเพิ่มเติมเกี่ยวกับข้อจำกัดในตัวของ Bazel ที่ด้านล่าง)
platform(
name = "linux_x86",
constraint_values = [
"@platforms//os:linux",
"@platforms//cpu:x86_64",
":glibc_2_25",
],
)
ข้อจำกัดและแพลตฟอร์มที่มีประโยชน์โดยทั่วไป
ทีม Bazel จะใช้ที่เก็บที่มีคำจำกัดความจำกัดสำหรับสถาปัตยกรรม CPU และระบบปฏิบัติการที่ได้รับความนิยมสูงสุด เพื่อรักษาระบบนิเวศให้สอดคล้องกัน ซึ่งทั้งหมดจะอยู่ที่ https://github.com/bazelbuild/platforms
Bazel มาพร้อมกับแพลตฟอร์มพิเศษตามคำจำกัดความของแพลตฟอร์มพิเศษต่อไปนี้ @platforms//host
(นามแฝงเป็น @bazel_tools//tools:host_platform
) นี่คือค่าแพลตฟอร์มของโฮสต์ที่ตรวจหาโดยอัตโนมัติ ซึ่งแสดงถึงแพลตฟอร์มที่ตรวจพบโดยอัตโนมัติสำหรับระบบที่ Bazel ทำงานอยู่
การระบุแพลตฟอร์มสำหรับบิลด์
คุณระบุแพลตฟอร์มโฮสต์และเป้าหมายสำหรับบิลด์ได้โดยใช้แฟล็กบรรทัดคำสั่งต่อไปนี้
--host_platform
- ค่าเริ่มต้นคือ@bazel_tools//tools:host_platform
- เป้าหมายนี้มีชื่อว่า
@platforms//host
ซึ่งมีกฎที่เก็บอยู่เบื้องหลังที่ตรวจหาระบบปฏิบัติการของโฮสต์และ CPU และเขียนเป้าหมายแพลตฟอร์ม - นอกจากนี้ยังมี
@platforms//host:constraints.bzl
ที่แสดงอาร์เรย์HOST_CONSTRAINTS
ซึ่งสามารถใช้ในไฟล์ BUILD และ Starlark อื่นๆ ได้
- เป้าหมายนี้มีชื่อว่า
--platforms
- ค่าเริ่มต้นคือแพลตฟอร์มโฮสต์- ซึ่งหมายความว่าเมื่อไม่มีการตั้งค่าแฟล็กอื่นๆ ไว้
@platforms//host
จะเป็นแพลตฟอร์มเป้าหมาย - หากตั้งค่า
--host_platform
ไม่ใช่--platforms
ค่าของ--host_platform
จะเป็นทั้งโฮสต์และแพลตฟอร์มเป้าหมาย
- ซึ่งหมายความว่าเมื่อไม่มีการตั้งค่าแฟล็กอื่นๆ ไว้
ข้ามเป้าหมายที่ใช้ร่วมกันไม่ได้
เมื่อสร้างสำหรับแพลตฟอร์มเป้าหมายที่เฉพาะเจาะจง คุณควรข้ามเป้าหมายที่จะใช้ไม่ได้บนแพลตฟอร์มนั้น เช่น ไดรเวอร์อุปกรณ์ Windows มีแนวโน้มที่จะสร้างข้อผิดพลาดของคอมไพเลอร์จำนวนมากเมื่อสร้างขึ้นในเครื่อง Linux ที่มี //...
ใช้แอตทริบิวต์ target_compatible_with
เพื่อแจ้งให้ Bazel ทราบถึงข้อจำกัดของแพลตฟอร์มเป้าหมายที่โค้ดของคุณมี
การใช้แอตทริบิวต์นี้ที่ง่ายที่สุดจะจำกัดเป้าหมายให้แพลตฟอร์มเดียว
ระบบจะไม่สร้างเป้าหมายสำหรับแพลตฟอร์มที่ไม่ตรงตามข้อจำกัดทั้งหมด ตัวอย่างต่อไปนี้จำกัด win_driver_lib.cc
ไว้ที่ Windows แบบ 64 บิต
cc_library(
name = "win_driver_lib",
srcs = ["win_driver_lib.cc"],
target_compatible_with = [
"@platforms//cpu:x86_64",
"@platforms//os:windows",
],
)
:win_driver_lib
ใช้ได้กับการสร้างด้วย Windows แบบ 64 บิตเท่านั้นและใช้งานร่วมกับ Windows อื่นๆ ไม่ได้ ความไม่เข้ากันนั้นจะมีผลทางอ้อม เป้าหมายใดๆ ที่ขึ้นอยู่กับเป้าหมายที่ใช้ร่วมกันไม่ได้จะถือว่าใช้ร่วมกันไม่ได้
เป้าหมายจะถูกข้ามเมื่อใด
ระบบจะข้ามเป้าหมายเมื่อถือว่าเข้ากันไม่ได้และรวมอยู่ในบิลด์เป็นส่วนหนึ่งของการขยายรูปแบบเป้าหมาย เช่น การเรียก 2 รายการต่อไปนี้ข้ามเป้าหมายที่ใช้ร่วมกันไม่ได้ ซึ่งพบในการขยายรูปแบบเป้าหมาย
$ bazel build --platforms=//:myplatform //...
$ bazel build --platforms=//:myplatform //:all
ระบบจะข้ามการทดสอบที่เข้ากันไม่ได้ใน test_suite
ในทำนองเดียวกัน หากระบุ test_suite
ในบรรทัดคำสั่งด้วย --expand_test_suites
กล่าวคือ เป้าหมาย test_suite
ในบรรทัดคำสั่งจะทำงานเหมือนกับ :all
และ ...
การใช้ --noexpand_test_suites
จะป้องกันการขยายและทำให้เป้าหมาย test_suite
รายการกับการทดสอบที่เข้ากันไม่ได้เข้ากันไม่ได้ด้วยเช่นกัน
การระบุเป้าหมายที่ใช้ร่วมกันไม่ได้ในบรรทัดคำสั่งอย่างชัดเจนจะทำให้มีข้อความแสดงข้อผิดพลาดและบิลด์ล้มเหลว
$ bazel build --platforms=//:myplatform //:target_incompatible_with_myplatform
...
ERROR: Target //:target_incompatible_with_myplatform is incompatible and cannot be built, but was explicitly requested.
...
FAILED: Build did NOT complete successfully
ระบบจะข้ามเป้าหมายที่อาจไม่เหมาะสมซึ่งใช้ร่วมกันไม่ได้ไปโดยอัตโนมัติ หากเปิดใช้ --skip_incompatible_explicit_targets
มีข้อจำกัดที่ชัดเจนมากขึ้น
หากต้องการความยืดหยุ่นมากขึ้นในการแสดงข้อจํากัด ให้ใช้@platforms//:incompatible
constraint_value
ที่ไม่มีแพลตฟอร์มที่ต้องการ
ใช้ select()
ร่วมกับ @platforms//:incompatible
เพื่อแสดงข้อจํากัดที่ซับซ้อนยิ่งขึ้น เช่น ใช้เพื่อติดตั้งใช้งานตรรกะ "หรือ" พื้นฐาน รายการต่อไปนี้ระบุว่าไลบรารีใช้งานร่วมกับ macOS และ Linux ได้ แต่ไม่ใช่แพลตฟอร์มอื่น
cc_library(
name = "unixish_lib",
srcs = ["unixish_lib.cc"],
target_compatible_with = select({
"@platforms//os:osx": [],
"@platforms//os:linux": [],
"//conditions:default": ["@platforms//:incompatible"],
}),
)
ข้อความข้างต้นสามารถตีความได้ดังนี้
- เมื่อกำหนดเป้าหมาย macOS เป้าหมายจะไม่มีข้อจำกัด
- เมื่อกำหนดเป้าหมาย Linux เป้าหมายจะไม่มีข้อจำกัด
- มิฉะนั้น เป้าหมายจะมีข้อจํากัด
@platforms//:incompatible
เนื่องจาก@platforms//:incompatible
ไม่ได้เป็นส่วนหนึ่งของแพลตฟอร์มใดๆ ระบบจึงถือว่าเป้าหมายเข้ากันไม่ได้
หากต้องการให้ข้อจำกัดอ่านได้ง่ายขึ้น ให้ใช้ selects.with_or()
ของ skylib
คุณสามารถแสดงความเข้ากันได้แบบผกผันได้ในลักษณะเดียวกัน ตัวอย่างต่อไปนี้อธิบายไลบรารีที่เข้ากันได้กับทุกอย่าง ยกเว้นสำหรับ ARM
cc_library(
name = "non_arm_lib",
srcs = ["non_arm_lib.cc"],
target_compatible_with = select({
"@platforms//cpu:arm": ["@platforms//:incompatible"],
"//conditions:default": [],
}),
)
การตรวจหาเป้าหมายที่ใช้ร่วมกันไม่ได้โดยใช้ bazel cquery
คุณสามารถใช้ IncompatiblePlatformProvider
ในรูปแบบเอาต์พุต Starlark ของ bazel cquery
เพื่อแยกแยะเป้าหมายที่เข้ากันไม่ได้ออกจากเป้าหมายที่เข้ากันได้
ใช้เพื่อกรองเป้าหมายที่ใช้ร่วมกันไม่ได้ออก ตัวอย่างด้านล่างจะพิมพ์เฉพาะป้ายกำกับสำหรับเป้าหมายที่เข้ากันได้เท่านั้น เป้าหมายที่เข้ากันไม่ได้ จะไม่ถูกพิมพ์
$ cat example.cquery
def format(target):
if "IncompatiblePlatformProvider" not in providers(target):
return target.label
return ""
$ bazel cquery //... --output=starlark --starlark:file=example.cquery
ปัญหาที่ทราบ
เป้าหมายที่ใช้ร่วมกันไม่ได้จะเพิกเฉยต่อข้อจํากัดระดับการเข้าถึง