Bazel Eğitimi: C++ Araç Zincirlerini Yapılandırma

Sorun bildir Kaynağı göster Gece · 7,3 · 7,2 · 7,1 · 7,0 · 6,5

Bu eğitimde, C++'ın nasıl yapılandırılacağını açıklayan örnek bir senaryo kullanılmaktadır. araç zincirleri olarak düşünebilirsiniz.

Neler öğreneceksiniz?

Bu eğitimde şunları öğreneceksiniz:

  • Derleme ortamını ayarlama
  • Araç zinciri çözünürlüğünde hata ayıklamak için --toolchain_resolution_debug kullanın
  • C++ araç zincirini yapılandırma
  • Etiket için ek yapılandırma sağlayan bir Starlark kuralı Bazel'in uygulamayı clang ile derleyebilmesi için cc_toolchain
  • bazel build //main:hello-world komutunu çalıştırarak Linux makinesi
  • bazel build //main:hello-world --platforms=//:android_x86_64 komutunu çalıştırarak Android için ikili programı çapraz derleyin

Başlamadan önce

Bu eğiticide, Linux kullandığınız ve C++ hizmetini başarıyla derlediğiniz varsayılmaktadır doğru araçları ve kitaplıkları yüklemeniz gerekir. Eğitim sisteminize yükleyebileceğiniz clang version 16 uygulamasını kullanır.

Derleme ortamını ayarlama

Derleme ortamınızı aşağıdaki gibi ayarlayın:

  1. Henüz yapmadıysanız Bazel'i indirip yükleyin 7.0.2 veya sonraki sürümler.

  2. Kök klasöre boş bir MODULE.bazel dosyası ekleyin.

  3. main/BUILD dosyasına aşağıdaki cc_binary hedefini ekleyin:

    cc_binary(
        name = "hello-world",
        srcs = ["hello-world.cc"],
    )
    

    Çünkü Bazel, derleme sırasında C++ dilinde yazılmış birçok dahili araç kullandığından, process-wrapper olarak ayarlanırsa önceden var olan varsayılan C++ araç zinciri belirtilir barındırma platformu için de geçerli. Böylece bu dahili araçlar, mevcut kaynaklarınızla araç zincirini kullanmaya devam edebilirsiniz. Dolayısıyla, cc_binary hedefi varsayılan araç zinciriyle de derlenmiştir.

  4. Derlemeyi aşağıdaki komutla ç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 kullanıyor @bazel_tools+cc_configure_extension+local_config_cc//:cc-compiler-k8.

C++ araç zincirini yapılandırma

C++ araç zincirini yapılandırmak için uygulamayı sürekli olarak derleyin ve her hatayı aşağıda açıklandığı gibi tek tek güncelleyin.

