Tutorial ini menggunakan contoh skenario untuk menjelaskan cara mengonfigurasi toolchain C++ untuk project. Project ini didasarkan pada
contoh project C++
yang di-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_toolchainsehingga Bazel dapat membangun aplikasi denganclang
- Konfirmasi hasil yang diharapkan dengan menjalankan
bazel build --config=clang_config //main:hello-worlddi komputer Linux
- Membangun aplikasi C++
Sebelum memulai
Menyiapkan lingkungan build
Tutorial ini mengasumsikan Anda menggunakan Linux dan telah berhasil membangun aplikasi C++ serta menginstal alat dan library yang sesuai.
Tutorial ini menggunakan clang version 9.0.1, yang dapat Anda instal di sistem Anda.
Siapkan lingkungan build Anda sebagai berikut:
- Jika Anda belum melakukannya, download dan instal Bazel 0.23 atau yang lebih baru. 
- Download project C++ contoh dari GitHub dan tempatkan di direktori kosong di komputer lokal Anda. 
- Tambahkan target - cc_binaryberikut ke file- main/BUILD:- cc_binary( name = "hello-world", srcs = ["hello-world.cc"], )
- Buat file - .bazelrcdi root direktori ruang kerja dengan konten berikut untuk mengaktifkan 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 tertentu tersebut. Lihat
dokumentasi untuk flag yang digunakan:
crosstool_top,
cpu, dan
host_crosstool_top.
Saat Anda membuat target
dengan bazel build --config=clang_config //main:hello-world, Bazel 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 tanda --cpu=k8.
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, sehingga alat ini dibangun menggunakan toolchain tersebut, bukan 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.
- Jalankan build dengan perintah berikut: - bazel build --config=clang_config //main:hello-world- Karena Anda menentukan - --crosstool_top=//toolchain:clang_suitedalam file- .bazelrc, Bazel akan menampilkan error berikut:- No such package `toolchain`: BUILD file not found on package path.- Di direktori ruang kerja, buat direktori - toolchainuntuk paket dan file- BUILDkosong di dalam direktori- toolchain.
- Jalankan build lagi. Karena paket - toolchainbelum menentukan target- clang_suite, Bazel akan menampilkan error berikut:- No such target '//toolchain:clang_suite': target 'clang_suite' not declared in package 'toolchain' defined by .../toolchain/BUILD- Dalam file - toolchain/BUILD, tentukan filegroup 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_topmengarah ke aturan yang tidak menyediakan penyedia- ToolchainInfoyang diperlukan. Jadi, Anda perlu mengarahkan- --crosstool_topke aturan yang menyediakan- ToolchainInfo- yaitu aturan- cc_toolchain_suite. Di file- toolchain/BUILD, ganti filegroup kosong dengan yang berikut:- cc_toolchain_suite( name = "clang_suite", toolchains = { "k8": ":k8_toolchain", }, )- Atribut - toolchainssecara otomatis memetakan nilai- --cpu(dan juga- --compilerjika ditentukan) ke- cc_toolchain. Anda belum menentukan target- cc_toolchaindan Bazel akan segera menampilkan error.
- Jalankan build lagi. Bazel menampilkan error berikut: - Rule '//toolchain:k8_toolchain' does not exist- Sekarang Anda perlu menentukan target - cc_toolchainuntuk setiap nilai dalam atribut- cc_toolchain_suite.toolchains. Tambahkan kode berikut ke file- toolchain/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'- CcToolchainConfigInfoadalah penyedia yang Anda gunakan untuk mengonfigurasi toolchain C++. Untuk memperbaiki error ini, buat aturan Starlark yang menyediakan- CcToolchainConfigInfoke Bazel dengan membuat file- toolchain/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 diperlukan- CcToolchainConfigInfo. Untuk menggunakan aturan- cc_toolchain_config, tambahkan pernyataan load ke- toolchain/BUILDtepat di bawah pernyataan paket:- load(":cc_toolchain_config.bzl", "cc_toolchain_config")- Lalu, ganti grup file "k8_toolchain_config" dengan deklarasi aturan - cc_toolchain_config:- 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 tahap ini, Bazel memiliki cukup informasi untuk mencoba membangun kode, tetapi Bazel masih belum mengetahui 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 bahwa - /usr/bin/clangdan- /usr/bin/ldadalah 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 mengatasi hal ini, seperti menggunakan atribut - includesdari- cc_binary, tetapi di sini hal ini diselesaikan di tingkat toolchain dengan parameter- cxx_builtin_include_directoriesdari- cc_common.create_cc_toolchain_config_info. Perhatikan bahwa jika Anda menggunakan- clangversi lain, jalur include 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-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 linker tidak memiliki library standar C++ dan tidak dapat menemukan simbolnya. Ada banyak cara untuk mengatasi hal ini, seperti menggunakan atribut - linkoptsdari- cc_binary. Di sini, masalah diselesaikan 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, build akan selesai.
Meninjau tugas Anda
Dalam tutorial ini, Anda telah mempelajari cara mengonfigurasi toolchain C++ dasar, tetapi toolchain lebih canggih daripada contoh sederhana ini.
Kesimpulan utamanya adalah:
- Anda perlu menentukan tanda --crosstool_top di command line yang harus
  menunjuk ke cc_toolchain_suite
- Anda dapat membuat pintasan untuk konfigurasi tertentu menggunakan file .bazelrc
  file
- cc_toolchain_suite dapat mencantumkan cc_toolchains untuk CPU dan
  compiler yang berbeda. Anda dapat menggunakan tanda command line seperti --cpu untuk membedakannya.
- 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 file-nya
  untuk cc_toolchain dengan dependensi target pada atribut, seperti
  compiler_files. tool_paths juga perlu diubah.
- Anda dapat membuat fitur untuk menyesuaikan tanda yang harus diteruskan ke
  tindakan yang berbeda, baik itu penautan maupun jenis tindakan lainnya.
Bacaan lebih lanjut
Untuk mengetahui detail selengkapnya, lihat Konfigurasi toolchain C++