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
  • Ek özellikler sağlayan bir Starlark kuralı Bazel'in uygulamayı derleyebilmesi için cc_toolchain yapılandırması clang ile
  • Şu komutu çalıştırarak C++ ikili programını derleyin: Bir Linux makinesinde bazel build //main:hello-world
  • 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 başarıyla geliştirdiğiniz varsayılmaktadır. C++ uygulamalarını yükleyebilir ve uygun araçlar ile kitaplıkları yükleyebilirsiniz. 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:

  1. Henüz yapmadıysanız Bazel 7.0.2 veya sonraki bir sürümünü indirip yüklemeniz gerekir.

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

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

    load("@rules_cc//cc:defs.bzl", "cc_binary")
    
    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, barındırma platformu. Böylece bu dahili araçlar, mevcut kaynaklarınızla araç zincirini kullanmaya devam edebilirsiniz. Bu nedenle, 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, WORKSPACE içinde kayıtlı herhangi bir araç zinciri olmadan başarılı olur.

    Gelişmiş seçenekleri daha fazla 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 @@local_config_platform//:host: Selected execution platform @@local_config_platform//:host, type @@bazel_tools//tools/cpp:toolchain_type -> toolchain @@bazel_tools+cc_configure_extension+local_config_cc//:cc-compiler-k8
    

    Bazel, --platforms belirtmeden @local_config_platform//: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 clang'ın farklı versiyonları arasında biraz fark var.

  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 araç zincirini WORKSPACE öğesine kaydedin.

    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, yapılandırmak için kullandığınız bir sağlayıcıdır çok önemlidir. Bu hatayı düzeltmek için bir Starlark kuralı oluşturun oluşturarak Bazel'e CcToolchainConfigInfo sağlayan bir Ş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 @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 doğru olduğundan emin olun bir uygulamadır.

  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. Her biri 100'den az gösterim alan bunu çözmek için includes cc_binary, ancak burada bu, cxx_builtin_include_directories parametresi için cc_common.create_cc_toolchain_config_info değerini girin. Bu nedenle, farklı bir clang sürümünü 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 değiştirerek aşağıdaki gibidir:

    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, belirli bir 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 ana makine için ikili programın başarıyla derlenmesi gerekir.

  9. toolchain/BUILD bölümündeki cc_toolchain_config, cc_toolchain ve toolchain hedef ve linux_x86_64 yerine android_x86_64 değerini hedefle gösterir.

    WORKSPACE 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. Android için ikili programı derlemek üzere bazel build //main:hello-world --android_platforms=//toolchain:android_x86_64 komutunu çalıştırın.

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 basit örnekten daha güçlüdür.

Ana fikirler:

  • Bazel'ın şunları yapması için komut satırında eşleşen bir platforms işareti belirtmeniz gerekir: platformdaki aynı kısıtlama değerleri için araç zincirine çözümlenir. Dokümanlarda, dile özgü yapılandırma işaretleri hakkında daha fazla bilgi yer almaktadır.
  • 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 çalışma alanları gibi diğer işlevler de dahildir. Araçlarınız nereden ve onlara ait dosyaları kullanılabilir hale getirmeniz, cc_toolchain ile 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 bilgi için bkz. C++ araç zinciri yapılandırması