Pengantar
Bazel dapat mem-build dan menguji kode di berbagai hardware, sistem operasi, dan konfigurasi sistem. Hal ini dapat melibatkan berbagai versi alat build seperti linker dan compiler. Untuk membantu mengelola kompleksitas ini, Bazel memiliki konsep batasan dan platform.
Batasan adalah properti pembeda dari mesin build atau produksi. Batasan umum adalah arsitektur CPU, ada atau tidak adanya GPU, atau versi compiler yang diinstal secara lokal. Namun, batasan dapat berupa apa pun yang membedakan mesin secara bermakna saat mengatur pekerjaan build.
Platform adalah kumpulan batasan yang menentukan mesin lengkap. Bazel menggunakan konsep ini untuk memungkinkan developer memilih mesin yang ingin mereka build, mesin yang harus menjalankan tindakan kompilasi dan pengujian, serta toolchain yang harus digunakan untuk mengompilasi tindakan build.
Developer juga dapat menggunakan batasan untuk memilih
properti atau dependensi kustom pada aturan build mereka. Misalnya: "gunakan
src_arm.cc saat build menargetkan mesin Arm".
Jenis platform
Bazel mengenali tiga peran yang dapat dimainkan platform:
- Host - Platform tempat Bazel berjalan.
- Eksekusi - Platform yang menjalankan tindakan kompilasi untuk menghasilkan output build.
- Target - Platform tempat kode yang di-build harus berjalan.
Build umumnya memiliki tiga jenis hubungan dengan platform:
Build platform tunggal - Platform host, eksekusi, dan target sama. Misalnya, membangun di mesin developer tanpa eksekusi jarak jauh, lalu menjalankan biner yang di-build di mesin yang sama.
Build kompilasi silang - Platform host dan eksekusi sama, tetapi platform target berbeda. Misalnya, membangun aplikasi iOS di Macbook Pro tanpa eksekusi jarak jauh.
Build multi-platform - Platform host, eksekusi, dan target semuanya berbeda. Misalnya, membangun aplikasi iOS di Macbook Pro dan menggunakan mesin Linux jarak jauh untuk mengompilasi tindakan C++ yang tidak memerlukan Xcode.
Menentukan platform
Cara paling umum bagi developer untuk menggunakan platform adalah menentukan mesin target yang diinginkan dengan tanda --platforms:
$ bazel build //:my_linux_app --platforms=//myplatforms:linux_x86
Organisasi umumnya mempertahankan definisi platform mereka sendiri karena penyiapan mesin build berbeda-beda antar-organisasi.
Jika --platforms tidak ditetapkan, nilai defaultnya adalah @platforms//host. Hal ini secara khusus ditentukan untuk mendeteksi properti OS dan CPU mesin host secara otomatis sehingga build menargetkan mesin yang sama dengan Bazel. Aturan build dapat
memilih properti ini dengan
@platforms/os dan
@platforms/cpu
batasan.
Platform dan batasan yang umumnya berguna
Untuk menjaga konsistensi ekosistem, tim Bazel mempertahankan repositori dengan definisi batasan untuk arsitektur CPU dan sistem operasi yang paling populer. Semua ini ditentukan di https://github.com/bazelbuild/platforms.
Bazel dilengkapi dengan definisi platform khusus berikut: @platforms//host (diberi alias sebagai @bazel_tools//tools:host_platform). Hal ini akan mendeteksi properti OS dan CPU mesin tempat Bazel berjalan secara otomatis.
Menentukan batasan
Batasan dimodelkan dengan aturan build constraint_setting dan
constraint_value.
constraint_setting mendeklarasikan jenis properti. Contoh:
constraint_setting(name = "cpu")
constraint_value mendeklarasikan kemungkinan nilai untuk properti tersebut:
constraint_value(
name = "x86",
constraint_setting = ":cpu"
)
Hal ini dapat direferensikan sebagai label saat menentukan platform atau menyesuaikan aturan build di platform tersebut. Jika contoh di atas ditentukan di cpus/BUILD, Anda dapat mereferensikan
batasan x86 sebagai //cpus:x86.
Jika visibilitas memungkinkan, Anda dapat memperluas constraint_setting yang ada dengan menentukan nilai Anda sendiri untuk batasan tersebut.
Menentukan platform
Aturan build platform
menentukan platform sebagai kumpulan constraint_values:
platform(
name = "linux_x86",
constraint_values = [
"//oses:linux",
"//cpus:x86",
],
)
Hal ini memodelkan mesin yang harus memiliki batasan //oses:linux dan //cpus:x86.
Platform hanya dapat memiliki satu constraint_value untuk constraint_setting tertentu.
Artinya, misalnya, platform tidak dapat memiliki dua CPU kecuali jika Anda membuat jenis constraint_setting lain untuk memodelkan nilai kedua.
Melewati target yang tidak kompatibel
Saat membangun untuk platform target tertentu, sering kali diinginkan untuk melewati target yang tidak akan pernah berfungsi di platform tersebut. Misalnya, driver perangkat Windows Anda kemungkinan akan menghasilkan banyak error compiler saat membangun di mesin Linux dengan //.... Gunakan atribut
target_compatible_with
untuk memberi tahu Bazel batasan platform target yang dimiliki kode Anda.
Penggunaan atribut ini yang paling sederhana membatasi target ke satu platform.
Target tidak akan di-build untuk platform apa pun yang tidak memenuhi semua batasan. Contoh berikut membatasi win_driver_lib.cc ke Windows 64-bit.
cc_library(
name = "win_driver_lib",
srcs = ["win_driver_lib.cc"],
target_compatible_with = [
"@platforms//cpu:x86_64",
"@platforms//os:windows",
],
)
:win_driver_lib hanya kompatibel untuk membangun dengan Windows 64-bit dan tidak kompatibel dengan yang lainnya. Inkompatibilitas bersifat transitif. Target apa pun yang secara transitif bergantung pada target yang tidak kompatibel juga dianggap tidak kompatibel.
Kapan target dilewati?
Target dilewati jika dianggap tidak kompatibel dan disertakan dalam build sebagai bagian dari perluasan pola target. Misalnya, dua pemanggilan berikut akan melewati target yang tidak kompatibel yang ditemukan dalam perluasan pola target.
$ bazel build --platforms=//:myplatform //...
$ bazel build --platforms=//:myplatform //:all
Pengujian yang tidak kompatibel dalam test_suite juga dilewati jika test_suite ditentukan di command line dengan
--expand_test_suites.
Dengan kata lain, target test_suite di command line berperilaku seperti :all dan .... Menggunakan --noexpand_test_suites akan mencegah perluasan dan menyebabkan
test_suite target dengan pengujian yang tidak kompatibel juga menjadi tidak kompatibel.
Menentukan target yang tidak kompatibel secara eksplisit di command line akan menghasilkan pesan error dan build yang gagal.
$ 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
Target eksplisit yang tidak kompatibel akan dilewati secara diam-diam jika --skip_incompatible_explicit_targets diaktifkan.
Batasan yang lebih ekspresif
Untuk lebih fleksibel dalam mengekspresikan batasan, gunakan yang tidak memenuhi platform.@platforms//:incompatibleconstraint_value
Gunakan select() bersama dengan
@platforms//:incompatible untuk mengekspresikan batasan yang lebih rumit. Misalnya, gunakan untuk menerapkan logika OR dasar. Berikut ini menandai library yang kompatibel dengan macOS dan Linux, tetapi tidak dengan platform lainnya.
cc_library(
name = "unixish_lib",
srcs = ["unixish_lib.cc"],
target_compatible_with = select({
"@platforms//os:osx": [],
"@platforms//os:linux": [],
"//conditions:default": ["@platforms//:incompatible"],
}),
)
Penjelasan di atas dapat diartikan sebagai berikut:
- Saat menargetkan macOS, target tidak memiliki batasan.
- Saat menargetkan Linux, target tidak memiliki batasan.
- Jika tidak, target akan memiliki batasan
@platforms//:incompatible. Karena@platforms//:incompatiblebukan bagian dari platform mana pun, target dianggap tidak kompatibel.
Untuk membuat batasan Anda lebih mudah dibaca, gunakan
skylib's
selects.with_or().
Anda dapat mengekspresikan kompatibilitas terbalik dengan cara yang sama. Contoh berikut menjelaskan library yang kompatibel dengan semuanya kecuali ARM.
cc_library(
name = "non_arm_lib",
srcs = ["non_arm_lib.cc"],
target_compatible_with = select({
"@platforms//cpu:arm": ["@platforms//:incompatible"],
"//conditions:default": [],
}),
)
Mendeteksi target yang tidak kompatibel menggunakan bazel cquery
Anda dapat menggunakan
IncompatiblePlatformProvider
dalam bazel cquery's format output Starlark untuk membedakan target yang tidak kompatibel dari target yang kompatibel.
Hal ini dapat digunakan untuk memfilter target yang tidak kompatibel. Contoh di bawah hanya akan mencetak label untuk target yang kompatibel. Target yang tidak kompatibel tidak akan dicetak.
$ cat example.cquery
def format(target):
if "IncompatiblePlatformProvider" not in providers(target):
return target.label
return ""
$ bazel cquery //... --output=starlark --starlark:file=example.cquery
Masalah Umum
Target yang tidak kompatibel mengabaikan visibilitas batasan.