BazelCon 2022 16-17 নভেম্বর নিউ ইয়র্ক এবং অনলাইনে আসছে।
নিবন্ধন আজ!

কনফিগারযোগ্য বিল্ড বৈশিষ্ট্য

সেভ করা পৃষ্ঠা গুছিয়ে রাখতে 'সংগ্রহ' ব্যবহার করুন আপনার পছন্দ অনুযায়ী কন্টেন্ট সেভ করুন ও সঠিক বিভাগে রাখুন।

কনফিগারযোগ্য অ্যাট্রিবিউট , সাধারণত Select select() নামে পরিচিত, একটি Bazel বৈশিষ্ট্য যা ব্যবহারকারীদের কমান্ড লাইনে বিল্ড রুল অ্যাট্রিবিউটের মান টগল করতে দেয়।

এটি ব্যবহার করা যেতে পারে, উদাহরণস্বরূপ, একটি মাল্টিপ্ল্যাটফর্ম লাইব্রেরির জন্য যা স্বয়ংক্রিয়ভাবে আর্কিটেকচারের জন্য উপযুক্ত বাস্তবায়ন বেছে নেয়, অথবা একটি বৈশিষ্ট্য-কনফিগারযোগ্য বাইনারি যা নির্মাণের সময় কাস্টমাইজ করা যেতে পারে।

উদাহরণ

# myapp/BUILD

cc_binary(
    name = "mybinary",
    srcs = ["main.cc"],
    deps = select({
        ":arm_build": [":arm_lib"],
        ":x86_debug_build": [":x86_dev_lib"],
        "//conditions:default": [":generic_lib"],
    }),
)

config_setting(
    name = "arm_build",
    values = {"cpu": "arm"},
)

config_setting(
    name = "x86_debug_build",
    values = {
        "cpu": "x86",
        "compilation_mode": "dbg",
    },
)

এটি একটি cc_binary ঘোষণা করে যা কমান্ড লাইনের পতাকার উপর ভিত্তি করে এর ডিপগুলিকে "নির্বাচন করে"। বিশেষত, deps হয়ে যায়:

আদেশ deps =
bazel build //myapp:mybinary --cpu=arm [":arm_lib"]
bazel build //myapp:mybinary -c dbg --cpu=x86 [":x86_dev_lib"]
bazel build //myapp:mybinary --cpu=ppc [":generic_lib"]
bazel build //myapp:mybinary -c dbg --cpu=ppc [":generic_lib"]

select() একটি মানের জন্য একটি স্থানধারক হিসাবে কাজ করে যা কনফিগারেশন শর্তের উপর ভিত্তি করে নির্বাচন করা হবে, যা config_setting লক্ষ্যগুলিকে উল্লেখ করে লেবেল। কনফিগারযোগ্য অ্যাট্রিবিউটে select() , অ্যাট্রিবিউট কার্যকরভাবে বিভিন্ন মান গ্রহণ করে যখন বিভিন্ন শর্ত থাকে।

মিলগুলি অবশ্যই দ্ব্যর্থহীন হতে হবে: হয় ঠিক একটি শর্ত মিলতে হবে বা, যদি একাধিক শর্ত মিলে যায়, তবে একজনের values অবশ্যই অন্য সকলের একটি কঠোর সুপারসেট হতে হবে। উদাহরণস্বরূপ, values = {"cpu": "x86", "compilation_mode": "dbg"} হল values = {"cpu": "x86"} । অন্তর্নির্মিত শর্ত //conditions:default স্বয়ংক্রিয়ভাবে মেলে যখন অন্য কিছু করে না।

যদিও এই উদাহরণটি deps ব্যবহার করে, Select select() ঠিক একইভাবে কাজ করে srcs , resources , cmd , এবং অন্যান্য বেশিরভাগ বৈশিষ্ট্যে। শুধুমাত্র অল্প সংখ্যক গুণাবলী অ-কনফিগারযোগ্য , এবং এগুলি স্পষ্টভাবে টীকা করা হয়েছে৷ উদাহরণস্বরূপ, config_setting এর নিজস্ব values বৈশিষ্ট্যটি কনফিগারযোগ্য নয়।

select() এবং নির্ভরতা

নির্দিষ্ট বৈশিষ্ট্য একটি লক্ষ্যের অধীনে সমস্ত ট্রানজিটিভ নির্ভরতার জন্য বিল্ড প্যারামিটার পরিবর্তন করে। উদাহরণ স্বরূপ, genrule এর tools --cpu কে Bazel চালিত মেশিনের CPU-তে পরিবর্তিত করে (যা, ক্রস-কম্পাইলেশনের জন্য, লক্ষ্যটি যে CPU-র জন্য তৈরি করা হয়েছে তার থেকে আলাদা হতে পারে)। এটি একটি কনফিগারেশন ট্রানজিশন হিসাবে পরিচিত।

দেওয়া

#myapp/BUILD

config_setting(
    name = "arm_cpu",
    values = {"cpu": "arm"},
)

config_setting(
    name = "x86_cpu",
    values = {"cpu": "x86"},
)