Ayrıca clang version 9.0.1 varsayılır, ancak ayrıntılar yalnızca değişmelidir ve clang'ın farklı versiyonları arasında biraz daha

  1. Şunu ekle: toolchain/BUILD

    filegroup(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ç zincirini MODULE.bazel

    bazel_dep(name = "platforms", version = "0.0.10")
    register_toolchains(
        "//toolchain:cc_toolchain_for_linux_x86_64"
    )
    

    Bu adım bir cc_toolchain tanımlar ve bunu bir toolchain hedefine bağlar. yapılandırdığınızdan emin olun.

  2. Derlemeyi tekrar çalıştırın. Çünkü toolchain paketi henüz linux_x86_64_toolchain_config hedefi belirlendiğinde, Bazel şu 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.
    
  3. 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")
    
  4. Derlemeyi tekrar çalıştırın. Bazel şu hatayı verir:

    '//toolchain:linux_x86_64_toolchain_config' does not have mandatory providers: 'CcToolchainConfigInfo'.
    

    CcToolchainConfigInfo, C++ uygulamanızı yapılandırmak için kullandığınız bir sağlayıcıdır. araç zincirleri olarak düşünebilirsiniz. Bu hatayı düzeltmek için aşağıdakileri sağlayan bir Starlark kuralı oluşturun: CcToolchainConfigInfo işlemini kullanarak Bazel'e Şu içeriğe sahip toolchain/cc_toolchain_config.bzl dosyası:

    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şturur CcToolchainConfigInfo. cc_toolchain_config kuralını kullanmak için bir yük ekleyin deyimini paket ekstresinin hemen altında bulunan toolchain/BUILD olarak değiştirin:

    load(":cc_toolchain_config.bzl", "cc_toolchain_config")
    

    "linux_x86_64_toolchain_config" ifadesini ise bildirim içeren dosya grubu cc_toolchain_config kuralının sayısı:

    cc_toolchain_config(name = "linux_x86_64_toolchain_config")
    
  5. Derlemeyi tekrar çalıştırın. Bazel şu 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 oluşturmayı denemek için yeterli bilgiye sahip ancak ancak gerekli derlemeyi tamamlamak için hangi araçların kullanılması gerektiğini işlemlerdir. Starlark kuralının uygulanmasını değiştirerek Bazel'a çeşitli araçlar vardır. Bunun için tool_path() oluşturucuya @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
        )
    

    /usr/bin/clang ve /usr/bin/ld yollarının en iyi uygulamaları paylaşacağız.

  6. Derlemeyi tekrar çalıştırın. Bazel şu 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 eklenen başlıkları nerede arayacağını bilmesi gerekiyor. Birden fazla Örneğin cc_binary için includes özelliğini kullanmak, Ancak burada bu, tek bir kodla araç zinciri düzeyinde cxx_builtin_include_directories parametresi için cc_common.create_cc_toolchain_config_info değerini girin. Proje başlatma belgesinde clang için farklı bir sürüm kullanıyorsanız dahil etme yolu yardımcı olur. Bu yollar ayrıca dağıtıma bağlı olarak farklı olabilir.

    toolchain/cc_toolchain_config.bzl bölümündeki döndürülen değeri şu şekilde değiştirin: bu:

    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,
    )
    
  7. Derleme komutunu tekrar çalıştırdığınızda şuna benzer bir hata gösterilir:

    /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, bağlayıcıda C++ standardının eksik olmasıdır. simgelerini bulamıyor. Bunu çözmenin pek çok yolu var. örneğin cc_binary için linkopts özelliğini kullanabilirsiniz. Bu örnekte araç zincirini kullanan herhangi bir hedefin bunu belirtmek zorunda tıklayın.

    Aşağıdaki kodu toolchain/cc_toolchain_config.bzl cihazı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],
    )
    
  8. bazel build //main:hello-world çalıştırıldığında, nihayet ikili program derlenir işlemi başarıyla tamamlandı.

  9. toolchain/BUILD bölümündeki cc_toolchain_config, cc_toolchain ve toolchain hedef ve linux_x86_64 yerine android_x86_64 daha iyidir.

    MODULE.bazel uygulamasında Android için araç zincirini kaydedin

    register_toolchains(
        "//toolchain:cc_toolchain_for_linux_x86_64",
        "//toolchain:cc_toolchain_for_android_x86_64"
    )
    
  10. bazel build //main:hello-world --android_platforms=//toolchain:android_x86_64 komutunu çalıştırarak ikili programı derleyin Android

Pratikte, Linux ve Android'in farklı C++ araç zinciri yapılandırmaları olması gerekir. Siz mevcut cc_toolchain_config değerini farklar için değiştirebilir veya farklı veri hizmetleri için ayrı kurallar (ör. CcToolchainConfigInfo sağlayıcısı) platformlar.

Çalışmanızı inceleyin

Bu eğiticide temel bir C++ araç zincirinin nasıl yapılandırılacağını öğrendiniz, araç zincirleri bu örnekten daha güçlüdür.

Ana fikirler:

  • Şunun için komut satırında eşleşen bir platforms işareti belirtmeniz gerekir: platformu. Dokümanlar, dil ile ilgili daha fazla bilgi içerir. yapılandırma işaretleri dahil edilmiştir.
  • Araç zincirine araçların nerede bulunduğunu bildirmeniz gerekir. Bu eğiticide araçlara sistemden erişebileceğiniz basitleştirilmiş bir sürümü vardır. Eğer daha bağımsız bir yaklaşım istiyorsanız dış bağımlılıklara yol açabilir. Araçlarınız nereden ve bu modülün sonunda kendi dosyalarını, Özelliklere hedef bağımlılıkları olan cc_toolchain compiler_files. tool_paths değerinin de değiştirilmesi gerekir.
  • Hangi işaretlerin iletileceğini özelleştirmek için özellikler oluşturabilirsiniz. işlemler (ör. bağlantı oluşturma veya başka türden işlemler)

Daha fazla bilgi

Daha fazla ayrıntı için C++ araç zincirine bakın yapılandırma