Bazel ट्यूटोरियल: C++ टूलचेन कॉन्फ़िगर करें

किसी समस्या की शिकायत करें सोर्स देखें रात · 7.4 को अपनाएं. 7.3 · 7.2 · 7.1 · 7.0 · 6.5

इस ट्यूटोरियल में, किसी प्रोजेक्ट के लिए C++ टूलचेन को कॉन्फ़िगर करने का तरीका बताने के लिए, एक उदाहरण का इस्तेमाल किया गया है. यह clang का इस्तेमाल करके, गड़बड़ी के बिना बने उदाहरण के तौर पर दिए गए C++ प्रोजेक्ट पर आधारित है.

आपको क्या सीखने को मिलेगा

इस ट्यूटोरियल में आपको ये काम करने का तरीका पता चलेगा:

  • बिल्ड एनवायरमेंट सेट अप करना
  • C++ टूलचेन को कॉन्फ़िगर करना
  • Starlark नियम बनाएं, जो cc_toolchain के लिए अतिरिक्त कॉन्फ़िगरेशन उपलब्ध कराता है, ताकि Bazel clang की मदद से ऐप्लिकेशन बना सके
  • Linux मशीन पर bazel build --config=clang_config //main:hello-world को चलाकर, उम्मीद के मुताबिक नतीजे की पुष्टि करना
  • C++ ऐप्लिकेशन बनाना

शुरू करने से पहले

बिल्ड एनवायरमेंट को सेट अप करें

यह ट्यूटोरियल मानता है कि आप Linux का इस्तेमाल कर रहे हैं और आपने इसे सफलतापूर्वक बना लिया है C++ ऐप्लिकेशन इंस्टॉल किए और ज़रूरी टूल और लाइब्रेरी इंस्टॉल कीं. ट्यूटोरियल में clang version 9.0.1 का इस्तेमाल किया गया है. इसे अपने सिस्टम पर इंस्टॉल किया जा सकता है.

बिल्ड एनवायरमेंट को इस तरह सेट अप करें:

  1. अगर आपने पहले से ऐसा नहीं किया है, तो Basel 0.23 या इसके बाद का वर्शन डाउनलोड और इंस्टॉल करें.

  2. Google News ऐप्लिकेशन C++ प्रोजेक्ट का उदाहरण GitHub से कॉपी करें और उसे अपने कंप्यूटर पर किसी खाली डायरेक्ट्री में डालें.

  3. main/BUILD फ़ाइल में यह cc_binary टारगेट जोड़ें:

    cc_binary(
        name = "hello-world",
        srcs = ["hello-world.cc"],
    )
    
  4. फ़ाइल फ़ोल्डर की डायरेक्ट्री के रूट में एक .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++ टूलचेन को कॉन्फ़िगर करने के लिए, बार-बार ऐप्लिकेशन बनाएं और उन्हें समस्या को एक-एक करके ठीक करें, जैसा कि नीचे बताया गया है.

  1. इस कमांड का इस्तेमाल करके बिल्ड चलाएं:

    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 फ़ाइल है.

  2. बिल्ड को फिर से चलाएं. 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")
    
  3. बिल्ड को फिर से चलाएं. बेज़ल यह गड़बड़ी दिखाता है:

    '//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 जल्द ही इसकी शिकायत करेगा.

  4. बिल्ड को फिर से चलाएं. 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,
    )
    
  5. बिल्ड को फिर से चलाएं. बेज़ल यह गड़बड़ी दिखाता है:

    Rule '//toolchain:k8_toolchain_config' does not exist
    

    इसके बाद, toolchain/BUILD फ़ाइल में ":k8_toolchain_config" टारगेट जोड़ें:

    filegroup(name = "k8_toolchain_config")
    
  6. बिल्ड को फिर से चलाएं. बेज़ल यह गड़बड़ी दिखाता है:

    '//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")
    
  7. बिल्ड को फिर से चलाएं. 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 आपके सिस्टम के लिए सही पाथ हों.

  8. बिल्ड को फिर से चलाएं. बेज़ल यह गड़बड़ी दिखाता है:

     ..../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,
     )
    
  9. बिल्ड कमांड को फिर से चलाएं, आपको इस तरह की गड़बड़ी दिखेगी:

    /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],
      )
    
  10. अगर आप 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++ टूलचेन कॉन्फ़िगरेशन देखें