genrule(
    name = "my_genrule",
    srcs = select({
        ":arm_cpu": ["g_arm.src"],
        ":x86_cpu": ["g_x86.src"],
    }),
    tools = select({
        ":arm_cpu": [":tool1"],
        ":x86_cpu": [":tool2"],
    }),
)

cc_binary(
    name = "tool1",
    srcs = select({
        ":arm_cpu": ["armtool.cc"],
        ":x86_cpu": ["x86tool.cc"],
    }),
)

চলমান

$ bazel build //myapp:my_genrule --cpu=arm

একটি x86 ডেভেলপার মেশিনে g_arm.src , tool1 , এবং x86tool.cc এর সাথে আবদ্ধ করে। my_genrule এর সাথে সংযুক্ত উভয় select my_genrule এর বিল্ড প্যারামিটার ব্যবহার করে, যার মধ্যে --cpu=arm অন্তর্ভুক্ত রয়েছে। টুল tool1 এবং এর ট্রানজিটিভ নির্ভরতার জন্য tools অ্যাট্রিবিউট --cpu তে x86 পরিবর্তন করে। tool1 -এর select tool1 -এর বিল্ড প্যারামিটার ব্যবহার করে, যার মধ্যে --cpu=x86 অন্তর্ভুক্ত রয়েছে।

কনফিগারেশন শর্তাবলী

একটি কনফিগারযোগ্য বৈশিষ্ট্যের প্রতিটি কী একটি config_setting বা constraint_value এর একটি লেবেল রেফারেন্স।

config_setting প্রত্যাশিত কমান্ড লাইন পতাকা সেটিংসের একটি সংগ্রহ মাত্র। এগুলিকে একটি টার্গেটে এনক্যাপসুলেট করে, ব্যবহারকারীরা একাধিক জায়গা থেকে রেফারেন্স করতে পারে এমন "মানক" অবস্থা বজায় রাখা সহজ।

constraint_value মাল্টি-প্ল্যাটফর্ম আচরণের জন্য সমর্থন প্রদান করে।

অন্তর্নির্মিত পতাকা

--cpu-এর মতো ফ্ল্যাগগুলি --cpu এর মধ্যে তৈরি করা হয়েছে: বিল্ড টুল নেটিভভাবে সমস্ত প্রোজেক্টের সমস্ত বিল্ডের জন্য সেগুলি বোঝে। এগুলি config_setting এর values বৈশিষ্ট্যের সাথে নির্দিষ্ট করা হয়েছে:

config_setting(
    name = "meaningful_condition_name",
    values = {
        "flag1": "value1",
        "flag2": "value2",
        ...
    },
)

flagN হল একটি পতাকার নাম ( -- ছাড়া, তাই "--cpu" এর পরিবর্তে "cpu" ")। valueN হল সেই পতাকার জন্য প্রত্যাশিত মান। :meaningful_condition_name মেলে যদি values প্রতিটি এন্ট্রি মিলে যায়। আদেশ অপ্রাসঙ্গিক.

valueN কে পার্স করা হয়েছে যেন এটি কমান্ড লাইনে সেট করা হয়েছে। এর অর্থ:

  • values = { "compilation_mode": "opt" } bazel build -c opt মেলে
  • values = { "force_pic": "true" } bazel build --force_pic=1
  • values = { "force_pic": "0" } bazel build --noforce_pic

config_setting শুধুমাত্র ফ্ল্যাগ সমর্থন করে যা লক্ষ্য আচরণকে প্রভাবিত করে। উদাহরণস্বরূপ, --show_progress মঞ্জুরিপ্রাপ্ত নয় কারণ এটি শুধুমাত্র Bazel ব্যবহারকারীর কাছে কীভাবে অগ্রগতি রিপোর্ট করে তা প্রভাবিত করে। লক্ষ্যগুলি তাদের ফলাফল তৈরি করতে সেই পতাকা ব্যবহার করতে পারে না। সমর্থিত পতাকার সঠিক সেট নথিভুক্ত করা হয় না। অনুশীলনে, বেশিরভাগ পতাকা যা "অর্থবোধক" কাজ করে।

কাস্টম পতাকা

আপনি Starlark বিল্ড সেটিংসের সাথে আপনার নিজস্ব প্রকল্প-নির্দিষ্ট পতাকা মডেল করতে পারেন। অন্তর্নির্মিত পতাকাগুলির বিপরীতে, এগুলিকে বিল্ড টার্গেট হিসাবে সংজ্ঞায়িত করা হয়, তাই Bazel এগুলিকে লক্ষ্য লেবেলের সাথে উল্লেখ করে।

এগুলি config_setting এর flag_values ​​অ্যাট্রিবিউট দিয়ে ট্রিগার করা হয়েছে:

config_setting(
    name = "meaningful_condition_name",
    flag_values = {
        "//myflags:flag1": "value1",
        "//myflags:flag2": "value2",
        ...
    },
)

আচরণ বিল্ট-ইন পতাকার মতোই। একটি কাজের উদাহরণের জন্য এখানে দেখুন.

--define হল কাস্টম পতাকাগুলির জন্য একটি বিকল্প লিগ্যাসি সিনট্যাক্স (উদাহরণস্বরূপ --define foo=bar )। এটি মান বৈশিষ্ট্যে প্রকাশ করা যেতে পারে ( values = {"define": "foo=bar"} ) অথবা define_values ​​বৈশিষ্ট্য ( define_values = {"foo": "bar"} )। --define শুধুমাত্র পিছনের সামঞ্জস্যের জন্য সমর্থিত। যখনই সম্ভব স্টারলার্ক বিল্ড সেটিংস পছন্দ করুন।

values , flag_values ​​, এবং define_values ​​স্বাধীনভাবে মূল্যায়ন করে। config_setting মেলে যদি তাদের সব জুড়ে সমস্ত মান মিলে যায়।

ডিফল্ট শর্ত

অন্তর্নির্মিত শর্ত //conditions:default মেলে যখন অন্য কোন শর্ত মেলে না।

"ঠিক একটি ম্যাচ" নিয়মের কারণে, কোনো মিল ছাড়াই একটি কনফিগারযোগ্য বৈশিষ্ট্য এবং কোনো ডিফল্ট শর্ত একটি "no matching conditions" ত্রুটি নির্গত করে। এটি অপ্রত্যাশিত সেটিংস থেকে নীরব ব্যর্থতা থেকে রক্ষা করতে পারে:

# myapp/BUILD

config_setting(
    name = "x86_cpu",
    values = {"cpu": "x86"},
)

cc_library(
    name = "x86_only_lib",
    srcs = select({
        ":x86_cpu": ["lib.cc"],
    }),
)
$ bazel build //myapp:x86_only_lib --cpu=arm
ERROR: Configurable attribute "srcs" doesn't match this configuration (would
a default condition help?).
Conditions checked:
  //myapp:x86_cpu

