Bazel สร้างและทดสอบโค้ดบนฮาร์ดแวร์ ระบบปฏิบัติการ และการกำหนดค่าระบบต่างๆ ได้โดยใช้เครื่องมือสร้างเวอร์ชันต่างๆ มากมาย เช่น Linkers และคอมไพเลอร์ 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
สร้างค่าใหม่สําหรับมิติข้อมูลที่ระบุ ร่วมกันแล้ว 2 คำสั่งนี้จะกําหนด 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 มาพร้อมกับคําจํากัดความแพลตฟอร์มพิเศษต่อไปนี้
@local_config_platform//:host
ค่านี้คือค่าแพลตฟอร์มโฮสต์ที่ตรวจพบโดยอัตโนมัติ ซึ่งแสดงถึงแพลตฟอร์มที่ตรวจพบโดยอัตโนมัติสำหรับระบบที่ Bazel ทำงานอยู่
การระบุแพลตฟอร์มสําหรับบิลด์
คุณสามารถระบุโฮสต์และแพลตฟอร์มเป้าหมายสำหรับบิลด์ได้โดยใช้ Flag บรรทัดคำสั่งต่อไปนี้
--host_platform
- ค่าเริ่มต้นคือ@bazel_tools//platforms:host_platform
--platforms
- ค่าเริ่มต้นคือ@bazel_tools//platforms:target_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 บิตเท่านั้น และใช้งานร่วมกับระบบอื่นๆ ไม่ได้ ความไม่เข้ากันนี้เป็นแบบทรานซิทีฟ ระบบจะถือว่าเป้าหมายใดก็ตามที่อาศัยเป้าหมายที่เข้ากันไม่ได้แบบอ้อมนั้นเข้ากันไม่ได้
เมื่อใดที่เป้าหมายจะถูกข้าม
ระบบจะข้ามเป้าหมายเมื่อพิจารณาว่าใช้งานร่วมกันไม่ได้และรวมไว้ในบิลด์โดยเป็นส่วนหนึ่งของการขยายรูปแบบเป้าหมาย ตัวอย่างเช่น การเรียกใช้ 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
ข้อจำกัดที่สื่ออารมณ์ได้มากขึ้น
หากต้องการแสดงความจำกัดให้มีความยืดหยุ่นมากขึ้น ให้ใช้
@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
ปัญหาที่ทราบ
เป้าหมายที่ใช้ร่วมกันไม่ได้จะไม่สนใจข้อจํากัดการมองเห็น