Tutorial ini menggunakan skenario contoh untuk menjelaskan cara mengonfigurasi toolchain C++ untuk project.
Yang akan Anda pelajari
Dalam tutorial ini, Anda akan mempelajari cara:
- Menyiapkan lingkungan build
- Menggunakan
--toolchain_resolution_debuguntuk men-debug resolusi toolchain - Mengonfigurasi toolchain C++
- Membuat aturan Starlark yang memberikan konfigurasi tambahan untuk
cc_toolchainsehingga Bazel dapat mem-build aplikasi denganclang - Mem-build biner C++ dengan menjalankan
bazel build //main:hello-worlddi mesin Linux - Melakukan 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 mem-build aplikasi C++ serta menginstal alat dan library yang sesuai. Tutorial ini menggunakan clang version 19, yang dapat Anda instal di sistem.
Menyiapkan lingkungan build
Siapkan lingkungan build Anda sebagai berikut:
Jika belum melakukannya, download dan instal Bazel 7.0.2 atau yang lebih baru.
Tambahkan file
MODULE.bazelkosong di folder root.Tambahkan target
cc_binaryberikut ke filemain/BUILD:cc_binary( name = "hello-world", srcs = ["hello-world.cc"], )Karena Bazel menggunakan banyak alat internal yang ditulis dalam C++ selama build, seperti
process-wrapper, toolchain C++ default yang sudah ada ditentukan untuk platform host. Hal ini memungkinkan alat internal ini di-build menggunakan toolchain yang dibuat dalam tutorial ini. Oleh karena itu, targetcc_binaryjuga di-build dengan toolchain default.Jalankan build dengan perintah berikut:
bazel build //main:hello-worldBuild berhasil tanpa toolchain yang terdaftar di
MODULE.bazel.Untuk melihat lebih lanjut 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 @@platforms//host:host: Selected execution platform @@platforms//host:host, type @@bazel_tools//tools/cpp:toolchain_type -> toolchain @@bazel_tools+cc_configure_extension+local_config_cc//:cc-compiler-k8Tanpa menentukan
--platforms, Bazel mem-build target untuk@platforms//hostmenggunakan@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 yang dijelaskan berikut.
Tutorial ini juga mengasumsikan clang version 9.0.1, meskipun detailnya hanya akan sedikit berubah antara berbagai versi clang.
Tambahkan
toolchain/BUILDdenganfilegroup(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, tambahkan dependensi yang sesuai dan daftarkan toolchain dengan
MODULE.bazeldenganbazel_dep(name = "platforms", version = "0.0.10") register_toolchains( "//toolchain:cc_toolchain_for_linux_x86_64" )Langkah ini menentukan
cc_toolchaindan mengikatnya ke targettoolchainuntuk konfigurasi host.Jalankan build lagi. Karena paket
toolchainbelum menentukan targetlinux_x86_64_toolchain_config, Bazel 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.Di file
toolchain/BUILD, tentukan filegroup kosong sebagai berikut:package(default_visibility = ["//visibility:public"]) filegroup(name = "linux_x86_64_toolchain_config")Jalankan build lagi. Bazel menampilkan error berikut:
'//toolchain:linux_x86_64_toolchain_config' does not have mandatory providers: 'CcToolchainConfigInfo'.CcToolchainConfigInfoadalah penyedia yang Anda gunakan untuk mengonfigurasi toolchain C++. Untuk memperbaiki error ini, buat aturan Starlark yang menyediakanCcToolchainConfigInfoke Bazel dengan membuat filetoolchain/cc_toolchain_config.bzldengan 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 load ketoolchain/BUILDtepat di bawah pernyataan paket:load(":cc_toolchain_config.bzl", "cc_toolchain_config")Kemudian, ganti filegroup "linux_x86_64_toolchain_config" dengan deklarasi aturan
cc_toolchain_config:cc_toolchain_config(name = "linux_x86_64_toolchain_config")Jalankan build lagi. Bazel menampilkan 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 informasi yang cukup untuk mencoba mem-build kode, tetapi Bazel masih belum mengetahui alat yang akan digunakan untuk menyelesaikan tindakan build yang diperlukan. Anda akan mengubah implementasi aturan Starlark untuk memberi tahu Bazel alat 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", # Compiler is referenced by the name "gcc" for historic reasons. 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/clangdan/usr/bin/ldadalah jalur yang benar untuk sistem Anda. Perhatikan bahwa kompilator dirujuk berdasarkan nama "gcc" karena alasan historis.Jalankan build lagi. Bazel menampilkan 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 tempat untuk menelusuri header yang disertakan. Ada beberapa cara untuk mengatasi hal ini, seperti menggunakan atribut
includesdaricc_binary, tetapi di sini hal ini diselesaikan di tingkat toolchain dengancxx_builtin_include_directoriesparameter daricc_common.create_cc_toolchain_config_info. Perhatikan bahwa jika Anda menggunakanclangversi lain, jalur sertakan akan berbeda. Jalur ini juga dapat berbeda bergantung pada distribusinya.Ubah nilai yang ditampilkan di
toolchain/cc_toolchain_config.bzlagar terlihat seperti ini:return cc_common.create_cc_toolchain_config_info( ctx = ctx, cxx_builtin_include_directories = [ # NEW "/usr/lib/llvm-19/lib/clang/19/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
linkoptsdaricc_binary. Di sini, masalah ini diselesaikan dengan memastikan bahwa target apa pun yang menggunakan toolchain tidak perlu 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", # Compiler is referenced by the name "gcc" for historic reasons. 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-19/lib/clang/19/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], )Perhatikan bahwa kode ini menggunakan library GNU C++ libstdc++. Jika Anda ingin menggunakan library LLVM C++, gunakan "-lc++" dan bukan "-lstdc++".
Dengan menjalankan
bazel build //main:hello-world, biner akhirnya akan berhasil di-build untuk host.Di
toolchain/BUILD, salin targetcc_toolchain_config,cc_toolchain, dantoolchain, lalu gantilinux_x86_64denganandroid_x86_64dalam nama target.Di
MODULE.bazel, 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_64untuk 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 atau membuat aturan terpisah (yaitu penyedia CcToolchainConfigInfo) untuk platform terpisah.
Meninjau tugas Anda
Dalam tutorial ini, Anda mempelajari cara mengonfigurasi toolchain C++ dasar, tetapi toolchain lebih canggih daripada contoh ini.
Poin-poin penting yang perlu diperhatikan adalah:
- Anda harus menentukan flag
platformsyang cocok di command line agar Bazel dapat menyelesaikan toolchain untuk nilai batasan yang sama di platform. Dokumentasi ini berisi selengkapnya tentang informasi tentang konfigurasi khusus bahasa flag konfigurasi. - Anda harus memberi tahu toolchain tempat alat berada. Dalam tutorial ini, ada versi yang disederhanakan tempat Anda mengakses alat dari sistem. Jika
Anda tertarik dengan pendekatan yang lebih mandiri, Anda dapat membaca tentang
dependensi eksternal. Alat Anda dapat berasal dari modul yang berbeda dan Anda harus menyediakan file-nya untuk
cc_toolchaindengan dependensi target pada atribut, seperticompiler_files.tool_pathsjuga perlu diubah. - Anda dapat membuat fitur untuk menyesuaikan flag mana yang harus diteruskan ke tindakan yang berbeda, baik itu menghubungkan atau jenis tindakan lainnya.
Bacaan lebih lanjut
Untuk mengetahui detail selengkapnya, lihat Konfigurasi toolchain C++