Bu eğitim, bir proje için C++ araç zincirlerinin nasıl yapılandırılacağını açıklamak üzere örnek bir senaryo kullanır. Bu örnek, clang
ile hatasız çalışan örnek bir C++ projesine dayanır.
Neler öğreneceksiniz?
Bu eğitimde şunları öğreneceksiniz:
- Derleme ortamını ayarlama
- C++ araç zincirini yapılandırma
- Bazel'ın
clang
ile uygulama derleyebilmesi amacıylacc_toolchain
için ek yapılandırma sağlayan bir Starlark kuralı oluşturun. bazel build --config=clang_config //main:hello-world
komutunu bir Linux makinesinde çalıştırarak beklenen sonucu onaylayın- C++ uygulamasını derleme
Başlamadan önce
Derleme ortamını ayarlama
Bu eğitim, Linux kullandığınız ve C++ uygulamalarını başarılı bir şekilde derleyip uygun araçları ve kitaplıkları yüklediğiniz varsayılır.
Eğitim, sisteminize yükleyebileceğiniz clang version 9.0.1
hizmetini kullanı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ü indirip yükleyin.
GitHub'dan örnek C++ projesini indirin ve yerel makinenizdeki boş bir dizine yerleştirin.
main/BUILD
dosyasına aşağıdakicc_binary
hedefini ekleyin:cc_binary( name = "hello-world", srcs = ["hello-world.cc"], )
--config
işaretinin kullanımını etkinleştirmek için Workspace dizininin kök dizininde aşağıdaki içeriklerle bir.bazelrc
dosyası oluşturun:# 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
Bir build:{config_name} --flag=value
girişi için --config={config_name}
komut satırı işareti bu işaretle ilişkilendirilir. Kullanılan işaretlerle ilgili belgelere göz atın:
crosstool_top
,
cpu
ve
host_crosstool_top
.
bazel build --config=clang_config //main:hello-world
ile hedefinizi oluştururken Bazel, cc_toolchain_suite'ten //toolchain:clang_suite
özel araç zincirinizi kullanır. Paket, farklı CPU'lar için farklı araç zincirleri listeleyebilir. Bu nedenle, --cpu=k8
işaretiyle diğerlerinden ayrılır.
Bazel, derleme sırasında işlem sarmalayıcı gibi C++'ta yazılmış birçok dahili araç kullandığından ana makine platformu için önceden mevcut olan varsayılan C++ araç zinciri belirtilir. Böylece bu araçlar, bu eğiticide oluşturulan araç zinciri yerine bu araç zinciri kullanılarak oluşturulur.
C++ araç zincirini yapılandırma
C++ araç zincirini yapılandırmak için uygulamayı tekrar tekrar derleyin ve aşağıda açıklandığı gibi her hatayı teker teker ortadan kaldırın.
Derlemeyi aşağıdaki komutla çalıştırın:
bazel build --config=clang_config //main:hello-world
.bazelrc
dosyasında--crosstool_top=//toolchain:clang_suite
öğesini belirttiğiniz için Bazel aşağıdaki hatayı bildirir:No such package `toolchain`: BUILD file not found on package path.
Workspace dizininde, paket için
toolchain
dizinini vetoolchain
dizininde boş birBUILD
dosyası oluşturun.Derlemeyi tekrar çalıştırın.
toolchain
paketi henüzclang_suite
hedefini tanımlamadığından, Bazel aşağıdaki hatayı bildirir:No such target '//toolchain:clang_suite': target 'clang_suite' not declared in package 'toolchain' defined by .../toolchain/BUILD
toolchain/BUILD
dosyasında aşağıdaki gibi boş bir dosya grubu tanımlayın:package(default_visibility = ["//visibility:public"]) filegroup(name = "clang_suite")
Derlemeyi tekrar çalıştırın. Bazel şu hatayı bildirir:
'//toolchain:clang_suite' does not have mandatory providers: 'ToolchainInfo'
Bazel,
--crosstool_top
işaretinin gerekliToolchainInfo
sağlayıcısını sağlamayan bir kuralı işaret ettiğini tespit etti. Dolayısıyla,--crosstool_top
özelliğini,ToolchainInfo
sağlayan bir kurala yönlendirmeniz gerekir. Bu,cc_toolchain_suite
kuralıdır.toolchain/BUILD
dosyasında, boş dosya grubunu aşağıdakiyle değiştirin:cc_toolchain_suite( name = "clang_suite", toolchains = { "k8": ":k8_toolchain", }, )
toolchains
özelliği,--cpu
(ve belirtildiğinde--compiler
) değerlerini otomatik olarakcc_toolchain
ile eşler. Henüzcc_toolchain
hedefi tanımlamadınız ve Bazel kısa süre içinde bundan şikayet edecek.Derlemeyi tekrar çalıştırın. Bazel şu hatayı bildirir:
Rule '//toolchain:k8_toolchain' does not exist
Şimdi
cc_toolchain_suite.toolchains
özelliğindeki her değer içincc_toolchain
hedefleri tanımlamanız gerekiyor.toolchain/BUILD
dosyasına aşağıdakileri ekleyin: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ı bildirir:
Rule '//toolchain:k8_toolchain_config' does not exist
Daha sonra,
toolchain/BUILD
dosyasına bir ":k8_toolchain_config" hedefi ekleyin:filegroup(name = "k8_toolchain_config")
Derlemeyi tekrar çalıştırın. Bazel şu hatayı bildirir:
'//toolchain:k8_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.bzl
dosyası oluşturarak Bazel'aCcToolchainConfigInfo
sağ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()
gerekliCcToolchainConfigInfo
sağlayıcısını oluşturur.cc_toolchain_config
kuralını kullanmak için paket ifadesinin hemen altındakitoolchain/BUILD
öğesine bir yük ifadesi ekleyin:load(":cc_toolchain_config.bzl", "cc_toolchain_config")
"k8_toolchain_config" dosya grubunu da bir
cc_toolchain_config
kuralı açıklamasıyla değiştirin:cc_toolchain_config(name = "k8_toolchain_config")
Derlemeyi tekrar çalıştırın. Bazel şu hatayı bildirir:
.../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 olsa da gerekli derleme işlemlerini tamamlamak için hangi araçları kullanacağını hâlâ bilmiyor. Bazel'a hangi araçların kullanılacağını bildirmek için Starlark kural uygulamasını değiştirirsiniz. Bunun için
@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl
öğesinden tool_path() oluşturucusuna 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", 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
değerlerinin sisteminiz için doğru yollar olduğundan emin olun.Derlemeyi tekrar çalıştırın. Bazel şu hatayı bildirir:
..../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'ın eklenen başlıkları nerede arayacağını bilmesi gerekir. Bu sorunu çözmenin
cc_binary
içinincludes
özelliğini kullanmak gibi birden fazla yolu vardır. Ancak burada bu çözümcc_common.create_cc_toolchain_config_info
cxx_builtin_include_directories
parametresiyle araç zinciri düzeyinde çözülmüştür. Farklı birclang
sürümü kullanıyorsanız dahil etme yolunun farklı olacağını unutmayın. Bu yollar, dağıtıma bağlı olarak da farklılık gösterebilir.Döndürülen
toolchain/cc_toolchain_config.bzl
değerini aşağıdaki gibi değiştirin: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ırın. Aşağıdaki gibi 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++ standart kitaplığının bulunmaması ve simgelerini bulamamasıdır. Bunu çözmenin birçok yolu vardır. Örneğin,
cc_binary
içinlinkopts
özelliğini kullanabilirsiniz. Burada sorun, araç zincirini kullanan herhangi bir hedefin bu işareti belirtmek zorunda kalmaması sağlanarak çözülür.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 son olarak derlenir.
Çalışmanızı inceleyin
Bu eğiticide temel bir C++ araç zincirinin nasıl yapılandırılacağını öğrendiniz ancak araç zincirleri bu basit örnekten daha güçlüdür.
Temel çıkarımlar şunlardır:
- Komut satırında, cc_toolchain_suite
öğesine işaret etmesi gereken bir --crosstool_top
işareti belirtmeniz gerekir
- .bazelrc
dosyasını kullanarak belirli bir yapılandırma için kısayol oluşturabilirsiniz
- cc_toolchain_suite, farklı CPU'lar ve derleyiciler için cc_toolchains
listesini listeleyebilir. Ayırt etmek için --cpu
gibi komut satırı işaretlerini kullanabilirsiniz.
- Araç zincirine, araçların bulunduğu yerleri bildirmeniz gerekir. Bu eğitimde, araçlara sistemden erişebileceğiniz basitleştirilmiş bir sürüm bulunmaktadır. Daha bağımsız bir yaklaşım istiyorsanız çalışma alanları hakkında buradan bilgi edinebilirsiniz. Araçlarınız farklı bir çalışma alanından gelebilir ve bu araçların dosyalarını, compiler_files
gibi özelliklere hedef bağımlılıklarla cc_toolchain
tarafından kullanılabilir hale getirmeniz gerekir. tool_paths
öğesinin de değiştirilmesi gerekiyor.
- Hangi işaretlerin farklı işlemlere (bağlantı oluşturma veya diğer işlem türleri) iletilmesi gerektiğini özelleştirmek için özellikler oluşturabilirsiniz.
Daha fazla bilgi
Daha fazla bilgi için C++ araç zinciri yapılandırması bölümüne bakın