इस ट्यूटोरियल में, किसी प्रोजेक्ट के लिए C++ टूलचेन को कॉन्फ़िगर करने का तरीका बताने के लिए, एक उदाहरण का इस्तेमाल किया गया है. यह clang
का इस्तेमाल करके, गड़बड़ी के बिना बने उदाहरण के तौर पर दिए गए C++ प्रोजेक्ट पर आधारित है.
आपको क्या सीखने को मिलेगा
इस ट्यूटोरियल में आपको ये काम करने का तरीका पता चलेगा:
- बिल्ड एनवायरमेंट सेट अप करना
- C++ टूलचेन को कॉन्फ़िगर करना
- Starlark नियम बनाएं, जो
cc_toolchain
के लिए अतिरिक्त कॉन्फ़िगरेशन उपलब्ध कराता है, ताकि Bazelclang
की मदद से ऐप्लिकेशन बना सके - Linux मशीन पर
bazel build --config=clang_config //main:hello-world
को चलाकर, उम्मीद के मुताबिक नतीजे की पुष्टि करना - C++ ऐप्लिकेशन बनाना
शुरू करने से पहले
बिल्ड एनवायरमेंट को सेट अप करें
यह ट्यूटोरियल मानता है कि आप Linux का इस्तेमाल कर रहे हैं और आपने इसे सफलतापूर्वक बना लिया है
C++ ऐप्लिकेशन इंस्टॉल किए और ज़रूरी टूल और लाइब्रेरी इंस्टॉल कीं.
ट्यूटोरियल में clang version 9.0.1
का इस्तेमाल किया गया है. इसे अपने सिस्टम पर इंस्टॉल किया जा सकता है.
बिल्ड एनवायरमेंट को इस तरह सेट अप करें:
अगर आपने पहले से ऐसा नहीं किया है, तो Basel 0.23 या इसके बाद का वर्शन डाउनलोड और इंस्टॉल करें.
Google News ऐप्लिकेशन C++ प्रोजेक्ट का उदाहरण GitHub से कॉपी करें और उसे अपने कंप्यूटर पर किसी खाली डायरेक्ट्री में डालें.
main/BUILD
फ़ाइल में यहcc_binary
टारगेट जोड़ें:cc_binary( name = "hello-world", srcs = ["hello-world.cc"], )
फ़ाइल फ़ोल्डर की डायरेक्ट्री के रूट में एक
.bazelrc
फ़ाइल बनाएं.--config
फ़्लैग का इस्तेमाल चालू करने के लिए कॉन्टेंट:# 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
एंट्री के लिए, कमांड लाइन फ़्लैग
--config={config_name}
उस खास फ़्लैग से जुड़ा है. यहां जाएं:
इस्तेमाल किए गए फ़्लैग के लिए दस्तावेज़:
crosstool_top
cpu
और
host_crosstool_top
.
जब आपने अपना टारगेट बनाया हो
bazel build --config=clang_config //main:hello-world
की सदस्यता के साथ, Ba बैंक आपकी
इंडस्ट्री के विशेषज्ञों की मदद से
cc_toolchain_suite
//toolchain:clang_suite
. सुइट अलग सूची में हो सकता है
टूलचेन का इस्तेमाल करके, कई तरह के सीपीयू इस्तेमाल किए जा सकते हैं,
और इसलिए इसे --cpu=k8
झंडे से अलग-अलग दिखाया गया है.
Bazel, बिल्ड के दौरान C++ में लिखे गए कई इंटरनल टूल का इस्तेमाल करता है. जैसे, प्रोसेस-रैपर. इसलिए, होस्ट प्लैटफ़ॉर्म के लिए पहले से मौजूद डिफ़ॉल्ट C++ टूलचेन तय किया जाता है, ताकि इन टूल को इस ट्यूटोरियल में बनाए गए टूलचेन के बजाय उस टूलचेन का इस्तेमाल करके बनाया जा सके.
C++ टूलचेन को कॉन्फ़िगर करना
C++ टूलचेन को कॉन्फ़िगर करने के लिए, बार-बार ऐप्लिकेशन बनाएं और उन्हें समस्या को एक-एक करके ठीक करें, जैसा कि नीचे बताया गया है.
इस कमांड का इस्तेमाल करके बिल्ड चलाएं:
bazel build --config=clang_config //main:hello-world
आपने
.bazelrc
फ़ाइल में--crosstool_top=//toolchain:clang_suite
तय किया है, इसलिए Bazel यह गड़बड़ी दिखाता है:No such package `toolchain`: BUILD file not found on package path.
वर्कस्पेस डायरेक्ट्री में, पैकेज के लिए
toolchain
डायरेक्ट्री बनाएं औरtoolchain
डायरेक्ट्री में एक खालीBUILD
फ़ाइल है.बिल्ड को फिर से चलाएं.
toolchain
पैकेज में अब तकclang_suite
टारगेट तय नहीं किया गया है. इसलिए, Bazel यह गड़बड़ी दिखाता है:No such target '//toolchain:clang_suite': target 'clang_suite' not declared in package 'toolchain' defined by .../toolchain/BUILD
toolchain/BUILD
फ़ाइल में, खाली फ़ाइल ग्रुप को इस तरह सेट करें:package(default_visibility = ["//visibility:public"]) filegroup(name = "clang_suite")
बिल्ड को फिर से चलाएं. बेज़ल यह गड़बड़ी दिखाता है:
'//toolchain:clang_suite' does not have mandatory providers: 'ToolchainInfo'
बेज़ल ने पाया कि
--crosstool_top
का झंडा एक नियम की ओर इशारा करता है ज़रूरीToolchainInfo
नहीं देता कंपनी. इसलिए आपको--crosstool_top
को एक ऐसे नियम की ओर इशारा करना होगा जोToolchainInfo
- यहीcc_toolchain_suite
नियम है.toolchain/BUILD
फ़ाइल में, खाली फ़ाइल ग्रुप को इनसे बदलें:cc_toolchain_suite( name = "clang_suite", toolchains = { "k8": ":k8_toolchain", }, )
toolchains
एट्रिब्यूट,--cpu
(और तय होने पर--compiler
) की वैल्यू कोcc_toolchain
पर अपने-आप मैप करता है. आपने अब तक कोईcc_toolchain
टारगेट तय नहीं किया है और Bazel जल्द ही इसकी शिकायत करेगा.बिल्ड को फिर से चलाएं. Bazel, यह गड़बड़ी दिखाता है:
Rule '//toolchain:k8_toolchain' does not exist
अब आपको
cc_toolchain_suite.toolchains
एट्रिब्यूट की हर वैल्यू के लिए,cc_toolchain
टारगेट तय करने होंगे. निम्न को इसमें जोड़ें:toolchain/BUILD
फ़ाइल: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, )
बिल्ड को फिर से चलाएं. बेज़ल यह गड़बड़ी दिखाता है:
Rule '//toolchain:k8_toolchain_config' does not exist
इसके बाद,
toolchain/BUILD
फ़ाइल में ":k8_toolchain_config" टारगेट जोड़ें:filegroup(name = "k8_toolchain_config")
बिल्ड को फिर से चलाएं. बेज़ल यह गड़बड़ी दिखाता है:
'//toolchain:k8_toolchain_config' does not have mandatory providers: 'CcToolchainConfigInfo'
CcToolchainConfigInfo
ऐसी सेवा देने वाली कंपनी है जिसका इस्तेमाल आप कॉन्फ़िगर करने के लिए करते हैं आपके C++ टूलचेन का इस्तेमाल कर सकते हैं. इस गड़बड़ी को ठीक करने के लिए, Starlark नियम बनाएं. यह नियम,CcToolchainConfigInfo
को Bazel में उपलब्ध कराएगा. इसके लिए, यहां दिए गए कॉन्टेंट वाली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
नियम का इस्तेमाल करने के लिए, एक लोड जोड़ेंtoolchains/BUILD
के लिए स्टेटमेंट:load(":cc_toolchain_config.bzl", "cc_toolchain_config")
इसके बाद, "k8_toolchain_config" को बदलें फ़ाइलग्रुप
cc_toolchain_config
नियम:cc_toolchain_config(name = "k8_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 के पास कोड बनाने की कोशिश करने के लिए ज़रूरी जानकारी है. हालांकि, उसे अब भी यह नहीं पता है कि ज़रूरी बिल्ड ऐक्शन को पूरा करने के लिए, किन टूल का इस्तेमाल करना है. आपको Starlark नियम को लागू करने के तरीके में बदलाव करना होगा, ताकि Bazel को यह बताया जा सके कि किन टूल का इस्तेमाल करना है. इसके लिए, आपको
@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl
से tool_path() कन्स्ट्रक्टर की ज़रूरत होगी:# 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
आपके सिस्टम के लिए सही पाथ हों.बिल्ड को फिर से चलाएं. बेज़ल यह गड़बड़ी दिखाता है:
..../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 को यह पता होना चाहिए कि शामिल किए गए हेडर कहां खोजने हैं. इस समस्या को हल करने के कई तरीके हैं. जैसे,
cc_binary
केincludes
एट्रिब्यूट का इस्तेमाल करना. हालांकि, यहांcc_common.create_cc_toolchain_config_info
केcxx_builtin_include_directories
पैरामीटर की मदद से, टूलचेन लेवल पर इस समस्या को हल किया गया है. ध्यान रहे कि अगर आपclang
का कोई दूसरा वर्शन इस्तेमाल कर रहे हैं, तो शामिल करने का पाथ अलग हैं. डिस्ट्रिब्यूशन के हिसाब से, ये पाथ अलग-अलग भी हो सकते हैं.toolchain/cc_toolchain_config.bzl
में रिटर्न वैल्यू को बदलकर, इसे इस तरह से दिखाएं: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, )
बिल्ड कमांड को फिर से चलाएं, आपको इस तरह की गड़बड़ी दिखेगी:
/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
एट्रिब्यूट का इस्तेमाल करना. यहाँ इसे हल किया गया है: यह पक्का करना ज़रूरी है कि टूलचेन का इस्तेमाल करने वाले किसी भी टारगेट को यह फ़्लैग.नीचे दिए गए कोड को
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", "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
चलाते हैं, तो यह होना चाहिए तैयार करने में मदद मिलेगी.
अपने काम की समीक्षा करें
इस ट्यूटोरियल में आपने C++ के एक बुनियादी टूलचेन को कॉन्फ़िगर करने का तरीका सीखा, लेकिन इस सामान्य उदाहरण से ज़्यादा असरदार टूलचेन हैं.
सीखने लायक ज़रूरी बातें:
- आपको कमांड लाइन में --crosstool_top
फ़्लैग डालना होगा
cc_toolchain_suite
पर कर्सर ले जाएं
- .bazelrc
का इस्तेमाल करके, किसी खास कॉन्फ़िगरेशन के लिए शॉर्टकट बनाया जा सकता है
फ़ाइल
- cc_toolchain_suite में अलग-अलग सीपीयू के लिए cc_toolchains
को शामिल किया जा सकता है और
कंपाइलर. फ़र्क़ करने के लिए, --cpu
जैसे कमांड लाइन फ़्लैग का इस्तेमाल किया जा सकता है.
- आपको टूलचेन को यह बताना होगा कि टूल कहां उपलब्ध हैं. इस ट्यूटोरियल में, सिस्टम से टूल ऐक्सेस करने का आसान तरीका बताया गया है. अगर आपने
की है, तो ज़्यादा सुरक्षित तरीके से काम करने में आपकी दिलचस्पी है.
फ़ाइल फ़ोल्डर यहां देखें. आपके टूल किसी दूसरे वर्कस्पेस से हो सकते हैं. ऐसे में, आपको उनकी फ़ाइलों को cc_toolchain
के लिए उपलब्ध कराना होगा. साथ ही, compiler_files
जैसे एट्रिब्यूट पर टारगेट डिपेंडेंसी भी सेट करनी होगी. tool_paths
को भी बदलना होगा.
- आपके पास यह तय करने की सुविधा होती है कि किन फ़्लैग को अलग-अलग कार्रवाइयों के लिए पास किया जाना चाहिए. भले ही, वे लिंक करने या किसी अन्य तरह की कार्रवाइयां हों.
इसके बारे में और पढ़ें
ज़्यादा जानकारी के लिए, C++ टूलचेन कॉन्फ़िगरेशन देखें