Bu eğitimde, bir proje için C++ araç zincirlerinin nasıl yapılandırılacağını açıklayan örnek bir senaryo kullanılmıştır. clang
kullanarak hatasız derleme yapan örnek bir C++ projesine dayanır.
Neler öğreneceksiniz?
Bu eğitimde şunları öğreneceksiniz:
- Derleme ortamını ayarlama
- C++ araç zincirini yapılandırma
- Bazel'in uygulamayı
clang
ile derleyebilmesi içincc_toolchain
için ek yapılandırma sağlayan bir Starlark kuralı oluşturun - Bir Linux makinesinde
bazel build --config=clang_config //main:hello-world
çalıştırarak beklenen sonucu onaylayın - C++ uygulamasını derleme
Başlamadan önce
Derleme ortamını ayarlama
Bu eğiticide, Linux kullandığınız ve C++ uygulamalarını başarıyla derlediğiniz ve uygun araçlar ile kitaplıkları yüklediğiniz varsayılır.
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ü indirip yükleyin.
GitHub'dan örnek C++ projesini indirin ve 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"], )
--config
işaretinin kullanımını etkinleştirmek için çalışma alanı dizininin kökünde 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, komut satırı işareti
--config={config_name}
bu belirli işaretle ilişkilendirilir. Kullanılan işaretlerle ilgili belgeleri inceleyin:
crosstool_top
,
cpu
ve
host_crosstool_top
.
bazel build --config=clang_config //main:hello-world
ile hedefinizi oluşturduğunuzda Bazel, cc_toolchain_suite'teki özel araç zincirinizi kullanır//toolchain:clang_suite
. 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 C++'ta yazılan işlem sarmalayıcı gibi birçok dahili araç kullandığından, ana makine platformu için önceden mevcut olan varsayılan C++ araç zinciri belirtilmiştir. Böylece, bu araçlar bu eğiticide oluşturulan araç yerine o araç zinciri kullanılarak oluşturulur.
C++ araç zincirini yapılandırma
C++ araç zincirini yapılandırmak için uygulamayı art arda derleyin ve her hatayı aşağıda açıklandığı gibi tek tek 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
belirttiğiniz için Bazel şu hatayı verir:No such package `toolchain`: BUILD file not found on package path.
Çalışma alanı 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 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 gerekliToolchainInfo
sağlayıcısını sağlamayan bir kuralı işaret ettiğini fark etti. Dolayısıyla,--crosstool_top
öğesiniToolchainInfo
sağlayan bir kurala yönlendirmeniz gerekir. Bucc_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 de--compiler
) değerlerini otomatik olarakcc_toolchain
ile eşler. Henüz herhangi bircc_toolchain
hedefi tanımlamadınız. Bazel bundan kısa bir süre şikayet edecek.Derlemeyi tekrar çalıştırın. Bazel şu hatayı verir:
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ğıdaki bilgileri 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ı verir:
Rule '//toolchain:k8_toolchain_config' does not exist
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ı verir:
'//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ı hazırlayarak Bazel'eCcToolchainConfigInfo
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()
, gereken sağlayıcıyı oluştururCcToolchainConfigInfo
.cc_toolchain_config
kuralını kullanmak içintoolchains/BUILD
öğesine bir yükleme ifadesi ekleyin:load(":cc_toolchain_config.bzl", "cc_toolchain_config")
Ve "k8_toolchain_config" dosya grubunu bir
cc_toolchain_config
kuralı bildirimiyle değiştirin: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 gerekli derleme işlemlerini tamamlamak için hangi araçları kullanması gerektiğini bilmiyor. Bazel'a hangi araçları kullanacağını bildirmek için Starlark kuralının uygulamasını değiştireceksiniz. Bunun için
@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl
'teki 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
yollarının sisteminiz için doğru yollar olduğundan emin olun.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. Bu sorunu çözmenin birden fazla yolu vardır. Örneğin
cc_binary
öğesininincludes
özelliğini kullanmak gibi. Ancak bu sorun,cc_common.create_cc_toolchain_config_info
değerine sahipcxx_builtin_include_directories
parametresiyle araç zinciri düzeyinde çözülür. Farklı birclang
sürümü kullanıyorsanız dahil etme yolunun farklı olacağını unutmayın. Bu yollar ayrıca dağıtıma bağlı olarak farklı olabilir.toolchain/cc_toolchain_config.bzl
içindeki döndürülen değeri 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ı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ının C++ standart kitaplığının eksik olması ve simgelerini bulamamasıdır. Bunu çözmenin birçok yolu vardır. Örneğin
cc_binary
içinlinkopts
özelliğini kullanabilirsiniz. Bu yöntemde sorun, araç zincirini kullanan herhangi bir hedefin bu işareti belirtmek zorunda kalmamasıyla çö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 nihayetinde uygulama 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:
- 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
listeleyebilir. 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ğ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
üzerinde kullanılabilir hale getirmeniz gerekir. tool_paths
değerinin de değiştirilmesi gerekir.
- Bağlantı oluşturma veya başka bir işlem türü gibi farklı işlemlere hangi işaretlerin 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