Tutorial ini menggunakan contoh skenario untuk menjelaskan cara mengonfigurasi C++
toolchain untuk sebuah project. Contoh ini didasarkan pada
contoh project C++
yang mem-build tanpa error menggunakan clang
.
Yang akan Anda pelajari
Dalam tutorial ini, Anda akan mempelajari cara:
- Menyiapkan lingkungan build
- Mengonfigurasi toolchain C++
- Buat aturan Starlark yang memberikan konfigurasi tambahan
untuk
cc_toolchain
sehingga Bazel dapat mem-build aplikasi denganclang
- Konfirmasikan hasil yang diharapkan dengan menjalankan
bazel build --config=clang_config //main:hello-world
di komputer Linux - Membangun aplikasi C++
Sebelum memulai
Menyiapkan lingkungan build
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 9.0.1
, yang dapat Anda instal di sistem.
Siapkan lingkungan build Anda sebagai berikut:
Jika Anda belum melakukannya, download dan instal Bazel 0.23 atau yang lebih baru.
Download contoh project C++ dari GitHub dan tempatkan di direktori kosong di komputer lokal Anda.
Tambahkan target
cc_binary
berikut ke filemain/BUILD
:cc_binary( name = "hello-world", srcs = ["hello-world.cc"], )
Buat file
.bazelrc
di root direktori ruang kerja dengan konten berikut untuk memungkinkan penggunaan flag--config
:# Use our custom-configured c++ toolchain. build:clang_config --crosstool_top=//toolchain:clang_suite # Use --cpu as a differentiator. build:clang_config --cpu=k8 # Use the default Bazel C++ toolchain to build the tools used during the # build. build:clang_config --host_crosstool_top=@bazel_tools//tools/cpp:toolchain
Untuk entri build:{config_name} --flag=value
, flag command line
--config={config_name}
dikaitkan dengan flag tersebut. Lihat
dokumentasi untuk flag yang digunakan:
crosstool_top
,
cpu
, dan
host_crosstool_top
.
Saat Anda mem-build target
dengan bazel build --config=clang_config //main:hello-world
, Bazel akan menggunakan
toolchain kustom dari
cc_toolchain_suite
//toolchain:clang_suite
. Suite ini dapat mencantumkan
toolchain yang berbeda untuk CPU yang berbeda,
dan itulah sebabnya suite ini dibedakan dengan flag --cpu=k8
.
Karena Bazel menggunakan banyak alat internal yang ditulis dalam C++ selama build, seperti {i>process-wrapper<i}, toolchain C++ default yang sudah ada sebelumnya ditentukan untuk platform host, sehingga alat ini dibangun menggunakan toolchain itu yang dibuat dalam tutorial ini.
Mengonfigurasi toolchain C++
Untuk mengonfigurasi toolchain C++, bangun aplikasi berulang kali dan hilangkan setiap error satu per satu seperti yang dijelaskan di bawah ini.
Jalankan build dengan perintah berikut:
bazel build --config=clang_config //main:hello-world
Karena Anda menentukan
--crosstool_top=//toolchain:clang_suite
di file.bazelrc
, Bazel akan menampilkan error berikut:No such package `toolchain`: BUILD file not found on package path.
Di direktori ruang kerja, buat direktori
toolchain
untuk paket dan fileBUILD
kosong di dalam direktoritoolchain
.Jalankan build lagi. Karena paket
toolchain
belum menentukan Targetclang_suite
, Bazel akan menampilkan error berikut:No such target '//toolchain:clang_suite': target 'clang_suite' not declared in package 'toolchain' defined by .../toolchain/BUILD
Di file
toolchain/BUILD
, tentukan grup file kosong sebagai berikut:package(default_visibility = ["//visibility:public"]) filegroup(name = "clang_suite")
Jalankan build lagi. Bazel menampilkan error berikut:
'//toolchain:clang_suite' does not have mandatory providers: 'ToolchainInfo'
Bazel menemukan bahwa tanda
--crosstool_top
mengarah ke aturan yang tidak menyediakan penyediaToolchainInfo
yang diperlukan. Jadi, Anda perlu mengarahkan--crosstool_top
ke aturan yang menyediakanToolchainInfo
- itu adalah aturancc_toolchain_suite
. Dalam filetoolchain/BUILD
, ganti grup file kosong dengan yang berikut ini:cc_toolchain_suite( name = "clang_suite", toolchains = { "k8": ":k8_toolchain", }, )
Atribut
toolchains
secara otomatis memetakan--cpu
(dan juga--compiler
jika ditentukan) menjadicc_toolchain
. Anda belum menentukan targetcc_toolchain
dan Bazel akan segera mengeluh tentang hal itu.Jalankan build lagi. Bazel menampilkan error berikut:
Rule '//toolchain:k8_toolchain' does not exist
Sekarang Anda harus menentukan target
cc_toolchain
untuk setiap nilai dalam Atributcc_toolchain_suite.toolchains
. Tambahkan kode berikut ke filetoolchain/BUILD
:filegroup(name = "empty") cc_toolchain( name = "k8_toolchain", toolchain_identifier = "k8-toolchain", toolchain_config = ":k8_toolchain_config", all_files = ":empty", compiler_files = ":empty", dwp_files = ":empty", linker_files = ":empty", objcopy_files = ":empty", strip_files = ":empty", supports_param_files = 0, )
Jalankan build lagi. Bazel menampilkan error berikut:
Rule '//toolchain:k8_toolchain_config' does not exist
Selanjutnya, tambahkan target ":k8_toolchain_config" ke file
toolchain/BUILD
:filegroup(name = "k8_toolchain_config")
Jalankan build lagi. Bazel menampilkan error berikut:
'//toolchain:k8_toolchain_config' does not have mandatory providers: 'CcToolchainConfigInfo'
CcToolchainConfigInfo
adalah penyedia yang Anda gunakan untuk mengonfigurasi toolchain C++ Anda. Untuk memperbaiki error ini, buat aturan Starlark yang menyediakanCcToolchainConfigInfo
ke Bazel dengan membuat filetoolchain/cc_toolchain_config.bzl
dengan 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 beban pernyataan untuktoolchains/BUILD
:load(":cc_toolchain_config.bzl", "cc_toolchain_config")
Dan ganti "k8_toolchain_config" filegroup dengan deklarasi
cc_toolchain_config
aturan:cc_toolchain_config(name = "k8_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 titik ini, Bazel memiliki cukup informasi untuk mencoba membuat kode tetapi mereka masih belum tahu alat apa yang digunakan untuk menyelesaikan build yang dibutuhkan tindakan. Anda akan memodifikasi implementasi aturan Starlark untuk memberi tahu Bazel apa yang peralatan yang tepat untuk 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 build lagi. Bazel menampilkan error berikut:
..../BUILD:3:1: undeclared inclusion(s) in rule '//main:hello-world': this rule is missing dependency declarations for the following files included by 'main/hello-world.cc': '/usr/include/c++/9/ctime' '/usr/include/x86_64-linux-gnu/c++/9/bits/c++config.h' '/usr/include/x86_64-linux-gnu/c++/9/bits/os_defines.h' ....
Bazel perlu mengetahui tempat untuk menelusuri header yang disertakan. Ada beberapa cara untuk menyelesaikan masalah ini, seperti menggunakan atribut
includes
cc_binary
, tetapi di sini, masalah ini dipecahkan di level toolchain dengancxx_builtin_include_directories
daricc_common.create_cc_toolchain_config_info
. Perhatikan bahwa jika Anda menggunakan versiclang
yang berbeda, jalur penyertaan akan berbeda. Jalur ini juga dapat berbeda bergantung pada distribusi.Ubah nilai yang ditampilkan di
toolchain/cc_toolchain_config.bzl
untuk mencarinya seperti ini:return cc_common.create_cc_toolchain_config_info( ctx = ctx, cxx_builtin_include_directories = [ # NEW "/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, )
Jalankan perintah build lagi, 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 penaut tidak memiliki library standar C++ dan tidak dapat menemukan simbolnya. Ada banyak cara untuk menyelesaikan ini, seperti menggunakan atribut
linkopts
daricc_binary
. Di sini, masalah ini diatasi dengan memastikan bahwa target apa pun yang menggunakan toolchain tidak perlu menentukan flag ini.Salin kode berikut ke
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", "flag_group", "flag_set", "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], )
Jika Anda menjalankan
bazel build --config=clang_config //main:hello-world
, seharusnya akhirnya dibangun.
Meninjau tugas Anda
Dalam tutorial ini, Anda telah mempelajari cara mengonfigurasi toolchain C++ dasar, tetapi toolchain lebih canggih daripada contoh sederhana ini.
Poin-poin penting adalah:
- Anda perlu menentukan flag --crosstool_top
di command line yang seharusnya
arahkan ke cc_toolchain_suite
- Anda dapat membuat pintasan untuk konfigurasi tertentu menggunakan .bazelrc
file
- cc_era_suite mungkin mencantumkan cc_toolchains
untuk CPU yang berbeda dan
compiler. Anda dapat menggunakan flag command line seperti --cpu
untuk membedakan.
- Anda harus memberi tahu toolchain tempat alat berada. Dalam tutorial ini,
ada versi sederhana tempat Anda mengakses alat dari sistem. Jika
Anda tertarik dengan pendekatan yang lebih mandiri, Anda dapat membaca tentang
ruang kerja di sini. Alat Anda dapat berasal dari
ruang kerja yang berbeda dan Anda harus menyediakan filenya
ke cc_toolchain
dengan dependensi target pada atribut, seperti
compiler_files
. tool_paths
juga perlu diubah.
- Anda dapat membuat fitur untuk menyesuaikan flag yang akan diteruskan ke
berbagai tindakan, baik penautan maupun jenis tindakan lainnya.
Bacaan lebih lanjut
Untuk mengetahui detail selengkapnya, lihat Konfigurasi toolchain C++