Bazel টিউটোরিয়াল: C++ টুলচেইন কনফিগার করুন

এই টিউটোরিয়ালটি একটি প্রকল্পের জন্য কিভাবে C++ টুলচেইন কনফিগার করতে হয় তা বর্ণনা করার জন্য একটি উদাহরণের দৃশ্য ব্যবহার করে। এটি একটি উদাহরণ C++ প্রকল্পের উপর ভিত্তি করে যা clang ব্যবহার করে ত্রুটি-মুক্ত তৈরি করে।

আপনি কি শিখবেন

এই টিউটোরিয়ালে আপনি শিখবেন কিভাবে:

  • বিল্ড পরিবেশ সেট আপ করুন
  • C++ টুলচেইন কনফিগার করুন
  • একটি স্টারলার্ক নিয়ম তৈরি করুন যা cc_toolchain এর জন্য অতিরিক্ত কনফিগারেশন প্রদান করে যাতে Bazel clang সহ অ্যাপ্লিকেশনটি তৈরি করতে পারে
  • একটি লিনাক্স মেশিনে bazel build --config=clang_config //main:hello-world চালিয়ে প্রত্যাশিত ফলাফল নিশ্চিত করুন
  • C++ অ্যাপ্লিকেশন তৈরি করুন

তুমি শুরু করার আগে

বিল্ড পরিবেশ সেট আপ করুন

এই টিউটোরিয়ালটি ধরে নেয় আপনি লিনাক্সে আছেন এবং সফলভাবে C++ অ্যাপ্লিকেশন তৈরি করেছেন এবং উপযুক্ত টুলিং এবং লাইব্রেরি ইনস্টল করেছেন। টিউটোরিয়ালটিতে clang version 9.0.1 ব্যবহার করা হয়েছে, যা আপনি আপনার সিস্টেমে ইনস্টল করতে পারেন।

নিম্নলিখিত হিসাবে আপনার বিল্ড পরিবেশ সেট আপ করুন:

  1. আপনি যদি ইতিমধ্যে এটি না করে থাকেন তবে Bazel 0.23 বা তার পরে ডাউনলোড এবং ইনস্টল করুন

  2. GitHub থেকে উদাহরণ C++ প্রকল্পটি ডাউনলোড করুন এবং আপনার স্থানীয় মেশিনে একটি খালি ডিরেক্টরিতে রাখুন।

  3. main/BUILD ফাইলে নিম্নলিখিত cc_binary টার্গেট যোগ করুন:

    cc_binary(
        name = "hello-world",
        srcs = ["hello-world.cc"],
    )
    
  4. --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-র জন্য বিভিন্ন টুলচেন তালিকাভুক্ত করতে পারে, এবং সেই কারণেই এটি পতাকা --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. আবার বিল্ড চালান. 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 শীঘ্রই এটি সম্পর্কে অভিযোগ করবে।

  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. আবার বিল্ড চালান. Bazel নিম্নলিখিত ত্রুটি নিক্ষেপ করে:

    Rule '//toolchain:k8_toolchain_config' does not exist
    

    এরপরে, toolchain/BUILD ফাইলে একটি ":k8_toolchain_config" টার্গেট যোগ করুন:

    filegroup(name = "k8_toolchain_config")
    
  6. আবার বিল্ড চালান. Bazel নিম্নলিখিত ত্রুটি নিক্ষেপ করে:

    '//toolchain:k8_toolchain_config' does not have mandatory providers:
    'CcToolchainConfigInfo'
    

    CcToolchainConfigInfo হল একটি প্রদানকারী যা আপনি আপনার C++ টুলচেইন কনফিগার করতে ব্যবহার করেন। এই ত্রুটিটি ঠিক করতে, একটি স্টারলার্ক নিয়ম তৈরি করুন যা নিম্নোক্ত বিষয়বস্তু সহ একটি 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 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_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. আবার বিল্ড চালান. 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,
     )
    
  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_filestool_paths পরিবর্তন করা দরকার। - বিভিন্ন অ্যাকশনে কোন ফ্ল্যাগগুলি পাস করা উচিত তা কাস্টমাইজ করার জন্য আপনি বৈশিষ্ট্যগুলি তৈরি করতে পারেন, এটি লিঙ্কিং বা অন্য কোনও ধরণের অ্যাকশন হোক।

আরও পড়া

আরো বিস্তারিত জানার জন্য, C++ টুলচেন কনফিগারেশন দেখুন