আরও পরিষ্কার ত্রুটির জন্য, আপনি select() এর no_match_error বৈশিষ্ট্য সহ কাস্টম বার্তা সেট করতে পারেন।

প্ল্যাটফর্ম

যদিও কমান্ড লাইনে একাধিক পতাকা নির্দিষ্ট করার ক্ষমতা নমনীয়তা প্রদান করে, আপনি যখনই একটি লক্ষ্য তৈরি করতে চান তখন প্রতিটিকে পৃথকভাবে সেট করাও কঠিন হতে পারে। প্ল্যাটফর্মগুলি আপনাকে এগুলিকে সাধারণ বান্ডিলে একত্রিত করতে দেয়।

# myapp/BUILD

sh_binary(
    name = "my_rocks",
    srcs = select({
        ":basalt": ["pyroxene.sh"],
        ":marble": ["calcite.sh"],
        "//conditions:default": ["feldspar.sh"],
    }),
)

config_setting(
    name = "basalt",
    constraint_values = [
        ":black",
        ":igneous",
    ],
)

config_setting(
    name = "marble",
    constraint_values = [
        ":white",
        ":metamorphic",
    ],
)

# constraint_setting acts as an enum type, and constraint_value as an enum value.
constraint_setting(name = "color")
constraint_value(name = "black", constraint_setting = "color")
constraint_value(name = "white", constraint_setting = "color")
constraint_setting(name = "texture")
constraint_value(name = "smooth", constraint_setting = "texture")
constraint_setting(name = "type")
constraint_value(name = "igneous", constraint_setting = "type")
constraint_value(name = "metamorphic", constraint_setting = "type")

platform(
    name = "basalt_platform",
    constraint_values = [
        ":black",
        ":igneous",
    ],
)

platform(
    name = "marble_platform",
    constraint_values = [
        ":white",
        ":smooth",
        ":metamorphic",
    ],
)

প্ল্যাটফর্মটি কমান্ড লাইনে নির্দিষ্ট করা যেতে পারে। এটি config_setting s সক্রিয় করে যাতে প্ল্যাটফর্মের constraint_values এর একটি উপসেট থাকে, এই config_setting গুলিকে select() এক্সপ্রেশনের সাথে মেলে।

উদাহরণস্বরূপ, calcite.sh এর srcs অ্যাট্রিবিউট my_rocks এ সেট করার জন্য, আপনি সহজভাবে চালাতে পারেন

bazel build //my_app:my_rocks --platforms=//myapp:marble_platform

প্ল্যাটফর্ম ছাড়া, এই মত কিছু দেখতে পারে

bazel build //my_app:my_rocks --define color=white --define texture=smooth --define type=metamorphic

select() সরাসরি constraint_value s পড়তে পারে:

constraint_setting(name = "type")
constraint_value(name = "igneous", constraint_setting = "type")
constraint_value(name = "metamorphic", constraint_setting = "type")
sh_binary(
    name = "my_rocks",
    srcs = select({
        ":igneous": ["igneous.sh"],
        ":metamorphic" ["metamorphic.sh"],
    }),
)

এটি বয়লারপ্লেট config_setting -এর প্রয়োজনীয়তা সংরক্ষণ করে যখন আপনাকে শুধুমাত্র একক মান পরীক্ষা করতে হবে।

প্ল্যাটফর্মগুলি এখনও উন্নয়নাধীন। বিস্তারিত জানার জন্য ডকুমেন্টেশন দেখুন.

select() s এর সমন্বয়

select একই বৈশিষ্ট্যে একাধিকবার প্রদর্শিত হতে পারে:

