इस ट्यूटोरियल में, किसी प्रोजेक्ट के लिए C++ टूलचेन को कॉन्फ़िगर करने का तरीका बताने के लिए, एक उदाहरण दिया गया है.
आपको क्या सीखने को मिलेगा
इस ट्यूटोरियल में, आपको ये चीज़ें सीखने को मिलेंगी:
- बिल्ड एनवायरमेंट सेट अप करना
- टूलचेन रिज़ॉल्यूशन को डीबग करने के लिए,
--toolchain_resolution_debugका इस्तेमाल करना - C++ टूलचेन को कॉन्फ़िगर करना
- एक Starlark नियम बनाना. इससे
cc_toolchainके लिए अतिरिक्त कॉन्फ़िगरेशन मिलता है, ताकि Bazelclangकी मदद से ऐप्लिकेशन बना सके - Linux मशीन पर
bazel build //main:hello-worldचलाकर, C++ बाइनरी बनाना bazel build //main:hello-world --platforms=//:android_x86_64चलाकर, Android के लिए बाइनरी को क्रॉस-कंपाइल करना
शुरू करने से पहले
इस ट्यूटोरियल में यह माना गया है कि आप Linux का इस्तेमाल कर रहे हैं और आपने C++ ऐप्लिकेशन सफलतापूर्वक बनाए हैं. साथ ही, आपने ज़रूरी टूल और लाइब्रेरी इंस्टॉल की हैं. इस ट्यूटोरियल में clang version 16 का इस्तेमाल किया गया है. इसे अपने सिस्टम पर इंस्टॉल किया जा सकता है.
बिल्ड एनवायरमेंट सेट अप करना
अपना बिल्ड एनवायरमेंट इस तरह सेट अप करें:
अगर आपने अब तक ऐसा नहीं किया है, तो Bazel 7.0.2 या इसके बाद का वर्शन डाउनलोड और इंस्टॉल करें.
रूट फ़ोल्डर में, खाली
MODULE.bazelफ़ाइल जोड़ें.main/BUILDफ़ाइल में, यहcc_binaryटारगेट जोड़ें:cc_binary( name = "hello-world", srcs = ["hello-world.cc"], )Bazel, बिल्ड के दौरान C++ में लिखे गए कई इंटरनल टूल का इस्तेमाल करता है. जैसे,
process-wrapper. इसलिए, होस्ट प्लैटफ़ॉर्म के लिए पहले से मौजूद डिफ़ॉल्ट C++ टूलचेन तय किया जाता है. इससे ये इंटरनल टूल, इस ट्यूटोरियल में बनाए गए टूलचेन का इस्तेमाल करके बिल्ड कर पाते हैं. इसलिए,cc_binaryटारगेट को डिफ़ॉल्ट टूलचेन के साथ भी बनाया जाता है.इस कमांड से बिल्ड चलाएं:
bazel build //main:hello-worldMODULE.bazelमें कोई टूलचेन रजिस्टर न होने पर भी, बिल्ड पूरा हो जाता है.ज़्यादा जानकारी के लिए, यह कमांड चलाएं:
bazel build //main:hello-world --toolchain_resolution_debug='@bazel_tools//tools/cpp:toolchain_type' INFO: ToolchainResolution: Target platform @@platforms//host:host: Selected execution platform @@platforms//host:host, type @@bazel_tools//tools/cpp:toolchain_type -> toolchain @@bazel_tools+cc_configure_extension+local_config_cc//:cc-compiler-k8--platformsतय किए बिना, Bazel@platforms//hostके लिए टारगेट को@bazel_tools+cc_configure_extension+local_config_cc//:cc-compiler-k8का इस्तेमाल करके बनाता है.
C++ टूलचेन को कॉन्फ़िगर करना
C++ टूलचेन को कॉन्फ़िगर करने के लिए, ऐप्लिकेशन को बार-बार बनाएं और एक-एक करके हर गड़बड़ी को ठीक करें. इसके लिए, यहां दिया गया तरीका अपनाएं.
इसमें यह भी माना गया है कि clang version 9.0.1 का इस्तेमाल किया जा रहा है. हालांकि, clang के अलग-अलग वर्शन के बीच, जानकारी में मामूली बदलाव ही होता है.
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", ], )इसके बाद, ज़रूरी डिपेंडेंसी जोड़ें और
MODULE.bazelके साथ टूलचेन रजिस्टर करें. इसके लिए, यह कोड जोड़ें:bazel_dep(name = "platforms", version = "0.0.10") register_toolchains( "//toolchain:cc_toolchain_for_linux_x86_64" )इस चरण में,
cc_toolchainतय किया जाता है और इसे होस्ट कॉन्फ़िगरेशन के लिएtoolchainटारगेट से बाइंड किया जाता है.बिल्ड को फिर से चलाएं.
toolchainपैकेज में अब तकlinux_x86_64_toolchain_configटारगेट तय नहीं किया गया है. इसलिए, Bazel यह गड़बड़ी दिखाता है: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.toolchain/BUILDफ़ाइल में, खाली फ़ाइल ग्रुप को इस तरह तय करें:package(default_visibility = ["//visibility:public"]) filegroup(name = "linux_x86_64_toolchain_config")बिल्ड को फिर से चलाएं. Bazel यह गड़बड़ी दिखाता है:
'//toolchain:linux_x86_64_toolchain_config' does not have mandatory providers: 'CcToolchainConfigInfo'.CcToolchainConfigInfoएक ऐसा प्रोवाइडर है जिसका इस्तेमाल, C++ टूलचेन को कॉन्फ़िगर करने के लिए किया जाता है. इस गड़बड़ी को ठीक करने के लिए, एक Starlark नियम बनाएं. इससे Bazel कोCcToolchainConfigInfoमिलता है. इसके लिए,toolchain/cc_toolchain_config.bzlफ़ाइल बनाएं और इसमें यह कॉन्टेंट जोड़ें: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()से, ज़रूरी प्रोवाइडरCcToolchainConfigInfoबनता है.cc_toolchain_configनियम का इस्तेमाल करने के लिए,toolchain/BUILDमें पैकेज स्टेटमेंट के ठीक नीचे, लोड स्टेटमेंट जोड़ें:load(":cc_toolchain_config.bzl", "cc_toolchain_config")साथ ही, "linux_x86_64_toolchain_config" फ़ाइल ग्रुप को,
cc_toolchain_configनियम के एलान से बदलें:cc_toolchain_config(name = "linux_x86_64_toolchain_config")बिल्ड को फिर से चलाएं. Bazel यह गड़बड़ी दिखाता है:
.../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`इस समय, Bazel के पास कोड बनाने की कोशिश करने के लिए ज़रूरी जानकारी होती है. हालांकि, उसे अब भी यह नहीं पता होता कि ज़रूरी बिल्ड ऐक्शन पूरे करने के लिए किन टूल का इस्तेमाल करना है. Bazel को यह बताने के लिए कि किन टूल का इस्तेमाल करना है, Starlark नियम के लागू करने के तरीके में बदलाव करें. इसके लिए, आपको
tool_path()कंस्ट्रक्टर की ज़रूरत होगी@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और/usr/bin/ldआपके सिस्टम के लिए सही पाथ हों.बिल्ड को फिर से चलाएं. Bazel यह गड़बड़ी दिखाता है:
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 को यह पता होना चाहिए कि शामिल किए गए हेडर कहां खोजने हैं. इसे ठीक करने के कई तरीके हैं. जैसे,
cc_binaryकेincludesएट्रिब्यूट का इस्तेमाल करना. हालांकि, यहां इसे टूलचेन लेवल पर ठीक किया गया है. इसके लिए,cxx_builtin_include_directoriesकेcc_common.create_cc_toolchain_config_infoपैरामीटर का इस्तेमाल किया गया है. ध्यान रखें कि अगरclangका कोई दूसरा वर्शन इस्तेमाल किया जा रहा है, तो शामिल करने का पाथ अलग होगा. डिस्ट्रिब्यूशन के हिसाब से भी ये पाथ अलग-अलग हो सकते हैं.toolchain/cc_toolchain_config.bzlमें, रिटर्न वैल्यू में बदलाव करें, ताकि यह इस तरह दिखे: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, )बिल्ड कमांड को फिर से चलाएं. आपको इस तरह की गड़बड़ी दिखेगी:
/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'इसकी वजह यह है कि लिंकर में C++ स्टैंडर्ड लाइब्रेरी मौजूद नहीं है और उसे इसके सिंबल नहीं मिल रहे हैं. इसे ठीक करने के कई तरीके हैं. जैसे,
cc_binaryकेlinkoptsएट्रिब्यूट का इस्तेमाल करना. यहां इसे इस तरह ठीक किया गया है कि टूलचेन का इस्तेमाल करने वाले किसी भी टारगेट के लिए, इस फ़्लैग को तय न करना पड़े.toolchain/cc_toolchain_config.bzlमें यह कोड कॉपी करें:# 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], )bazel build //main:hello-worldचलाने पर, इसे होस्ट के लिए बाइनरी को सफलतापूर्वक बिल्ड करना चाहिए.toolchain/BUILDमें,cc_toolchain_config,cc_toolchain, औरtoolchainटारगेट कॉपी करें. साथ ही, टारगेट के नामों मेंlinux_x86_64कोandroid_x86_64से बदलें.MODULE.bazelमें, Android के लिए टूलचेन रजिस्टर करेंregister_toolchains( "//toolchain:cc_toolchain_for_linux_x86_64", "//toolchain:cc_toolchain_for_android_x86_64" )Android के लिए बाइनरी बनाने के लिए,
bazel build //main:hello-world --android_platforms=//toolchain:android_x86_64चलाएं.
असल में, Linux और Android के लिए C++ टूलचेन कॉन्फ़िगरेशन अलग-अलग होने चाहिए. अंतर के लिए, मौजूदा cc_toolchain_config में बदलाव किया जा सकता है या अलग-अलग प्लैटफ़ॉर्म के लिए अलग-अलग नियम बनाए जा सकते हैं. जैसे, CcToolchainConfigInfo प्रोवाइडर.
अपने काम की समीक्षा करना
इस ट्यूटोरियल में, आपने बुनियादी C++ टूलचेन को कॉन्फ़िगर करने का तरीका सीखा. हालांकि, टूलचेन इस उदाहरण से ज़्यादा पावरफ़ुल होते हैं.
खास बातें:
- Bazel को प्लैटफ़ॉर्म पर एक जैसी कंस्ट्रेंट वैल्यू के लिए टूलचेन को रिज़ॉल्व करने के लिए, कमांड लाइन में मैच करने वाला
platformsफ़्लैग तय करना होगा. दस्तावेज़ में, भाषा के हिसाब से कॉन्फ़िगरेशन फ़्लैग के बारे में ज़्यादा जानकारी दी गई है . - आपको टूलचेन को यह बताना होगा कि टूल कहां मौजूद हैं. इस ट्यूटोरियल में, एक आसान वर्शन दिया गया है. इसमें सिस्टम से टूल ऐक्सेस किए जाते हैं. अगर आपको ज़्यादा सेल्फ-कंटेन्ड अप्रोच चाहिए, तो
बाहरी डिपेंडेंसी के बारे में पढ़ें. ऐसा हो सकता है कि आपके टूल किसी दूसरे मॉड्यूल से आएं. ऐसे में, आपको एट्रिब्यूट पर टारगेट डिपेंडेंसी के साथ, उनकी फ़ाइलें
cc_toolchainके लिए उपलब्ध करानी होंगी. जैसे,compiler_files.tool_pathsमें भी बदलाव करना होगा. - अलग-अलग कार्रवाइयों के लिए, कौनसे फ़्लैग पास किए जाने चाहिए, यह तय करने के लिए सुविधाएं बनाई जा सकती हैं. ये कार्रवाइयां, लिंकिंग या किसी अन्य तरह की कार्रवाई हो सकती हैं.
इस बारे में और पढ़ें
ज़्यादा जानकारी के लिए, C++ टूलचेन कॉन्फ़िगरेशन देखें