บทนำ
Bazel สามารถสร้างและทดสอบโค้ดในฮาร์ดแวร์ ระบบปฏิบัติการ และ การกำหนดค่าระบบต่างๆ ได้ ซึ่งอาจเกี่ยวข้องกับเครื่องมือบิลด์เวอร์ชันต่างๆ เช่น ลิงก์เกอร์และคอมไพเลอร์ Bazel มีแนวคิดเรื่องข้อจำกัดและแพลตฟอร์มเพื่อช่วยจัดการความซับซ้อนนี้
ข้อจำกัดคือคุณสมบัติที่โดดเด่นของเครื่องที่ใช้สร้างหรือเครื่องที่ใช้ในการผลิต ข้อจำกัดที่พบบ่อย ได้แก่ สถาปัตยกรรม CPU, มีหรือไม่มี GPU หรือ เวอร์ชันของคอมไพเลอร์ที่ติดตั้งในเครื่อง แต่ข้อจำกัดอาจเป็นอะไรก็ได้ที่ แยกความแตกต่างของเครื่องอย่างมีนัยสำคัญเมื่อจัดระเบียบงานบิลด์
แพลตฟอร์มคือชุดข้อจำกัดที่ระบุเครื่องที่สมบูรณ์ Bazel ใช้แนวคิดนี้เพื่อให้ผู้พัฒนาเลือกเครื่องที่ต้องการสร้าง เครื่องที่ควรเรียกใช้การดำเนินการคอมไพล์และทดสอบ และทูลเชนที่ควรใช้คอมไพล์การดำเนินการสร้าง
นอกจากนี้ นักพัฒนาซอฟต์แวร์ยังใช้ข้อจํากัดเพื่อเลือก
พร็อพเพอร์ตี้ที่กําหนดเองหรือการขึ้นต่อกันในกฎการสร้างได้ด้วย เช่น "ใช้
src_arm.cc เมื่อบิลด์กำหนดเป้าหมายเป็นเครื่อง Arm"
ประเภทแพลตฟอร์ม
Bazel จะรับรู้บทบาท 3 อย่างที่แพลตฟอร์มอาจมี ดังนี้
- โฮสต์ - แพลตฟอร์มที่ Bazel ทำงาน
- การดำเนินการ - แพลตฟอร์มที่เรียกใช้การดำเนินการคอมไพล์เพื่อสร้างเอาต์พุตบิลด์
- เป้าหมาย - แพลตฟอร์มที่โค้ดที่สร้างขึ้นควรทำงาน
โดยทั่วไปแล้ว บิลด์มีความสัมพันธ์กับแพลตฟอร์ม 3 ประเภท ได้แก่
การสร้างแพลตฟอร์มเดียว - แพลตฟอร์มโฮสต์ การดำเนินการ และเป้าหมายเหมือนกัน เช่น การสร้างในเครื่องของนักพัฒนาซอฟต์แวร์โดยไม่มีการดำเนินการจากระยะไกล แล้วเรียกใช้ไบนารีที่สร้างขึ้นในเครื่องเดียวกัน
บิลด์การคอมไพล์ข้าม - แพลตฟอร์มโฮสต์และแพลตฟอร์มการดำเนินการเหมือนกัน แต่แพลตฟอร์มเป้าหมายแตกต่างกัน เช่น การสร้างแอป iOS ใน Macbook Pro โดยไม่ต้องมีการดำเนินการจากระยะไกล
การสร้างหลายแพลตฟอร์ม - แพลตฟอร์มโฮสต์ การดำเนินการ และเป้าหมายทั้งหมด แตกต่างกัน เช่น การสร้างแอป iOS ใน Macbook Pro และใช้เครื่อง Linux ระยะไกลเพื่อคอมไพล์การดำเนินการ C++ ที่ไม่จำเป็นต้องใช้ Xcode
การระบุแพลตฟอร์ม
วิธีที่นักพัฒนาซอฟต์แวร์ใช้แพลตฟอร์มที่พบบ่อยที่สุดคือการระบุเครื่องเป้าหมายที่ต้องการด้วยแฟล็ก --platforms ดังนี้
$ bazel build //:my_linux_app --platforms=//myplatforms:linux_x86
โดยทั่วไปแล้ว องค์กรจะดูแลคำจำกัดความของแพลตฟอร์มของตนเองเนื่องจากการตั้งค่าเครื่องบิลด์จะแตกต่างกันไปในแต่ละองค์กร
เมื่อไม่ได้ตั้งค่า --platforms ไว้ ค่าเริ่มต้นจะเป็น @platforms//host ซึ่งกำหนดขึ้นเป็นพิเศษเพื่อตรวจหาพร็อพเพอร์ตี้ของระบบปฏิบัติการและ CPU ของเครื่องโฮสต์โดยอัตโนมัติ เพื่อให้บิลด์กำหนดเป้าหมายไปยังเครื่องเดียวกับที่ Bazel ทำงาน กฎการสร้างสามารถเลือกพร็อพเพอร์ตี้เหล่านี้ได้โดยมีข้อจำกัด
@platforms/os และ
@platforms/cpu
ข้อจำกัดและแพลตฟอร์มที่มีประโยชน์โดยทั่วไป
ทีม Bazel จะดูแลที่เก็บข้อมูลที่มีคำจำกัดความของข้อจำกัดสำหรับสถาปัตยกรรม CPU และระบบปฏิบัติการที่ได้รับความนิยมมากที่สุดเพื่อรักษาระบบนิเวศให้สอดคล้องกัน ซึ่งทั้งหมดนี้กำหนดไว้ใน https://github.com/bazelbuild/platforms
Bazel มาพร้อมกับคำจำกัดความแพลตฟอร์มพิเศษต่อไปนี้
@platforms//host (มีชื่อแทนเป็น @bazel_tools//tools:host_platform) ซึ่งจะ
ตรวจหาคุณสมบัติของระบบปฏิบัติการและ CPU ของเครื่องที่ Bazel ทำงานโดยอัตโนมัติ
การกำหนดข้อจำกัด
ข้อจำกัดจะได้รับการจำลองด้วยกฎ constraint_setting และ
constraint_value
constraint_setting ประกาศประเภทของพร็อพเพอร์ตี้ เช่น
constraint_setting(name = "cpu")
constraint_value ประกาศค่าที่เป็นไปได้สำหรับพร็อพเพอร์ตี้นั้น
constraint_value(
name = "x86",
constraint_setting = ":cpu"
)
คุณสามารถอ้างอิงสิ่งเหล่านี้เป็นป้ายกำกับเมื่อกำหนดแพลตฟอร์มหรือปรับแต่งกฎการบิลด์
ในแพลตฟอร์มเหล่านั้น หากกำหนดตัวอย่างข้างต้นใน cpus/BUILD คุณจะอ้างอิงข้อจำกัด x86 เป็น //cpus:x86 ได้
หากระดับการมองเห็นอนุญาต คุณสามารถขยายconstraint_settingที่มีอยู่ได้โดย
กำหนดค่าของคุณเอง
การกำหนดแพลตฟอร์ม
กฎการสร้าง platform
กำหนดแพลตฟอร์มเป็นคอลเล็กชันของ constraint_value ดังนี้
platform(
name = "linux_x86",
constraint_values = [
"//oses:linux",
"//cpus:x86",
],
)
ซึ่งเป็นโมเดลของเครื่องที่ต้องมีทั้งข้อจำกัด //oses:linux และ //cpus:x86
แพลตฟอร์มจะมี constraint_value ได้เพียงรายการเดียวสำหรับ constraint_setting ที่กำหนด
ซึ่งหมายความว่าแพลตฟอร์มจะมี CPU 2 ตัวไม่ได้ เว้นแต่คุณจะสร้างconstraint_settingประเภทอื่นเพื่อจำลองค่าที่ 2
ข้ามเป้าหมายที่ใช้ร่วมกันไม่ได้
เมื่อสร้างสำหรับแพลตฟอร์มเป้าหมายที่เฉพาะเจาะจง มักจะต้องการข้าม
เป้าหมายที่จะใช้งานบนแพลตฟอร์มนั้นไม่ได้ เช่น ไดรเวอร์ของอุปกรณ์ 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
ระบบจะข้ามเป้าหมายอย่างชัดแจ้งที่ไม่เข้ากันโดยไม่มีการแจ้งเตือนหากเปิดใช้
--skip_incompatible_explicit_targets
ข้อจำกัดที่สื่อความหมายได้มากขึ้น
หากต้องการความยืดหยุ่นในการแสดงข้อจำกัดมากขึ้น ให้ใช้
@platforms//:incompatible
constraint_value
ที่ไม่มีแพลตฟอร์มใดตรงตามข้อกำหนด
ใช้ select() ร่วมกับ
@platforms//:incompatible เพื่อแสดงข้อจำกัดที่ซับซ้อนมากขึ้น
เช่น ใช้เพื่อติดตั้งใช้งานตรรกะ OR พื้นฐาน เครื่องหมายต่อไปนี้ระบุไลบรารีที่ใช้ได้กับ 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ไม่ได้เป็นส่วนหนึ่งของแพลตฟอร์มใดๆ ระบบจึงถือว่าเป้าหมายไม่เข้ากัน
หากต้องการให้ข้อจำกัดอ่านง่ายขึ้น ให้ใช้
skylib ของ
selects.with_or()
คุณสามารถแสดงความเข้ากันได้แบบย้อนกลับในลักษณะเดียวกัน ตัวอย่างต่อไปนี้ อธิบายไลบรารีที่เข้ากันได้กับทุกอย่างยกเว้น 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
ในbazel cqueryรูปแบบเอาต์พุต Starlark เพื่อแยกความแตกต่าง
เป้าหมายที่เข้ากันไม่ได้ออกจากเป้าหมายที่เข้ากันได้
ซึ่งใช้กรองเป้าหมายที่ไม่รองรับออกได้ ตัวอย่างด้านล่างจะพิมพ์ป้ายกำกับสำหรับเป้าหมายที่เข้ากันได้เท่านั้น ระบบจะไม่พิมพ์เป้าหมายที่ใช้ร่วมกันไม่ได้
$ cat example.cquery
def format(target):
if "IncompatiblePlatformProvider" not in providers(target):
return target.label
return ""
$ bazel cquery //... --output=starlark --starlark:file=example.cquery
ปัญหาที่ทราบ
เป้าหมายที่ใช้ร่วมกันไม่ได้ไม่สนใจข้อจำกัดด้านการมองเห็น