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ı
clangile derleyebilmesi içincc_toolchainiçin ek yapılandırma sağlayan bir Starlark kuralı oluşturun - Linux makinesinde
bazel build //main:hello-world'ü çalıştırarak C++ ikilisini derleyin bazel build //main:hello-world --platforms=//:android_x86_64dosyası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 19 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.bazeldosyası ekleyin.main/BUILDdosyasına aşağıdakicc_binaryhedefini ekleyin:cc_binary( name = "hello-world", srcs = ["hello-world.cc"], )Bazel, derleme sırasında
process-wrappergibi 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 derlenmesini sağlar. Bu nedenle,cc_binaryhedefi de varsayılan araç zinciriyle oluşturulur.Aşağıdaki komutu kullanarak derlemeyi çalıştırın:
bazel build //main:hello-worldDerleme,
MODULE.bazel'te kayıtlı herhangi bir araç zinciri olmadan başarılı olur.İşleyişin ayrıntılarını daha ayrıntılı görmek için şunları ç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-k8Bazel,
--platformsbelirtmeden@platforms//hostiçin hedefi@bazel_tools+cc_configure_extension+local_config_cc//:cc-compiler-k8kullanarak 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/BUILDile 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.bazelile kaydettirin.bazel_dep(name = "platforms", version = "0.0.10") register_toolchains( "//toolchain:cc_toolchain_for_linux_x86_64" )Bu adımda, bir
cc_toolchaintanımlanır ve ana makine yapılandırması için birtoolchainhedefine bağlanır.Derlemeyi tekrar çalıştırın.
toolchainpaketi henüzlinux_x86_64_toolchain_confighedefini tanımlamadığı için Bazel aşağıdaki hatayı verir: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/BUILDdosyası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.bzldosyası oluşturarak Bazel'eCcToolchainConfigInfosağlayan bir 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(), gerekli sağlayıcıyı oluştururCcToolchainConfigInfo.cc_toolchain_configkuralını kullanmak için paket ifadesi hemen altındakitoolchain/BUILDalanına bir yükleme ifadesi ekleyin:load(":cc_toolchain_config.bzl", "cc_toolchain_config")Ardından, "linux_x86_64_toolchain_config" dosya grubunu bir
cc_toolchain_configkuralı 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.bzlsınıfındakitool_path()kurucusuna 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", # 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 )/usr/bin/clangve/usr/bin/ld'un sisteminiz için doğru yollar olduğundan emin olun. Derleyiciye geçmişe dayalı nedenlerden dolayı "gcc" adıyla referans verildiğini unutmayın.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 üstbilgileri nerede arayacağını bilmesi gerekir. Bu sorunu çözmenin birden fazla yolu vardır (ör.
cc_binaryöğesininincludesözelliğini kullanmak). Ancak burada bu sorun,cc_common.create_cc_toolchain_config_infoöğesinincxx_builtin_include_directoriesparametresi kullanılarak araç zinciri düzeyinde çözülmüştü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.bzliç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-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, )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. Bu sorunu çözmenin birçok yolu vardır. Örneğin,
cc_binaryöğesininlinkoptsözelliğini kullanabilirsiniz. Burada, araç setini kullanan tüm hedeflerin bu işareti belirtmesi gerekmediğinden emin olarak bu sorun çözüldü.Aşağıdaki kodu
toolchain/cc_toolchain_config.bzlalanı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", # 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], )Bu kodun libstdc++ GNU C++ kitaplığını kullandığını unutmayın. LLVM C++ kitaplığını kullanmak istiyorsanız "-lstdc++" yerine "-lc++" kullanın.
bazel build //main:hello-worldçalıştırıldığında, ikili dosyayı ana makine için başarıyla derleyecektir.toolchain/BUILD'tecc_toolchain_config,cc_toolchainvetoolchainhedeflerini kopyalayın ve hedef adlarındalinux_x86_64yerineandroid_x86_64yazın.MODULE.bazel'te 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_64komutunu ç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.
Önemli noktalar şunlardır:
- 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
platformsişareti belirtmeniz gerekir. Dile özgü yapılandırma işaretleri hakkında daha fazla bilgi dokümanda yer almaktadır. - Araç setinin, araçların nerede olduğunu bilmesini sağlamanız 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 harici bağımlılıklar hakkında bilgi edinebilirsiniz. Araçlarınız farklı bir modülden gelebilir ve dosyalarını
cc_toolchainiçin kullanılabilir hale getirmeniz gerekir. Bu işlem içincompiler_filesgibi özelliklerde hedef bağımlılıklar kullanmanız gerekir.tool_pathsdeğerinin de değiştirilmesi gerekir. - Bağlantı oluşturma veya başka bir işlem türü olsun, farklı işlemlere hangi işaretlerin iletileceğ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.