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

किसी समस्या की शिकायत करें सोर्स देखें रात · 7.3 · 7.2 · 7.1 · 7.0 · 6.5

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

आप इन चीज़ों के बारे में जानेंगे

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

  • बिल्ड एनवायरमेंट को सेट अप करें
  • टूलचेन रिज़ॉल्यूशन को डीबग करने के लिए, --toolchain_resolution_debug का इस्तेमाल करना
  • C++ टूलचेन कॉन्फ़िगर करना
  • Starlark का ऐसा नियम बनाएं जो ज़्यादा जानकारी देता हो cc_toolchain के लिए कॉन्फ़िगरेशन करें, ताकि Basel ऐप्लिकेशन बना सके clang के साथ
  • चलाकर, C++ बाइनरी बनाएं Linux मशीन पर bazel build //main:hello-world
  • bazel build //main:hello-world --platforms=//:android_x86_64 चलाकर, Android के लिए बाइनरी को क्रॉस-कंपाइल करें

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

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

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

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

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

  2. रूट फ़ोल्डर में कोई खाली WORKSPACE फ़ाइल जोड़ें.

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

    load("@rules_cc//cc:defs.bzl", "cc_binary")
    
    cc_binary(
        name = "hello-world",
        srcs = ["hello-world.cc"],
    )
    

    हालांकि, बिल्ड के दौरान Basel में C++ में लिखे गए कई इंटरनल टूल इस्तेमाल किए जाते हैं, जैसे कि process-wrapper के तौर पर, पहले से मौजूद डिफ़ॉल्ट C++ टूलचेन होस्ट प्लैटफ़ॉर्म पर. इससे इन इंटरनल टूल को इस ट्यूटोरियल में बनाए गए टूल की चेन. इस वजह से, cc_binary टारगेट को डिफ़ॉल्ट टूलचेन के साथ भी बनाया गया है.

  4. बिल्ड को नीचे दिए गए निर्देश के साथ चलाएं:

    bazel build //main:hello-world
    

    WORKSPACE में रजिस्टर किए गए किसी भी टूलचेन के बिना, बिल्ड सफल हो जाता है.

    यह देखने के लिए कि आगे क्या है, चलाएं:

    bazel build //main:hello-world --toolchain_resolution_debug='@bazel_tools//tools/cpp:toolchain_type'
    
    INFO: ToolchainResolution: Target platform @@local_config_platform//:host: Selected execution platform @@local_config_platform//:host, type @@bazel_tools//tools/cpp:toolchain_type -> toolchain @@bazel_tools+cc_configure_extension+local_config_cc//:cc-compiler-k8
    

    --platforms तय किए बिना, Basel ने इसके लिए टारगेट बनाया @local_config_platform//:host इसका इस्तेमाल कर रहे हैं @bazel_tools//cc_configure_extension/local_config_cc//:cc-compiler-k8

C++ टूलचेन कॉन्फ़िगर करना

C++ टूलचेन को कॉन्फ़िगर करने के लिए, बार-बार ऐप्लिकेशन बनाएं और उन्हें गड़बड़ी को एक-एक करके ठीक करें. इसके बारे में नीचे बताया गया है.