sh_binary(
    name = "my_target",
    srcs = ["always_include.sh"] +
           select({
               ":armeabi_mode": ["armeabi_src.sh"],
               ":x86_mode": ["x86_src.sh"],
           }) +
           select({
               ":opt_mode": ["opt_extras.sh"],
               ":dbg_mode": ["dbg_extras.sh"],
           }),
)

select অন্য select ভিতরে প্রদর্শিত হতে পারে না। আপনি যদি নেস্ট selects করতে চান এবং আপনার অ্যাট্রিবিউট অন্য টার্গেটকে মান হিসেবে নেয়, তাহলে একটি মধ্যবর্তী টার্গেট ব্যবহার করুন:

sh_binary(
    name = "my_target",
    srcs = ["always_include.sh"],
    deps = select({
        ":armeabi_mode": [":armeabi_lib"],
        ...
    }),
)

sh_library(
    name = "armeabi_lib",
    srcs = select({
        ":opt_mode": ["armeabi_with_opt.sh"],
        ...
    }),
)

একাধিক শর্ত মিলে গেলে আপনার যদি ম্যাচ করার জন্য একটি select প্রয়োজন হয়, তাহলে AND চেইনিং বিবেচনা করুন।

বা চেইনিং

নিম্নোক্ত বিবেচনা কর:

sh_binary(
    name = "my_target",
    srcs = ["always_include.sh"],
    deps = select({
        ":config1": [":standard_lib"],
        ":config2": [":standard_lib"],
        ":config3": [":standard_lib"],
        ":config4": [":special_lib"],
    }),
)

অধিকাংশ শর্ত একই ডিপ মূল্যায়ন. কিন্তু এই সিনট্যাক্স পড়া এবং বজায় রাখা কঠিন। [":standard_lib"] একাধিকবার পুনরাবৃত্তি করতে না পারলে ভালো হবে।

একটি বিকল্প হল মানটিকে একটি বিল্ড ভেরিয়েবল হিসাবে পূর্বনির্ধারিত করা:

STANDARD_DEP = [":standard_lib"]

sh_binary(
    name = "my_target",
    srcs = ["always_include.sh"],
    deps = select({
        ":config1": STANDARD_DEP,
        ":config2": STANDARD_DEP,
        ":config3": STANDARD_DEP,
        ":config4": [":special_lib"],
    }),
)

এটি নির্ভরতা পরিচালনা করা সহজ করে তোলে। কিন্তু এটি এখনও অপ্রয়োজনীয় নকল সৃষ্টি করে।

আরও সরাসরি সমর্থনের জন্য, নিম্নলিখিতগুলির মধ্যে একটি ব্যবহার করুন:

selects.with_or

Skylib- এর selects OR with_or ম্যাক্রো একটি সিলেক্টের ভিতরে সরাসরি শর্তগুলিকে সমর্থন select

load("@bazel_skylib//lib:selects.bzl", "selects")
sh_binary(
    name = "my_target",
    srcs = ["always_include.sh"],
    deps = selects.with_or({
        (":config1", ":config2", ":config3"): [":standard_lib"],
        ":config4": [":special_lib"],
    }),
)

selects.config_setting_group

Skylib- এর config_setting_group ম্যাক্রো selects মডিউল সমর্থন করে OR একাধিক config_setting s:

load("@bazel_skylib//lib:selects.bzl", "selects")
config_setting(
    name = "config1",
    values = {"cpu": "arm"},
)
config_setting(
    name = "config2",
    values = {"compilation_mode": "dbg"},
)
selects.config_setting_group(
    name = "config1_or_2",
    match_any = [":config1", ":config2"],
)
sh_binary(
    name = "my_target",
    srcs = ["always_include.sh"],
    deps = select({
        ":config1_or_2": [":standard_lib"],
        "//conditions:default": [":other_lib"],
    }),
)

selects.with_or বিপরীতে, বিভিন্ন টার্গেট শেয়ার করতে পারে :config1_or_2 বিভিন্ন অ্যাট্রিবিউট জুড়ে।

এটি একাধিক শর্তের জন্য একটি ত্রুটি যদি না একটি অন্যদের একটি দ্ব্যর্থহীন "বিশেষায়ন" হয়। বিস্তারিত জানার জন্য এখানে দেখুন.

এবং চেইনিং

একাধিক শর্ত মিলে গেলে আপনার যদি একটি select শাখার প্রয়োজন হয়, তাহলে Skylib macro config_setting_group ব্যবহার করুন :

config_setting(
    name = "config1",
    values = {"cpu": "arm"},
)
config_setting(
    name = "config2",
    values = {"compilation_mode": "dbg"},
)
selects.config_setting_group(
    name = "config1_and_2",
    match_all = [":config1", ":config2"],
)
sh_binary(
    name = "my_target",
    srcs = ["always_include.sh"],
    deps = select({
        ":config1_and_2": [":standard_lib"],
        "//conditions:default": [":other_lib"],
    }),
)

OR চেইনিংয়ের বিপরীতে, বিদ্যমান config_setting সরাসরি AND একটি select ভিতরে ed করা যাবে না। আপনাকে স্পষ্টভাবে সেগুলিকে একটি config_setting_group এ আবৃত করতে হবে।

