Bu eğitimde, bir proje için C++ araç zincirlerinin nasıl yapılandırılacağı örnek bir senaryoyla açıklanmaktadır.
Neler öğreneceksiniz?
Bu eğitimde şunları öğreneceksiniz:
- Derleme ortamını ayarlama
- Araç zinciri çözümünde hata ayıklama için
--toolchain_resolution_debug
'ü kullanma - C++ araç zincirini yapılandırma
- Bazel'in uygulamayı
clang
ile derleyebilmesi içincc_toolchain
için ek yapılandırma sağlayan bir Starlark kuralı oluşturun - Linux makinesinde
bazel build //main:hello-world
çalıştırarak C++ ikili programını derleyin bazel build //main:hello-world --platforms=//:android_x86_64
dosyasını çalıştırarak ikili dosyayı Android için çapraz derleyin.
Başlamadan önce
Bu eğitimde, Linux kullanıyor ve C++ uygulamalarını başarıyla derleyip uygun araçları ve kitaplıkları yüklediğiniz varsayılmaktadır. Eğitimde, sisteminize yükleyebileceğiniz clang version 16
kullanılır.
Derleme ortamını ayarlama
Derleme ortamınızı aşağıdaki gibi ayarlayın:
Henüz yapmadıysanız Bazel 7.0.2 veya sonraki bir sürümü indirip yükleyin.
Kök klasöre boş bir
MODULE.bazel
dosyası ekleyin.main/BUILD
dosyasına aşağıdakicc_binary
hedefini ekleyin:cc_binary( name = "hello-world", srcs = ["hello-world.cc"], )
Bazel, derleme sırasında
process-wrapper
gibi C++ ile yazılmış birçok dahili araç kullandığından, ana makine platformu için önceden var olan varsayılan C++ araç zinciri belirtilir. Bu, bu dahili araçların bu eğitimde oluşturulan araç zincirini kullanarak derlemesine olanak tanır. Dolayısıyla,cc_binary
hedefi aynı zamanda varsayılan araç zinciriyle de oluşturulur.Aşağıdaki komutu kullanarak derlemeyi çalıştırın:
bazel build //main:hello-world
Derleme,
MODULE.bazel
içinde kayıtlı herhangi bir araç zinciri olmadan başarılı olur.Gelişmiş seçenekleri daha iyi görmek için şu komutu çalıştırın:
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-k8
Bazel,
--platforms
belirtmeden@platforms//host
için hedefi@bazel_tools+cc_configure_extension+local_config_cc//:cc-compiler-k8
kullanarak oluşturur.
C++ araç zincirini yapılandırma
C++ araç zincirini yapılandırmak için uygulamayı tekrar tekrar derleyin ve her hatayı aşağıda açıklandığı şekilde tek tek giderin.
Ayrıntılar clang'ın farklı sürümleri arasında yalnızca biraz değişse de clang version 9.0.1
de varsayılır.
toolchain/BUILD
eklemefilegroup(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", ], )
Ardından uygun bağımlılıkları ekleyin ve araç setini
MODULE.bazel
ile kaydettirin.bazel_dep(name = "platforms", version = "0.0.10") register_toolchains( "//toolchain:cc_toolchain_for_linux_x86_64" )
Bu adımda, bir
cc_toolchain
tanımlanır ve ana makine yapılandırması için birtoolchain
hedefine bağlanır.Derlemeyi tekrar çalıştırın.
toolchain
paketi henüzlinux_x86_64_toolchain_config
hedefini tanımlamadığından Bazel aşağıdaki hatayı bildirir: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.
toolchain/BUILD
dosyasında boş bir dosya grubunu aşağıdaki gibi tanımlayın:package(default_visibility = ["//visibility:public"]) filegroup(name = "linux_x86_64_toolchain_config")
Derlemeyi tekrar çalıştırın. Bazel aşağıdaki hatayı verir:
'//toolchain:linux_x86_64_toolchain_config' does not have mandatory providers: 'CcToolchainConfigInfo'.
CcToolchainConfigInfo
, C++ araç zincirlerinizi yapılandırmak için kullandığınız bir sağlayıcıdır. Bu hatayı düzeltmek için aşağıdaki içeriğe sahip birtoolchain/cc_toolchain_config.bzl
dosyası oluşturarak Bazel'eCcToolchainConfigInfo
sağlayan Starlark kuralı oluşturun: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()
, gereken sağlayıcıyı oluştururCcToolchainConfigInfo
.cc_toolchain_config
kuralını kullanmak için paket ifadesinin hemen altındatoolchain/BUILD
öğesine bir yük ifadesi ekleyin:load(":cc_toolchain_config.bzl", "cc_toolchain_config")
Ardından, "linux_x86_64_toolchain_config" dosya grubunu bir
cc_toolchain_config
kuralı beyanıyla değiştirin:cc_toolchain_config(name = "linux_x86_64_toolchain_config")
Derlemeyi tekrar çalıştırın. Bazel aşağıdaki hatayı verir:
.../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`
Bu noktada Bazel, kodu derlemeye çalışmak için yeterli bilgiye sahiptir ancak gerekli derleme işlemlerini tamamlamak için hangi araçların kullanılacağını hâlâ bilmez. Bazel'e hangi araçları kullanacağını bildirmek için Starlark kural uygulamasını değiştireceksiniz. Bunun için
@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl
kaynağındakitool_path()
oluşturucuya ihtiyacınız vardır:# 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 )
/usr/bin/clang
ve/usr/bin/ld
'nin sisteminiz için doğru yollar olduğundan emin olun.Derlemeyi tekrar çalıştırın. Bazel aşağıdaki hatayı verir:
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'in, dahil edilen üstbilgilerin nerede aranacağını bilmesi gerekir. Bu sorunu çözmenin birden fazla yolu vardır. Örneğin
cc_binary
öğesininincludes
özelliğini kullanmak gibi. Ancak bu sorun,cc_common.create_cc_toolchain_config_info
öğesinincxx_builtin_include_directories
parametresiyle araç zinciri düzeyinde çözülür.clang
'nin farklı bir sürümünü kullanıyorsanız dahil etme yolunun farklı olacağına dikkat edin. Bu yollar, dağıtıma bağlı olarak da farklı olabilir.toolchain/cc_toolchain_config.bzl
içindeki döndürülen değeri şu şekilde değiştirin: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, )
Derleme komutunu tekrar çalıştırdığınızda şuna benzer bir hata görürsünüz:
/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'
Bunun nedeni, C++ standart kitaplığının bağlayıcıda bulunmaması ve bağlayıcının bu kitaplığın simgelerini bulamamasıdır. Bunu çözmenin birçok yolu vardır. Örneğin
cc_binary
içinlinkopts
özelliğini kullanabilirsiniz. Bu yöntemde sorun, araç zincirini kullanan herhangi bir hedefin bu işareti belirtmek zorunda kalmamasıyla çözülür.Aşağıdaki kodu
toolchain/cc_toolchain_config.bzl
alanına kopyalayın:# 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], )
bazel build //main:hello-world
çalıştırıldığında, ikili dosya ana makine için başarıyla derlenir.toolchain/BUILD
'tecc_toolchain_config
,cc_toolchain
vetoolchain
hedeflerini kopyalayın ve hedef adlarındalinux_x86_64
yerineandroid_x86_64
yazın.MODULE.bazel
uygulamasında Android için araç zincirini kaydedinregister_toolchains( "//toolchain:cc_toolchain_for_linux_x86_64", "//toolchain:cc_toolchain_for_android_x86_64" )
Android için ikili dosyayı derlemek üzere
bazel build //main:hello-world --android_platforms=//toolchain:android_x86_64
komutunu çalıştırın.
Uygulamada Linux ve Android'in farklı C++ araç zinciri yapılandırmaları olmalıdır. Farklılıklar için mevcut cc_toolchain_config
'yi değiştirebilir veya ayrı platformlar için ayrı kurallar (ör. CcToolchainConfigInfo
sağlayıcısı) oluşturabilirsiniz.
Çalışmanızı inceleme
Bu eğitimde temel bir C++ araç zincirinin nasıl yapılandırılacağını öğrendiniz ancak araç zincirleri bu örnekten daha güçlüdür.
Ana fikirler:
- Bazel'in platformdaki aynı kısıtlama değerleri için araç zincirine çözüm üretmesi amacıyla komut satırında eşleşen bir
platforms
işareti belirtmeniz gerekir. Dil özelinde yapılandırma işaretleri hakkında daha fazla bilgi dokümanda yer almaktadır. - Araçların nerede olduğunu araç zincirine bildirmeniz gerekir. Bu eğitimde, sistemdeki araçlara eriştiğiniz basitleştirilmiş bir sürüm bulunmaktadır. Daha bağımsız bir yaklaşımla ilgileniyorsanız dış bağımlılıklar hakkında bilgi edinebilirsiniz. Araçlarınız farklı bir modülden gelebilir ve dosyalarını
cc_toolchain
için kullanılabilir hale getirmeniz gerekir. Bu işlem içincompiler_files
gibi özelliklerde hedef bağımlılıklar kullanmanız gerekir.tool_paths
değerinin de değiştirilmesi gerekir. - Bağlama veya başka bir işlem türü gibi farklı işlemlere hangi işaretlerin iletilmesi gerektiğini özelleştirmek için özellikler oluşturabilirsiniz.
Daha fazla bilgi
Daha fazla bilgi için C++ araç zinciri yapılandırması başlıklı makaleyi inceleyin.