इस ट्यूटोरियल में उदाहरण के तौर पर यह बताया गया है कि किसी प्रोजेक्ट के लिए C++ टूलचेन को कैसे कॉन्फ़िगर किया जाता है. यह C++ प्रोजेक्ट
पर आधारित है, जो clang
का इस्तेमाल करके गड़बड़ी के बिना काम करता है.
आप इन चीज़ों के बारे में जानेंगे
इस ट्यूटोरियल में, यह जाना जा सकता है कि:
- बिल्ड एनवायरमेंट को सेट अप करना
- C++ टूलचेन कॉन्फ़िगर करें
- Starlark नियम बनाएं जो
cc_toolchain
के लिए अतिरिक्त कॉन्फ़िगरेशन देता हो, ताकि Bazel,clang
के साथ ऐप्लिकेशन बना सके - Linux मशीन पर
bazel build --config=clang_config //main:hello-world
चलाकर, अनुमानित नतीजे की पुष्टि करें - C++ ऐप्लिकेशन बनाएं
शुरू करने से पहले
बिल्ड एनवायरमेंट को सेट अप करना
यह ट्यूटोरियल यह मानता है कि आप Linux का इस्तेमाल कर रहे हैं और आपने C++ ऐप्लिकेशन बना लिए हैं और ज़रूरी टूल और लाइब्रेरी इंस्टॉल कर ली हैं.
यह ट्यूटोरियल clang version 9.0.1
का इस्तेमाल करता है, जिसे अपने सिस्टम पर इंस्टॉल किया जा सकता है.
अपने बिल्ड एनवायरमेंट को इस तरह सेट अप करें:
अगर आपने पहले से ऐसा नहीं किया है, तो Bzel 0.23 या इसके बाद का वर्शन डाउनलोड करके इंस्टॉल करें.
GitHub से C++ प्रोजेक्ट का उदाहरण डाउनलोड करें और उसे अपनी लोकल मशीन पर किसी खाली डायरेक्ट्री में रखें.
main/BUILD
फ़ाइल में, यहcc_binary
टारगेट जोड़ें:cc_binary( name = "hello-world", srcs = ["hello-world.cc"], )
--config
फ़्लैग का इस्तेमाल चालू करने के लिए, फ़ाइल फ़ोल्डर डायरेक्ट्री के रूट में यहां दिए गए कॉन्टेंट के साथ एक.bazelrc
फ़ाइल बनाएं:# 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
के साथ टारगेट बनाने पर, Bazel
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")
बिल्ड को फिर से चलाएं. Bazel यह गड़बड़ी दिखाता है:
'//toolchain:clang_suite' does not have mandatory providers: 'ToolchainInfo'
Bazel को पता चला कि
--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, )
बिल्ड को फिर से चलाएं. Bazel यह गड़बड़ी दिखाता है:
Rule '//toolchain:k8_toolchain_config' does not exist
इसके बाद,
toolchain/BUILD
फ़ाइल में ":k8_toolchain_config" टारगेट जोड़ें:filegroup(name = "k8_toolchain_config")
बिल्ड को फिर से चलाएं. Bazel यह गड़बड़ी दिखाता है:
'//toolchain:k8_toolchain_config' does not have mandatory providers: 'CcToolchainConfigInfo'
CcToolchainConfigInfo
एक सेवा देने वाली कंपनी है, जिसका इस्तेमाल आप अपने C++ टूलचेन को कॉन्फ़िगर करने के लिए करते हैं. इस गड़बड़ी को ठीक करने के लिए, Starlark नियम बनाएं. इस नियम के तहत, इस कॉन्टेंट वालीtoolchain/cc_toolchain_config.bzl
फ़ाइल बनाकर, Bazel कोCcToolchainConfigInfo
मिलेगा: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
से टूल_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
आपके सिस्टम के लिए सही पाथ हैं.बिल्ड को फिर से चलाएं. Bazel यह गड़बड़ी दिखाता है:
..../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
जैसे कमांड लाइन फ़्लैग का इस्तेमाल किया जा सकता है.
- आपको टूलचेन को यह बताना होगा कि टूल कहां मौजूद हैं. इस ट्यूटोरियल में, एक आसान वर्शन दिया गया है, जिसमें सिस्टम से टूल ऐक्सेस किए जा सकते हैं. अगर आपको अपने काम को बेहतर तरीके से पूरा करना है, तो फ़ाइल फ़ोल्डर के बारे में यहां पढ़ें. आपके टूल किसी दूसरे फ़ाइल फ़ोल्डर से आ सकते हैं. ऐसा हो सकता है कि आपको उनकी फ़ाइलें, compiler_files
जैसे एट्रिब्यूट के हिसाब से टारगेट डिपेंडेंसी के साथ cc_toolchain
पर उपलब्ध करानी हों. tool_paths
को भी बदलना होगा.
- आपके पास यह तय करने के लिए सुविधाएं बनाने का विकल्प है कि अलग-अलग कार्रवाइयों के लिए कौनसे फ़्लैग भेजे जाएं.
यह लिंक करने या दूसरी तरह की कोई कार्रवाई हो सकती है.
इसके बारे में और पढ़ें
ज़्यादा जानकारी के लिए, C++ टूलचेन कॉन्फ़िगरेशन देखें