কাস্টম ত্রুটি বার্তা

ডিফল্টরূপে, যখন কোনো শর্ত মেলে না, লক্ষ্য select() এর সাথে সংযুক্ত করা হয় ত্রুটির সাথে ব্যর্থ হয়:

ERROR: Configurable attribute "deps" doesn't match this configuration (would
a default condition help?).
Conditions checked:
  //tools/cc_target_os:darwin
  //tools/cc_target_os:android

এটি no_match_error বৈশিষ্ট্যের সাথে কাস্টমাইজ করা যেতে পারে:

cc_library(
    name = "my_lib",
    deps = select(
        {
            "//tools/cc_target_os:android": [":android_deps"],
            "//tools/cc_target_os:windows": [":windows_deps"],
        },
        no_match_error = "Please build with an Android or Windows toolchain",
    ),
)
$ bazel build //myapp:my_lib
ERROR: Configurable attribute "deps" doesn't match this configuration: Please
build with an Android or Windows toolchain

নিয়মের সামঞ্জস্য

নিয়ম বাস্তবায়ন কনফিগারযোগ্য বৈশিষ্ট্যগুলির সমাধানকৃত মানগুলি পায়। উদাহরণস্বরূপ, দেওয়া হয়েছে:

# myapp/BUILD

some_rule(
    name = "my_target",
    some_attr = select({
        ":foo_mode": [":foo"],
        ":bar_mode": [":bar"],
    }),
)
$ bazel build //myapp/my_target --define mode=foo

নিয়ম বাস্তবায়ন কোড ctx.attr.some_attr কে [":foo"] হিসাবে দেখে।

ম্যাক্রো select() ক্লজ গ্রহণ করতে পারে এবং সেগুলিকে নেটিভ নিয়মে পাস করতে পারে। কিন্তু তারা সরাসরি তাদের কারসাজি করতে পারে না । উদাহরণস্বরূপ, একটি ম্যাক্রো রূপান্তর করার কোন উপায় নেই

select({"foo": "val"}, ...)

প্রতি

select({"foo": "val_with_suffix"}, ...)

এটি দুটি কারণে।

প্রথমত, ম্যাক্রো যেগুলিকে জানা দরকার যে কোন পথ select নেবে সেগুলি কাজ করতে পারে না কারণ ম্যাক্রোগুলি Bazel-এর লোডিং পর্বে মূল্যায়ন করা হয়, যা পতাকা মান জানার আগে ঘটে৷ এটি একটি মূল বেজেল ডিজাইনের সীমাবদ্ধতা যা শীঘ্রই পরিবর্তন হওয়ার সম্ভাবনা নেই।

দ্বিতীয়ত, ম্যাক্রো যেগুলিকে শুধুমাত্র সমস্ত select পথের উপর পুনরাবৃত্তি করতে হবে, যদিও প্রযুক্তিগতভাবে সম্ভব, একটি সুসংগত UI এর অভাব রয়েছে। এটি পরিবর্তন করার জন্য আরও নকশা প্রয়োজন।

Bazel ক্যোয়ারী এবং cquery

Bazel query Bazel এর লোডিং পর্যায়ে কাজ করে। এর মানে এটা জানে না যে কোন কমান্ড লাইন ফ্ল্যাগ কোন টার্গেট ব্যবহার করে কারণ সেই ফ্ল্যাগগুলিকে পরবর্তীতে বিল্ড না হওয়া পর্যন্ত মূল্যায়ন করা হয় না ( বিশ্লেষণ পর্বে )। সুতরাং এটি কোন select() শাখা নির্বাচন করা হয়েছে তা নির্ধারণ করতে পারে না।

Bazel cquery বিশ্লেষণ পর্বের পরে কাজ করে, তাই এটিতে এই সমস্ত তথ্য রয়েছে এবং সঠিকভাবে select() গুলি সমাধান করতে পারে।

বিবেচনা:

load("@bazel_skylib//rules:common_settings.bzl", "string_flag")
# myapp/BUILD

string_flag(
    name = "dog_type",
    build_setting_default = "cat"
)

cc_library(
    name = "my_lib",
    deps = select({
        ":long": [":foo_dep"],
        ":short": [":bar_dep"],
    }),
)

config_setting(
    name = "long",
    flag_values = {":dog_type": "dachshund"},
)

config_setting(
    name = "short",
    flag_values = {":dog_type": "pug"},
)

query আনুমানিক :my_lib এর নির্ভরতা:

$ bazel query 'deps(//myapp:my_lib)'
//myapp:my_lib
//myapp:foo_dep
//myapp:bar_dep

যখন cquery তার সঠিক নির্ভরতা দেখায়:

$ bazel cquery 'deps(//myapp:my_lib)' --//myapp:dog_type=pug
//myapp:my_lib
//myapp:bar_dep

FAQ

কেন নির্বাচন() ম্যাক্রোতে কাজ করে না?

select() নিয়মে কাজ করে ! বিস্তারিত জানার জন্য নিয়ম সামঞ্জস্য দেখুন।