इसे clang version 9.0.1 भी माना जा सकता है, लेकिन जानकारी में सिर्फ़ बदलाव होना चाहिए क्लैंग के अलग-अलग वर्शन के बीच थोड़ा-बहुत.

  1. 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",
        ],
    )
    

    इसके बाद, WORKSPACE के साथ टूलचेन को रजिस्टर करें. इसके लिए, इनकी मदद लें:

    register_toolchains(
        "//toolchain:cc_toolchain_for_linux_x86_64"
    )
    

    यह चरण cc_toolchain तय करता है और इसेtoolchain होस्ट कॉन्फ़िगरेशन.

  2. बिल्ड को फिर से चलाएं. क्योंकि toolchain पैकेज अभी तक linux_x86_64_toolchain_config टारगेट पर, बेज़ल यह गड़बड़ी दिखाता है:

    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.
    
  3. toolchain/BUILD फ़ाइल में, किसी खाली फ़ाइलग्रुप को इस तरह तय करें:

    package(default_visibility = ["//visibility:public"])
    
    filegroup(name = "linux_x86_64_toolchain_config")
    
  4. बिल्ड को फिर से चलाएं. बेज़ल यह गड़बड़ी दिखाता है:

    '//toolchain:linux_x86_64_toolchain_config' does not have mandatory providers: 'CcToolchainConfigInfo'.
    

    CcToolchainConfigInfo ऐसी सेवा देने वाली कंपनी है जिसका इस्तेमाल आप कॉन्फ़िगर करने के लिए करते हैं आपके C++ टूलचेन का इस्तेमाल कर सकते हैं. इस गड़बड़ी को ठीक करने के लिए, Starlark नियम बनाएं जो बेज़ल को 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")
    
  5. बिल्ड को फिर से चलाएं. बेज़ल यह गड़बड़ी दिखाता है:

    .../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`
    

    यहां तक, Basel के पास कोड बनाने की कोशिश करने के लिए पूरी जानकारी है, लेकिन उसे अब भी यह नहीं पता है कि ज़रूरी बिल्ड को पूरा करने के लिए कौनसे टूल का इस्तेमाल करना चाहिए कार्रवाइयां. बेज़ल को यह बताने के लिए कि आपको Starlark नियम लागू करने के तरीके में बदलाव करना होगा का इस्तेमाल करना है. इसके लिए, आपको इस प्रॉपर्टी से Tools_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 सही पाथ हैं को भी बनाए रखता है.

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

    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'
      ...
    

    Basel को यह जानने की ज़रूरत है कि शामिल किए गए हेडर को कहां खोजना है. यहां हैं इसे हल करने के कई तरीके हैं, जैसे कि includes एट्रिब्यूट का इस्तेमाल करना cc_binary, लेकिन यहां इसे हल करने के लिए टूलचेन लेवल पर 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,
    )
    
  7. बिल्ड कमांड को फिर से चलाएं, आपको इस तरह की गड़बड़ी दिखेगी:

    /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],
    )
    
  8. bazel build //main:hello-world को चलाने पर, आखिर में होस्ट के लिए बाइनरी बननी चाहिए.

  9. toolchain/BUILD में, cc_toolchain_config, cc_toolchain, और toolchain टारगेट और linux_x86_64 को android_x86_64टारगेट से बदलें नाम.

    WORKSPACE में, Android के लिए टूलचेन को रजिस्टर करें

    register_toolchains(
        "//toolchain:cc_toolchain_for_linux_x86_64",
        "//toolchain:cc_toolchain_for_android_x86_64"
    )
    
  10. Android के लिए बाइनरी बनाने के लिए, bazel build //main:hello-world --android_platforms=//toolchain:android_x86_64 चलाएं.

Linux और Android में C++ टूलचेन कॉन्फ़िगरेशन अलग-अलग होने चाहिए. आपने लोगों तक पहुंचाया मुफ़्त में या तो अंतर के लिए मौजूदा cc_toolchain_config में बदलाव कर सकता है या अलग-अलग क्वेरी के लिए एक अलग नियम (जैसे, CcToolchainConfigInfo कंपनी) बनाएं प्लैटफ़ॉर्म.

अपने काम की समीक्षा करें

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

सीखने लायक ज़रूरी बातें:

  • आपको इसके लिए कमांड लाइन में, मेल खाने वाले platforms फ़्लैग की जानकारी देनी होगी तो एक जैसी कंस्ट्रेंट वैल्यू के लिए टूलचेन को हल करें. दस्तावेज़ में किसी खास भाषा के कॉन्फ़िगरेशन फ़्लैग के बारे में ज़्यादा जानकारी दी गई है.
  • आपको टूलचेन को यह बताना होगा कि टूल कहां उपलब्ध हैं. इस ट्यूटोरियल में एक सरल वर्शन है, जहां सिस्टम से टूल ऐक्सेस किए जाते हैं. अगर आपने की है, तो ज़्यादा सुरक्षित तरीके से काम करने में आपकी दिलचस्पी है. फ़ाइल फ़ोल्डर. आपके टूल और आपको उनकी फ़ाइलें उपलब्ध करानी होंगी cc_toolchain तक, टारगेट डिपेंडेंसी के साथ एट्रिब्यूट पर निर्भर करता है. जैसे compiler_files. tool_paths को भी बदलना होगा.
  • किन फ़्लैग को भेजना है, यह तय करने के लिए आप सुविधाएं बना सकते हैं चाहे वह लिंक करना हो या कोई अन्य कार्रवाई.

इसके बारे में और पढ़ें

ज़्यादा जानकारी के लिए, यह देखें C++ टूलचेन कॉन्फ़िगरेशन