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:
Henüz yapmadıysanız Bazel 0.23 veya sonraki bir sürümünü indirip yükleyin.
İndirin: örnek C++ projesi dosyayı yerel makinenizde boş bir dizine yerleştirin.
main/BUILD
dosyasına aşağıdakicc_binary
hedefini ekleyin:cc_binary( name = "hello-world", srcs = ["hello-world.cc"], )
Ç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.
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 vetoolchain
dizininde boş birBUILD
dosyası bulunmalıdır.Derlemeyi tekrar çalıştırın. Çünkü
toolchain
paketi henüzclang_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")
Derlemeyi tekrar çalıştırın. Bazel şu hatayı verir:
'//toolchain:clang_suite' does not have mandatory providers: 'ToolchainInfo'
Bazel,
--crosstool_top
işaretinin gerekenToolchainInfo
sağlanmıyor sağlar. Bu nedenle,--crosstool_top
öğesiniToolchainInfo
-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ğerlericc_toolchain
değerine ayarlanır. Henüz göndermediniz tümcc_toolchain
hedefleri tanımladı. Bazel bundan şikayet ediyor yakında.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ğıdakileritoolchain/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, )
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")
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'eCcToolchainConfigInfo
sağlayan bir Şu içeriğe sahiptoolchain/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ştururCcToolchainConfigInfo
.cc_toolchain_config
kuralını kullanmak için bir yük ekleyintoolchains/BUILD
için ifade: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")
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.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çincc_common.create_cc_toolchain_config_info
değerini girin. Bu nedenle, farklı birclang
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, )
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çinlinkopts
ö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], )
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ı