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

. Sorun bildirin 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. Şuna dayalı: örnek C++ projesi hatasız derleme sunan bir kod snippet'i ekleyin.clang

Neler öğreneceksiniz?

Bu eğitimde şunları öğreneceksiniz:

  • Derleme ortamını ayarlama
  • 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
  • Beklenen sonucu almak için Bir Linux makinesinde bazel build --config=clang_config //main:hello-world
  • C++ uygulamasını derleme

Başlamadan önce

Derleme ortamını ayarlama

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 9.0.1 kullanılır.

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

  1. Henüz yapmadıysanız Bazel 0.23 veya sonraki bir sürümünü indirip yükleyin.

  2. İndirin: örnek C++ projesi dosyayı yerel makinenizde boş bir dizine yerleştirin.

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

    cc_binary(
        name = "hello-world",
        srcs = ["hello-world.cc"],
    )
    
  4. Çalışma alanı dizininin kökünde, şununla bir .bazelrc dosyası oluşturun: --config işaretinin kullanımını etkinleştirmek için aşağıdaki içerikleri inceleyin:

    # 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
    

build:{config_name} --flag=value girişi için komut satırı işareti --config={config_name} bu işaretle ilişkilendirilmiş. Görüntüleyin kullanılan flag'lerle ilgili dokümanlar: crosstool_top cpu ve host_crosstool_top.

Hedefinizi oluştururken bazel build --config=clang_config //main:hello-world kullanan Bazel, özel araç zincirini veya cc_toolchain_suite //toolchain:clang_suite. Paket, farklı araç zincirlerini kullanıma sunduk. Bu nedenle --cpu=k8 işaretiyle ayırt edilir.

Çünkü Bazel, derleme sırasında C++ dilinde yazılmış birçok dahili araç kullanır (ör. işlemiyle, önceden var olan varsayılan C++ araç zinciri ana makine platformu aracılığıyla yapılandırılabilir. Böylece bu araçlar bir şablondan oluşur.

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.

  1. Derlemeyi aşağıdaki komutla çalıştırın:

    bazel build --config=clang_config //main:hello-world
    

    --crosstool_top=//toolchain:clang_suite .bazelrc dosyasını kaydederken Bazel şu hatayı verir:

    No such package `toolchain`: BUILD file not found on package path.
    

    Çalışma alanı dizininde, paket için toolchain dizini oluşturun ve toolchain dizininde boş bir BUILD dosyası bulunmalıdır.

  2. Derlemeyi tekrar çalıştırın. Çünkü toolchain paketi henüz clang_suite hedefi belirlendiğinde, Bazel şu hatayı verir:

    No such target '//toolchain:clang_suite': target 'clang_suite' not declared
    in package 'toolchain' defined by .../toolchain/BUILD
    

    toolchain/BUILD dosyasında boş bir dosya grubunu aşağıdaki gibi tanımlayın:

    package(default_visibility = ["//visibility:public"])
    
    filegroup(name = "clang_suite")
    
  3. Derlemeyi tekrar çalıştırın. Bazel şu hatayı verir:

    '//toolchain:clang_suite' does not have mandatory providers: 'ToolchainInfo'
    

    Bazel, --crosstool_top işaretinin gereken ToolchainInfo sağlanmıyor sağlar. Bu nedenle, --crosstool_top öğesini ToolchainInfo - cc_toolchain_suite kuralı budur. toolchain/BUILD dosyası varsa boş dosya grubunu aşağıdakiyle değiştirin:

    cc_toolchain_suite(
        name = "clang_suite",
        toolchains = {
            "k8": ":k8_toolchain",
        },
    )
    

    toolchains özelliği, --cpu (ve ayrıca --compiler) değerleri cc_toolchain değerine ayarlanır. Henüz göndermediniz tüm cc_toolchain hedefleri tanımladı. Bazel bundan şikayet ediyor yakında.

  4. Derlemeyi tekrar çalıştırın. Bazel şu hatayı verir:

    Rule '//toolchain:k8_toolchain' does not exist
    

    Şimdi her değer için cc_toolchain hedefleri tanımlamanız gerekiyor. cc_toolchain_suite.toolchains özelliği için de geçerlidir. Aşağıdakileri toolchain/BUILD dosyası:

    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,
    )
    
  5. Derlemeyi tekrar çalıştırın. Bazel şu hatayı verir:

    Rule '//toolchain:k8_toolchain_config' does not exist
    

    Sonra, bir ":k8_toolchain_config" ekleyin toolchain/BUILD dosyasını hedefle:

    filegroup(name = "k8_toolchain_config")
    
  6. Derlemeyi tekrar çalıştırın. Bazel şu hatayı verir:

    '//toolchain:k8_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")
    

    "k8_toolchain_config" ifadesini ise bildirimi içeren dosya grubu cc_toolchain_config kural:

    cc_toolchain_config(name = "k8_toolchain_config")
    
  7. 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.

  8. Derlemeyi tekrar çalıştırın. Bazel şu hatayı verir:

     ..../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'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-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,
     )
    
  9. 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 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",
          "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],
      )
    
  10. bazel build --config=clang_config //main:hello-world çalıştırırsanız bahsedeceğim.

Ç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: - Komut satırında bir --crosstool_top işareti belirtmeniz gerekir. bir cc_toolchain_suite öğesine işaret et - Belirli bir yapılandırma için .bazelrc öğesini kullanarak kısayol oluşturabilirsiniz. dosya - cc_toolchain_suite, farklı CPU'lar vecc_toolchains derleyiciler. Farklılaştırmak için --cpu gibi komut satırı işaretlerini kullanabilirsiniz. - 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ınızı burada bulabilirsiniz. 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 iletilmesi gerektiğ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ı