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 tidaknya GPU, atau versi compiler yang diinstal secara lokal. Namun, batasan dapat berupa apa pun yang membedakan mesin secara signifikan saat mengatur pekerjaan build.
Platform adalah kumpulan batasan yang menentukan mesin lengkap. Bazel menggunakan konsep ini untuk memungkinkan developer memilih mesin yang ingin mereka bangun, mesin yang harus menjalankan tindakan kompilasi dan pengujian, serta tindakan build toolchain yang harus dikompilasi.
Developer juga dapat menggunakan batasan untuk memilih
properti kustom atau dependensi 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 dijalankan.
- Eksekusi - Platform yang menjalankan tindakan kompilasi untuk menghasilkan output build.
- Target - Platform tempat kode yang sedang dibuat harus dijalankan.
Build umumnya memiliki tiga jenis hubungan dengan platform:
Build platform tunggal - Platform host, eksekusi, dan target sama. Misalnya, membangun di komputer developer tanpa eksekusi jarak jauh, lalu menjalankan biner yang dibangun di komputer 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 multiplatform - 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 dengan menentukan target
mesin yang diinginkan dengan flag --platforms:
$ bazel build //:my_linux_app --platforms=//myplatforms:linux_x86
Organisasi umumnya mempertahankan definisi platform mereka sendiri karena penyiapan mesin build bervariasi di antara organisasi.
Jika --platforms tidak disetel, nilai defaultnya adalah @platforms//host. Ini
didefinisikan secara khusus untuk mendeteksi otomatis properti OS dan CPU mesin host sehingga
build menargetkan mesin yang sama dengan yang menjalankan Bazel. Aturan build dapat
memilih properti ini dengan batasan
@platforms/os dan
@platforms/cpu.
Batasan dan platform yang umumnya berguna
Untuk menjaga konsistensi ekosistem, tim Bazel mengelola 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 (dikenal juga sebagai @bazel_tools//tools:host_platform). Platform ini
mendeteksi otomatis properti OS dan CPU mesin tempat Bazel berjalan.
Menentukan batasan
Batasan dimodelkan dengan aturan pembuatan 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"
)
Label ini dapat dirujuk sebagai label saat menentukan platform atau menyesuaikan aturan build di platform tersebut. Jika contoh di atas ditentukan dalam cpus/BUILD, Anda dapat merujuk batasan x86 sebagai //cpus:x86.
Jika visibilitas memungkinkan, Anda dapat memperluas constraint_setting yang ada dengan
menentukan nilai Anda sendiri untuknya.
Menentukan platform
Aturan build platform
menentukan platform sebagai kumpulan constraint_value:
platform(
name = "linux_x86",
constraint_values = [
"//oses:linux",
"//cpus:x86",
],
)
Model 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 mem-build untuk platform target tertentu, sebaiknya lewati 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 dibangun untuk platform 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 dibangun dengan Windows 64-bit dan tidak kompatibel dengan yang lainnya. Inkompatibilitas bersifat transitif. Target apa pun yang bergantung secara transitif pada target yang tidak kompatibel 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 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
.... Penggunaan --noexpand_test_suites mencegah perluasan dan menyebabkan
target test_suite 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 fleksibilitas yang lebih besar dalam menyatakan batasan, gunakan
@platforms//:incompatible
constraint_value
yang tidak dipenuhi oleh platform mana pun.
Gunakan select() bersama dengan
@platforms//:incompatible untuk menyatakan batasan yang lebih rumit. Misalnya, gunakan untuk menerapkan logika OR dasar. Berikut menandai library yang kompatibel dengan macOS dan Linux, tetapi tidak dengan platform lain.
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 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 serupa. Contoh berikut menjelaskan library yang kompatibel dengan semua 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 format output Starlark bazel cquery untuk membedakan
target yang tidak kompatibel dari target yang kompatibel.
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 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 batasan visibilitas.