Tutorial ini menggunakan contoh skenario untuk menjelaskan cara mengonfigurasi toolchain C++ untuk sebuah project.
Yang akan Anda pelajari
Dalam tutorial ini, Anda akan mempelajari cara:
- Menyiapkan lingkungan build
- Menggunakan
--toolchain_resolution_debug
untuk men-debug resolusi toolchain - Mengonfigurasi toolchain C++
- Buat aturan Starlark yang memberikan konfigurasi
tambahan untuk
cc_toolchain
sehingga Bazel dapat mem-build aplikasi denganclang
- Bangun biner C++ dengan menjalankan
bazel build //main:hello-world
di mesin Linux - Kompilasi silang biner untuk Android dengan menjalankan
bazel build //main:hello-world --platforms=//:android_x86_64
Sebelum memulai
Tutorial ini mengasumsikan bahwa Anda menggunakan Linux dan telah berhasil membangun aplikasi C++ serta menginstal alat dan library yang sesuai.
Tutorial ini menggunakan clang version 16
, yang dapat diinstal di sistem Anda.
Menyiapkan lingkungan build
Siapkan lingkungan build Anda sebagai berikut:
Jika Anda belum melakukannya, download dan instal Bazel 7.0.2 atau yang lebih baru.
Tambahkan file
WORKSPACE
kosong di folder root.Tambahkan target
cc_binary
berikut ke filemain/BUILD
:load("@rules_cc//cc:defs.bzl", "cc_binary") cc_binary( name = "hello-world", srcs = ["hello-world.cc"], )
Karena Bazel menggunakan banyak alat internal yang ditulis dalam C++ selama proses build, seperti
process-wrapper
, toolchain C++ default yang sudah ada akan ditentukan untuk platform host. Dengan begitu, alat internal ini dapat dibuat menggunakan toolchain yang dibuat dalam tutorial ini. Oleh karena itu, targetcc_binary
juga dibuat dengan toolchain default.Jalankan build dengan perintah berikut:
bazel build //main:hello-world
Build akan berhasil tanpa toolchain apa pun yang terdaftar di
WORKSPACE
.Untuk mengetahui apa yang ada di balik layar, jalankan:
bazel build //main:hello-world --toolchain_resolution_debug='@bazel_tools//tools/cpp:toolchain_type' INFO: ToolchainResolution: Target platform @@local_config_platform//:host: Selected execution platform @@local_config_platform//:host, type @@bazel_tools//tools/cpp:toolchain_type -> toolchain @@bazel_tools~cc_configure_extension~local_config_cc//:cc-compiler-k8
Tanpa menentukan
--platforms
, Bazel akan mem-build target untuk@local_config_platform//:host
menggunakan@bazel_tools//cc_configure_extension/local_config_cc//:cc-compiler-k8
Mengonfigurasi toolchain C++
Untuk mengonfigurasi toolchain C++, build aplikasi berulang kali dan hilangkan setiap error satu per satu seperti dijelaskan seperti berikut.
Kode ini juga mengasumsikan clang version 9.0.1
, meskipun detailnya hanya akan berubah
sedikit berubah di antara versi clang yang berbeda.
Tambahkan
toolchain/BUILD
denganfilegroup(name = "empty") cc_toolchain( name = "linux_x86_64_toolchain", toolchain_identifier = "linux_x86_64-toolchain", toolchain_config = ":linux_x86_64_toolchain_config", all_files = ":empty", compiler_files = ":empty", dwp_files = ":empty", linker_files = ":empty", objcopy_files = ":empty", strip_files = ":empty", supports_param_files = 0, ) toolchain( name = "cc_toolchain_for_linux_x86_64", toolchain = ":linux_x86_64_toolchain", toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", exec_compatible_with = [ "@platforms//cpu:x86_64", "@platforms//os:linux", ], target_compatible_with = [ "@platforms//cpu:x86_64", "@platforms//os:linux", ], )
Kemudian daftarkan toolchain dengan
WORKSPACE
menggunakanregister_toolchains( "//toolchain:cc_toolchain_for_linux_x86_64" )
Langkah ini menentukan
cc_toolchain
dan mengikatnya ke targettoolchain
untuk konfigurasi host.Jalankan kembali build. Karena paket
toolchain
belum menentukan targetlinux_x86_64_toolchain_config
, Bazel akan menampilkan error berikut:ERROR: toolchain/BUILD:4:13: in toolchain_config attribute of cc_toolchain rule //toolchain:linux_x86_64_toolchain: rule '//toolchain:linux_x86_64_toolchain_config' does not exist.
Dalam file
toolchain/BUILD
, tentukan grup file kosong sebagai berikut:package(default_visibility = ["//visibility:public"]) filegroup(name = "linux_x86_64_toolchain_config")
Jalankan kembali build. Bazel memunculkan error berikut:
'//toolchain:linux_x86_64_toolchain_config' does not have mandatory providers: 'CcToolchainConfigInfo'.
CcToolchainConfigInfo
adalah penyedia yang Anda gunakan untuk mengonfigurasi toolchain C++. Untuk memperbaiki error ini, buat aturan Starlark yang menyediakanCcToolchainConfigInfo
ke Bazel dengan membuat filetoolchain/cc_toolchain_config.bzl
berisi konten berikut:def _impl(ctx): return cc_common.create_cc_toolchain_config_info( ctx = ctx, toolchain_identifier = "k8-toolchain", host_system_name = "local", target_system_name = "local", target_cpu = "k8", target_libc = "unknown", compiler = "clang", abi_version = "unknown", abi_libc_version = "unknown", ) cc_toolchain_config = rule( implementation = _impl, attrs = {}, provides = [CcToolchainConfigInfo], )
cc_common.create_cc_toolchain_config_info()
membuat penyedia yang diperlukanCcToolchainConfigInfo
. Untuk menggunakan aturancc_toolchain_config
, tambahkan pernyataan pemuatan ketoolchain/BUILD
tepat di bawah pernyataan paket:load(":cc_toolchain_config.bzl", "cc_toolchain_config")
Lalu, ganti grup file "linux_x86_64_ toolchain_config" dengan deklarasi aturan
cc_toolchain_config
:cc_toolchain_config(name = "linux_x86_64_toolchain_config")
Jalankan kembali build. Bazel memunculkan error berikut:
.../BUILD:1:1: C++ compilation of rule '//:hello-world' failed (Exit 1) src/main/tools/linux-sandbox-pid1.cc:421: "execvp(toolchain/DUMMY_GCC_TOOL, 0x11f20e0)": No such file or directory Target //:hello-world failed to build`
Pada tahap ini, Bazel memiliki cukup informasi untuk mencoba membuat kode, tetapi masih tidak tahu alat apa yang harus digunakan untuk menyelesaikan tindakan build yang diperlukan. Anda akan mengubah implementasi aturan Starlark untuk memberi tahu Bazel alat apa yang akan digunakan. Untuk itu, Anda memerlukan konstruktor tool_path() dari
@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl
:# toolchain/cc_toolchain_config.bzl: # NEW load("@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl", "tool_path") def _impl(ctx): tool_paths = [ # NEW tool_path( name = "gcc", path = "/usr/bin/clang", ), tool_path( name = "ld", path = "/usr/bin/ld", ), tool_path( name = "ar", path = "/usr/bin/ar", ), tool_path( name = "cpp", path = "/bin/false", ), tool_path( name = "gcov", path = "/bin/false", ), tool_path( name = "nm", path = "/bin/false", ), tool_path( name = "objdump", path = "/bin/false", ), tool_path( name = "strip", path = "/bin/false", ), ] return cc_common.create_cc_toolchain_config_info( ctx = ctx, toolchain_identifier = "local", host_system_name = "local", target_system_name = "local", target_cpu = "k8", target_libc = "unknown", compiler = "clang", abi_version = "unknown", abi_libc_version = "unknown", tool_paths = tool_paths, # NEW )
Pastikan
/usr/bin/clang
dan/usr/bin/ld
adalah jalur yang benar untuk sistem Anda.Jalankan kembali build. Bazel memunculkan error berikut:
ERROR: main/BUILD:3:10: Compiling main/hello-world.cc failed: absolute path inclusion(s) found in rule '//main:hello-world': the source file 'main/hello-world.cc' includes the following non-builtin files with absolute paths (if these are builtin files, make sure these paths are in your toolchain): '/usr/include/c++/13/ctime' '/usr/include/x86_64-linux-gnu/c++/13/bits/c++config.h' '/usr/include/x86_64-linux-gnu/c++/13/bits/os_defines.h' ...
Bazel perlu mengetahui di mana harus mencari {i>header<i} yang disertakan. Ada beberapa cara untuk mengatasi hal ini, seperti menggunakan atribut
includes
daricc_binary
, tetapi di sini hal ini diatasi pada level toolchain dengan parametercxx_builtin_include_directories
cc_common.create_cc_toolchain_config_info
. Perlu diketahui bahwa jika Anda menggunakan versiclang
yang berbeda, jalur penyertaan akan berbeda. Jalur ini mungkin juga berbeda tergantung pada distribusinya.Ubah nilai yang ditampilkan di
toolchain/cc_toolchain_config.bzl
agar terlihat seperti ini:return cc_common.create_cc_toolchain_config_info( ctx = ctx, cxx_builtin_include_directories = [ # NEW "/usr/lib/llvm-16/lib/clang/16/include", "/usr/include", ], toolchain_identifier = "local", host_system_name = "local", target_system_name = "local", target_cpu = "k8", target_libc = "unknown", compiler = "clang", abi_version = "unknown", abi_libc_version = "unknown", tool_paths = tool_paths, )
Jalankan kembali perintah build, Anda akan melihat error seperti:
/usr/bin/ld: bazel-out/k8-fastbuild/bin/main/_objs/hello-world/hello-world.o: in function `print_localtime()': hello-world.cc:(.text+0x68): undefined reference to `std::cout'
Alasannya adalah karena linker tidak memiliki library standar C++ dan tidak dapat menemukan simbolnya. Ada banyak cara untuk mengatasi hal ini, seperti menggunakan atribut
linkopts
daricc_binary
. Masalah ini diatasi dengan memastikan bahwa target apa pun yang menggunakan toolchain tidak harus menentukan flag ini.Salin kode berikut ke
toolchain/cc_toolchain_config.bzl
:# NEW load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES") # NEW load( "@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl", "feature", # NEW "flag_group", # NEW "flag_set", # NEW "tool_path", ) all_link_actions = [ # NEW ACTION_NAMES.cpp_link_executable, ACTION_NAMES.cpp_link_dynamic_library, ACTION_NAMES.cpp_link_nodeps_dynamic_library, ] def _impl(ctx): tool_paths = [ tool_path( name = "gcc", path = "/usr/bin/clang", ), tool_path( name = "ld", path = "/usr/bin/ld", ), tool_path( name = "ar", path = "/bin/false", ), tool_path( name = "cpp", path = "/bin/false", ), tool_path( name = "gcov", path = "/bin/false", ), tool_path( name = "nm", path = "/bin/false", ), tool_path( name = "objdump", path = "/bin/false", ), tool_path( name = "strip", path = "/bin/false", ), ] features = [ # NEW feature( name = "default_linker_flags", enabled = True, flag_sets = [ flag_set( actions = all_link_actions, flag_groups = ([ flag_group( flags = [ "-lstdc++", ], ), ]), ), ], ), ] return cc_common.create_cc_toolchain_config_info( ctx = ctx, features = features, # NEW cxx_builtin_include_directories = [ "/usr/lib/llvm-9/lib/clang/9.0.1/include", "/usr/include", ], toolchain_identifier = "local", host_system_name = "local", target_system_name = "local", target_cpu = "k8", target_libc = "unknown", compiler = "clang", abi_version = "unknown", abi_libc_version = "unknown", tool_paths = tool_paths, ) cc_toolchain_config = rule( implementation = _impl, attrs = {}, provides = [CcToolchainConfigInfo], )
Menjalankan
bazel build //main:hello-world
, pada akhirnya akan berhasil membuat biner untuk host.Di
toolchain/BUILD
, salin targetcc_toolchain_config
,cc_toolchain
, dantoolchain
, lalu gantilinux_x86_64
denganandroid_x86_64
di nama target.Di
WORKSPACE
, daftarkan toolchain untuk Androidregister_toolchains( "//toolchain:cc_toolchain_for_linux_x86_64", "//toolchain:cc_toolchain_for_android_x86_64" )
Jalankan
bazel build //main:hello-world --android_platforms=//toolchain:android_x86_64
untuk mem-build biner untuk Android.
Dalam praktiknya, Linux dan Android harus memiliki konfigurasi toolchain C++ yang berbeda. Anda dapat mengubah cc_toolchain_config
yang ada untuk perbedaan tersebut atau membuat aturan terpisah (yaitu penyedia CcToolchainConfigInfo
) untuk platform terpisah.
Tinjau tugas Anda
Dalam tutorial ini, Anda telah mempelajari cara mengonfigurasi toolchain C++ dasar, tetapi toolchain lebih andal daripada contoh sederhana ini.
Hal-hal yang bisa dipelajari adalah:
- Anda perlu menentukan flag
platforms
yang cocok pada command line agar Bazel dapat me-resolve ke toolchain untuk nilai batasan yang sama di platform. Dokumentasi ini menyimpan informasi selengkapnya tentang flag konfigurasi khusus bahasa. - Anda harus memberi tahu toolchain pada lokasi alat tersebut. Dalam tutorial ini,
ada versi yang disederhanakan tempat Anda mengakses alat dari sistem. Jika
tertarik dengan pendekatan yang lebih mandiri, Anda dapat membaca tentang
ruang kerja. Alat Anda dapat berasal dari
ruang kerja yang berbeda dan Anda harus menyediakan filenya
untuk
cc_toolchain
dengan dependensi target pada atribut, seperticompiler_files
.tool_paths
juga perlu diubah. - Anda dapat membuat fitur untuk menyesuaikan tanda mana yang harus diteruskan ke berbagai tindakan, baik itu penautan maupun jenis tindakan lainnya.
Bacaan lebih lanjut
Untuk mengetahui detail selengkapnya, lihat Konfigurasi toolchain C++