এই প্রশ্নের মূল সমস্যাটি সাধারণত বোঝায় যে select() ম্যাক্রোতে কাজ করে না। এগুলো নিয়মের চেয়ে ভিন্ন। পার্থক্য বুঝতে নিয়ম এবং ম্যাক্রোর ডকুমেন্টেশন দেখুন। এখানে একটি শেষ থেকে শেষ উদাহরণ:

একটি নিয়ম এবং ম্যাক্রো সংজ্ঞায়িত করুন:

# myapp/defs.bzl

# Rule implementation: when an attribute is read, all select()s have already
# been resolved. So it looks like a plain old attribute just like any other.
def _impl(ctx):
    name = ctx.attr.name
    allcaps = ctx.attr.my_config_string.upper()  # This works fine on all values.
    print("My name is " + name + " with custom message: " + allcaps)

# Rule declaration:
my_custom_bazel_rule = rule(
    implementation = _impl,
    attrs = {"my_config_string": attr.string()},
)

# Macro declaration:
def my_custom_bazel_macro(name, my_config_string):
    allcaps = my_config_string.upper()  # This line won't work with select(s).
    print("My name is " + name + " with custom message: " + allcaps)

নিয়ম এবং ম্যাক্রো ইনস্ট্যান্ট করুন:

# myapp/BUILD

load("//myapp:defs.bzl", "my_custom_bazel_rule")
load("//myapp:defs.bzl", "my_custom_bazel_macro")

my_custom_bazel_rule(
    name = "happy_rule",
    my_config_string = select({
        "//tools/target_cpu:x86": "first string",
        "//tools/target_cpu:ppc": "second string",
    }),
)

my_custom_bazel_macro(
    name = "happy_macro",
    my_config_string = "fixed string",
)

my_custom_bazel_macro(
    name = "sad_macro",
    my_config_string = select({
        "//tools/target_cpu:x86": "first string",
        "//tools/target_cpu:ppc": "other string",
    }),
)

বিল্ডিং ব্যর্থ হয় কারণ sad_macro select() :

$ bazel build //myapp:all
ERROR: /myworkspace/myapp/BUILD:17:1: Traceback
  (most recent call last):
File "/myworkspace/myapp/BUILD", line 17
my_custom_bazel_macro(name = "sad_macro", my_config_stri..."}))
File "/myworkspace/myapp/defs.bzl", line 4, in
  my_custom_bazel_macro
my_config_string.upper()
type 'select' has no method upper().
ERROR: error loading package 'myapp': Package 'myapp' contains errors.

বিল্ডিং সফল হয় যখন আপনি মন্তব্য করেন sad_macro :

# Comment out sad_macro so it doesn't mess up the build.
$ bazel build //myapp:all
DEBUG: /myworkspace/myapp/defs.bzl:5:3: My name is happy_macro with custom message: FIXED STRING.
DEBUG: /myworkspace/myapp/hi.bzl:15:3: My name is happy_rule with custom message: FIRST STRING.

এটি পরিবর্তন করা অসম্ভব কারণ ব্যাজেল বিল্ডের কমান্ড লাইন পতাকা পড়ার আগে সংজ্ঞা অনুসারে ম্যাক্রোগুলিকে মূল্যায়ন করা হয়। এর মানে নির্বাচন ()গুলি মূল্যায়ন করার জন্য পর্যাপ্ত তথ্য নেই।

ম্যাক্রো অবশ্য select() গুলিকে অস্বচ্ছ ব্লব হিসাবে নিয়মে পাস করতে পারে:

# myapp/defs.bzl

def my_custom_bazel_macro(name, my_config_string):
    print("Invoking macro " + name)
    my_custom_bazel_rule(
        name = name + "_as_target",
        my_config_string = my_config_string,
    )
$ bazel build //myapp:sad_macro_less_sad
DEBUG: /myworkspace/myapp/defs.bzl:23:3: Invoking macro sad_macro_less_sad.
DEBUG: /myworkspace/myapp/defs.bzl:15:3: My name is sad_macro_less_sad with custom message: FIRST STRING.

কেন নির্বাচন () সবসময় সত্য ফিরে আসে?

যেহেতু ম্যাক্রো (কিন্তু নিয়ম নয়) সংজ্ঞা অনুসারে select() s এর মূল্যায়ন করতে পারে না, তাই করার যেকোনো প্রচেষ্টা সাধারণত একটি ত্রুটি তৈরি করে:

ERROR: /myworkspace/myapp/BUILD:17:1: Traceback
  (most recent call last):
File "/myworkspace/myapp/BUILD", line 17
my_custom_bazel_macro(name = "sad_macro", my_config_stri..."}))
File "/myworkspace/myapp/defs.bzl", line 4, in
  my_custom_bazel_macro
my_config_string.upper()
type 'select' has no method upper().

বুলিয়ান একটি বিশেষ কেস যা নীরবে ব্যর্থ হয়, তাই আপনার তাদের সাথে বিশেষভাবে সতর্ক থাকা উচিত:

$ cat myapp/defs.bzl
def my_boolean_macro(boolval):
  print("TRUE" if boolval else "FALSE")

$ cat myapp/BUILD
load("//myapp:defs.bzl", "my_boolean_macro")
my_boolean_macro(
    boolval = select({
        "//tools/target_cpu:x86": True,
        "//tools/target_cpu:ppc": False,
    }),
)

$ bazel build //myapp:all --cpu=x86
DEBUG: /myworkspace/myapp/defs.bzl:4:3: TRUE.
$ bazel build //mypro:all --cpu=ppc
DEBUG: /myworkspace/myapp/defs.bzl:4:3: TRUE.

এটি ঘটে কারণ ম্যাক্রো select() এর বিষয়বস্তু বুঝতে পারে না। তাই তারা কি সত্যিই মূল্যায়ন করছি select() বস্তু নিজেই. পাইথনিক ডিজাইনের মান অনুযায়ী, খুব অল্প সংখ্যক ব্যতিক্রম বাদ দিয়ে সমস্ত বস্তু স্বয়ংক্রিয়ভাবে সত্যে ফিরে আসে।

আমি একটি dict মত select() পড়তে পারি?

ম্যাক্রো নির্বাচন(গুলি) মূল্যায়ন করতে পারে না কারণ বিল্ডের কমান্ড লাইন প্যারামিটারগুলি কী তা Bazel জানার আগে ম্যাক্রোগুলি মূল্যায়ন করে৷ তারা কি অন্তত select() এর অভিধান পড়তে পারে, উদাহরণস্বরূপ, প্রতিটি মানের সাথে একটি প্রত্যয় যোগ করতে?

ধারণাগতভাবে এটি সম্ভব, কিন্তু এটি এখনও একটি Bazel বৈশিষ্ট্য নয়। আপনি আজ যা করতে পারেন তা হল একটি সোজা অভিধান তৈরি করুন, তারপর এটিকে একটি select() এ খাওয়ান :

$ cat myapp/defs.bzl
def selecty_genrule(name, select_cmd):
  for key in select_cmd.keys():
    select_cmd[key] += " WITH SUFFIX"
  native.genrule(
      name = name,
      outs = [name + ".out"],
      srcs = [],
      cmd = "echo " + select(select_cmd + {"//conditions:default": "default"})
        + " > $@"
  )

$ cat myapp/BUILD
selecty_genrule(
    name = "selecty",
    select_cmd = {
        "//tools/target_cpu:x86": "x86 mode",
    },
)

$ bazel build //testapp:selecty --cpu=x86 && cat bazel-genfiles/testapp/selecty.out
x86 mode WITH SUFFIX

আপনি select() এবং নেটিভ উভয় প্রকারকে সমর্থন করতে চাইলে, আপনি এটি করতে পারেন:

$ cat myapp/defs.bzl
def selecty_genrule(name, select_cmd):
    cmd_suffix = ""
    if type(select_cmd) == "string":
        cmd_suffix = select_cmd + " WITH SUFFIX"
    elif type(select_cmd) == "dict":
        for key in select_cmd.keys():
            select_cmd[key] += " WITH SUFFIX"
        cmd_suffix = select(select_cmd + {"//conditions:default": "default"})

    native.genrule(
        name = name,
        outs = [name + ".out"],
        srcs = [],
        cmd = "echo " + cmd_suffix + "> $@",
    )

কেন নির্বাচন() bind() এর সাথে কাজ করে না?

কারণ bind() একটি WORKSPACE নিয়ম, একটি BUILD নিয়ম নয়।

ওয়ার্কস্পেস নিয়মগুলির একটি নির্দিষ্ট কনফিগারেশন নেই, এবং BUILD নিয়মগুলির মতো একইভাবে মূল্যায়ন করা হয় না। অতএব, একটি bind() select() আসলে কোনো নির্দিষ্ট শাখায় মূল্যায়ন করতে পারে না।

পরিবর্তে, এই ধরনের রান-টাইম নির্ধারণ করতে আপনার actual বৈশিষ্ট্যে একটি select() সহ alias() ব্যবহার করা উচিত। এটি সঠিকভাবে কাজ করে, যেহেতু alias() একটি BUILD নিয়ম, এবং একটি নির্দিষ্ট কনফিগারেশনের সাথে মূল্যায়ন করা হয়।

প্রয়োজনে আপনি একটি alias() -এ একটি bind() টার্গেট পয়েন্টও রাখতে পারেন।

$ cat WORKSPACE
workspace(name = "myapp")
bind(name = "openssl", actual = "//:ssl")
http_archive(name = "alternative", ...)
http_archive(name = "boringssl", ...)

$ cat BUILD
config_setting(
    name = "alt_ssl",
    define_values = {
        "ssl_library": "alternative",
    },
)

alias(
    name = "ssl",
    actual = select({
        "//:alt_ssl": "@alternative//:ssl",
        "//conditions:default": "@boringssl//:ssl",
    }),
)

এই সেটআপের মাধ্যমে, আপনি পাস করতে পারেন --define ssl_library=alternative , এবং //:ssl বা //external:ssl ssl-এর উপর নির্ভরশীল যেকোন টার্গেট @alternative//:ssl এ অবস্থিত বিকল্পটি দেখতে পাবে।

কেন আমার নির্বাচন () আমি যা আশা করি তা বেছে নেয় না?

যদি //myapp:foo তে একটি select() থাকে যা আপনার প্রত্যাশিত শর্তটি বেছে না নেয়, ডিবাগ করতে cquery এবং bazel config ব্যবহার করুন:

যদি //myapp:foo আপনি তৈরি করছেন শীর্ষ-স্তরের লক্ষ্য, চালান:

$ bazel cquery //myapp:foo <desired build flags>
//myapp:foo (12e23b9a2b534a)

আপনি যদি //myapp:foo এর সাবগ্রাফের কোথাও নির্ভর করে এমন কিছু অন্য টার্গেট //bar তৈরি করছেন, চালান:

$ bazel cquery 'somepath(//bar, //myapp:foo)' <desired build flags>
//bar:bar   (3ag3193fee94a2)
//bar:intermediate_dep (12e23b9a2b534a)
//myapp:foo (12e23b9a2b534a)

//myapp:foo এর পাশের (12e23b9a2b534a) হল কনফিগারেশনের একটি হ্যাশ যা সমাধান করে //myapp:foo এর Select select() । আপনি bazel config সাথে এর মানগুলি পরীক্ষা করতে পারেন:

$ bazel config 12e23b9a2b534a
BuildConfigurationValue 12e23b9a2b534a
Fragment com.google.devtools.build.lib.analysis.config.CoreOptions {
  cpu: darwin
  compilation_mode: fastbuild
  ...
}
Fragment com.google.devtools.build.lib.rules.cpp.CppOptions {
  linkopt: [-Dfoo=bar]
  ...
}
...

তারপর প্রতিটি config_setting দ্বারা প্রত্যাশিত সেটিংসের সাথে এই আউটপুটটির তুলনা করুন।

//myapp:foo একই বিল্ডে বিভিন্ন কনফিগারেশনে থাকতে পারে। সঠিকটি পেতে somepath ব্যবহার করার বিষয়ে নির্দেশনার জন্য cquery ডক্স দেখুন।

কেন select() প্ল্যাটফর্মের সাথে কাজ করে না?

Bazel একটি প্রদত্ত প্ল্যাটফর্ম লক্ষ্য প্ল্যাটফর্ম কিনা তা পরীক্ষা করে কনফিগারযোগ্য বৈশিষ্ট্য সমর্থন করে না কারণ শব্দার্থ অস্পষ্ট।

উদাহরণ স্বরূপ:

platform(
    name = "x86_linux_platform",
    constraint_values = [
        "@platforms//cpu:x86",
        "@platforms//os:linux",
    ],
)

cc_library(
    name = "lib",
    srcs = [...],
    linkopts = select({
        ":x86_linux_platform": ["--enable_x86_optimizations"],
        "//conditions:default": [],
    }),
)

এই BUILD ফাইলে, টার্গেট প্ল্যাটফর্মে @platforms//cpu:x86 এবং @platforms//os:linux সীমাবদ্ধতা থাকলে কোন select() ব্যবহার করা উচিত, কিন্তু এখানে কি :x86_linux_platform সংজ্ঞায়িত করা হয়নি? BUILD ফাইলের লেখক এবং পৃথক প্ল্যাটফর্ম সংজ্ঞায়িত ব্যবহারকারীর ভিন্ন ধারণা থাকতে পারে।

আমি পরিবর্তে কি করা উচিত?

পরিবর্তে, একটি config_setting সংজ্ঞায়িত করুন যা এই সীমাবদ্ধতার সাথে যেকোনো প্ল্যাটফর্মের সাথে মেলে:

config_setting(
    name = "is_x86_linux",
    constraint_values = [
        "@platforms//cpu:x86",
        "@platforms//os:linux",
    ],
)

cc_library(
    name = "lib",
    srcs = [...],
    linkopts = select({
        ":is_x86_linux": ["--enable_x86_optimizations"],
        "//conditions:default": [],
    }),
)

এই প্রক্রিয়াটি নির্দিষ্ট শব্দার্থবিদ্যাকে সংজ্ঞায়িত করে, যা ব্যবহারকারীদের কাছে এটি পরিষ্কার করে যে কোন প্ল্যাটফর্মগুলি পছন্দসই শর্তগুলি পূরণ করে।

আমি যদি সত্যিই, সত্যিই প্ল্যাটফর্মে select করতে চাই?

যদি আপনার বিল্ডের প্রয়োজনীয়তাগুলির জন্য বিশেষভাবে প্ল্যাটফর্ম পরীক্ষা করার প্রয়োজন হয়, আপনি একটি config_setting--platforms পতাকার মান ফ্লিপ করতে পারেন:

config_setting(
    name = "is_specific_x86_linux_platform",
    values = {
        "platforms": ["//package:x86_linux_platform"],
    },
)

cc_library(
    name = "lib",
    srcs = [...],
    linkopts = select({
        ":is_specific_x86_linux_platform": ["--enable_x86_optimizations"],
        "//conditions:default": [],
    }),
)

Bazel দল এটা করা সমর্থন করে না; এটি অত্যধিকভাবে আপনার বিল্ডকে সীমাবদ্ধ করে এবং প্রত্যাশিত অবস্থার সাথে মেলে না তখন ব্যবহারকারীদের বিভ্রান্ত করে।