কনফিগারেশন

এই পৃষ্ঠাটি স্টারলার্ক কনফিগারেশনের সুবিধা এবং মৌলিক ব্যবহার কভার করে, আপনার প্রকল্প কীভাবে তৈরি হয় তা কাস্টমাইজ করার জন্য Bazel এর API। এটি বিল্ড সেটিংস কিভাবে সংজ্ঞায়িত করতে হয় এবং উদাহরণ প্রদান করে তা অন্তর্ভুক্ত করে।

এটি এটি সম্ভব করে তোলে:

  • আপনার প্রকল্পের জন্য কাস্টম পতাকা সংজ্ঞায়িত করুন, --define এর প্রয়োজনীয়তা অপ্রচলিত
  • তাদের পিতামাতার চেয়ে ভিন্ন কনফিগারেশনে deps কনফিগার করার জন্য রূপান্তর লিখুন (যেমন --compilation_mode=opt বা --cpu=arm )
  • নিয়মে আরও ভাল ডিফল্ট বেক করুন (যেমন স্বয়ংক্রিয়ভাবে তৈরি //my:android_app একটি নির্দিষ্ট SDK দিয়ে)

এবং আরও অনেক কিছু, সম্পূর্ণরূপে .bzl ফাইল থেকে (কোন Bazel রিলিজের প্রয়োজন নেই)। উদাহরণের জন্য bazelbuild/examples repo দেখুন।

ব্যবহারকারী-সংজ্ঞায়িত বিল্ড সেটিংস

একটি বিল্ড সেটিং হল কনফিগারেশন তথ্যের একক অংশ। একটি কী/মান মানচিত্র হিসাবে একটি কনফিগারেশনের কথা ভাবুন। --cpu=ppc এবং --copt="-DFoo" সেট করা একটি কনফিগারেশন তৈরি করে যা দেখতে {cpu: ppc, copt: "-DFoo"} । প্রতিটি এন্ট্রি একটি বিল্ড সেটিং.

copt cpu ঐতিহ্যবাহী পতাকাগুলি নেটিভ সেটিংস - তাদের কীগুলি সংজ্ঞায়িত করা হয় এবং তাদের মানগুলি নেটিভ বেজেল জাভা কোডের মধ্যে সেট করা হয়। Bazel ব্যবহারকারীরা শুধুমাত্র কমান্ড লাইন এবং স্থানীয়ভাবে রক্ষণাবেক্ষণ করা অন্যান্য API এর মাধ্যমে সেগুলি পড়তে এবং লিখতে পারে। নেটিভ ফ্ল্যাগগুলি এবং এপিআইগুলি যেগুলি তাদের প্রকাশ করে তা পরিবর্তন করার জন্য একটি বেজেল রিলিজ প্রয়োজন৷ ব্যবহারকারী-সংজ্ঞায়িত বিল্ড সেটিংস .bzl ফাইলগুলিতে সংজ্ঞায়িত করা হয়েছে (এবং এইভাবে, পরিবর্তনগুলি নিবন্ধনের জন্য একটি বেজেল রিলিজের প্রয়োজন নেই)। এগুলি কমান্ড লাইনের মাধ্যমেও সেট করা যেতে পারে (যদি তারা flags হিসাবে মনোনীত হয়, নীচে আরও দেখুন), তবে ব্যবহারকারী-সংজ্ঞায়িত রূপান্তরের মাধ্যমেও সেট করা যেতে পারে।

বিল্ড সেটিংস সংজ্ঞায়িত করা

শেষ থেকে শেষ উদাহরণ

build_setting rule() প্যারামিটার

বিল্ড সেটিংস হল অন্য নিয়মের মতো নিয়ম এবং স্টারলার্ক rule() ফাংশনের build_setting অ্যাট্রিবিউট ব্যবহার করে আলাদা করা হয়।

# example/buildsettings/build_settings.bzl
string_flag = rule(
    implementation = _impl,
    build_setting = config.string(flag = True)
)

build_setting অ্যাট্রিবিউটটি একটি ফাংশন নেয় যা বিল্ড সেটিং-এর ধরন নির্ধারণ করে। টাইপটি বুল এবং string মতো মৌলিক bool ধরণের একটি সেটের মধ্যে সীমাবদ্ধ। বিস্তারিত জানার জন্য config মডিউল ডকুমেন্টেশন দেখুন। নিয়মের বাস্তবায়ন ফাংশনে আরও জটিল টাইপিং করা যেতে পারে। নীচে এই সম্পর্কে আরো.

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

ctx.build_setting_value ব্যবহার করা

সমস্ত নিয়মের মতো, বিল্ড সেটিং নিয়মগুলির বাস্তবায়ন ফাংশন রয়েছে। বিল্ড সেটিংসের মৌলিক স্টারলার্ক-টাইপ মান ctx.build_setting_value পদ্ধতির মাধ্যমে অ্যাক্সেস করা যেতে পারে। এই পদ্ধতিটি শুধুমাত্র বিল্ড সেটিং নিয়মের ctx অবজেক্টের জন্য উপলব্ধ। এই বাস্তবায়ন পদ্ধতিগুলি সরাসরি বিল্ড সেটিংস মানকে ফরোয়ার্ড করতে পারে বা এটিতে অতিরিক্ত কাজ করতে পারে, যেমন টাইপ চেকিং বা আরও জটিল কাঠামো তৈরি করা। এখানে আপনি কিভাবে একটি enum টাইপড বিল্ড সেটিং বাস্তবায়ন করবেন:

# example/buildsettings/build_settings.bzl
TemperatureProvider = provider(fields = ['type'])

temperatures = ["HOT", "LUKEWARM", "ICED"]

def _impl(ctx):
    raw_temperature = ctx.build_setting_value
    if raw_temperature not in temperatures:
        fail(str(ctx.label) + " build setting allowed to take values {"
             + ", ".join(temperatures) + "} but was set to unallowed value "
             + raw_temperature)
    return TemperatureProvider(type = raw_temperature)

temperature = rule(
    implementation = _impl,
    build_setting = config.string(flag = True)
)

মাল্টি-সেট স্ট্রিং পতাকা সংজ্ঞায়িত করা

স্ট্রিং সেটিংসে একটি অতিরিক্ত allow_multiple প্যারামিটার রয়েছে যা কমান্ড লাইনে বা bazelrcs-এ একাধিকবার পতাকা সেট করার অনুমতি দেয়। তাদের ডিফল্ট মান এখনও একটি স্ট্রিং-টাইপ বৈশিষ্ট্যের সাথে সেট করা আছে:

# example/buildsettings/build_settings.bzl
allow_multiple_flag = rule(
    implementation = _impl,
    build_setting = config.string(flag = True, allow_multiple = True)
)
# example/buildsettings/BUILD
load("//example/buildsettings:build_settings.bzl", "allow_multiple_flag")
allow_multiple_flag(
    name = "roasts",
    build_setting_default = "medium"
)

পতাকার প্রতিটি সেটিং একটি একক মান হিসাবে বিবেচিত হয়:

$ bazel build //my/target --//example:roasts=blonde \
    --//example:roasts=medium,dark

উপরেরটি {"//example:roasts": ["blonde", "medium,dark"]} এ পার্স করা হয়েছে এবং ctx.build_setting_value তালিকাটি ["blonde", "medium,dark"] প্রদান করে।

তাত্ক্ষণিক বিল্ড সেটিংস

build_setting প্যারামিটারের সাথে সংজ্ঞায়িত নিয়মগুলির একটি অন্তর্নিহিত বাধ্যতামূলক build_setting_default বৈশিষ্ট্য রয়েছে। এই বৈশিষ্ট্যটি build_setting দ্বারা ঘোষিত একই প্রকারে গ্রহণ করে।

# example/buildsettings/build_settings.bzl
FlavorProvider = provider(fields = ['type'])

def _impl(ctx):
    return FlavorProvider(type = ctx.build_setting_value)

flavor = rule(
    implementation = _impl,
    build_setting = config.string(flag = True)
)
# example/buildsettings/BUILD
load("//example/buildsettings:build_settings.bzl", "flavor")
flavor(
    name = "favorite_flavor",
    build_setting_default = "APPLE"
)

পূর্বনির্ধারিত সেটিংস

শেষ থেকে শেষ উদাহরণ

Skylib লাইব্রেরিতে পূর্বনির্ধারিত সেটিংসের একটি সেট রয়েছে যা আপনি কাস্টম স্টারলার্ক না লিখেই ইনস্ট্যান্টিয়েট করতে পারেন।

উদাহরণস্বরূপ, একটি সেটিং সংজ্ঞায়িত করতে যা স্ট্রিং মানগুলির একটি সীমিত সেট গ্রহণ করে:

# example/BUILD
load("@bazel_skylib//rules:common_settings.bzl", "string_flag")
string_flag(
    name = "myflag",
    values = ["a", "b", "c"],
    build_setting_default = "a",
)

একটি সম্পূর্ণ তালিকার জন্য, সাধারণ বিল্ড সেটিং নিয়ম দেখুন।

বিল্ড সেটিংস ব্যবহার করে

বিল্ড সেটিংসের উপর নির্ভর করে

যদি একটি টার্গেট কনফিগারেশন তথ্যের একটি অংশ পড়তে চায়, তবে এটি একটি নিয়মিত বৈশিষ্ট্য নির্ভরতার মাধ্যমে সরাসরি বিল্ড সেটিং এর উপর নির্ভর করতে পারে।

# example/rules.bzl
load("//example/buildsettings:build_settings.bzl", "FlavorProvider")
def _rule_impl(ctx):
    if ctx.attr.flavor[FlavorProvider].type == "ORANGE":
        ...

drink_rule = rule(
    implementation = _rule_impl,
    attrs = {
        "flavor": attr.label()
    }
)
# example/BUILD
load("//example:rules.bzl", "drink_rule")
load("//example/buildsettings:build_settings.bzl", "flavor")
flavor(
    name = "favorite_flavor",
    build_setting_default = "APPLE"
)
drink_rule(
    name = "my_drink",
    flavor = ":favorite_flavor",
)

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

# kotlin/rules.bzl
_KOTLIN_CONFIG = {
    "_compiler": attr.label(default = "//kotlin/config:compiler-flag"),
    "_mode": attr.label(default = "//kotlin/config:mode-flag"),
    ...
}

...

kotlin_library = rule(
    implementation = _rule_impl,
    attrs = dicts.add({
        "library-attr": attr.string()
    }, _KOTLIN_CONFIG)
)

kotlin_binary = rule(
    implementation = _binary_impl,
    attrs = dicts.add({
        "binary-attr": attr.label()
    }, _KOTLIN_CONFIG)

কমান্ড লাইনে বিল্ড সেটিংস ব্যবহার করে

বেশিরভাগ নেটিভ পতাকার মতো, আপনি পতাকা হিসাবে চিহ্নিত বিল্ড সেটিংস সেট করতে কমান্ড লাইন ব্যবহার করতে পারেন। বিল্ড সেটিং এর নাম হল name=value সিনট্যাক্স ব্যবহার করে এর সম্পূর্ণ টার্গেট পাথ:

$ bazel build //my/target --//example:string_flag=some-value # allowed
$ bazel build //my/target --//example:string_flag some-value # not allowed

বিশেষ বুলিয়ান সিনট্যাক্স সমর্থিত:

$ bazel build //my/target --//example:boolean_flag
$ bazel build //my/target --no//example:boolean_flag

বিল্ড সেটিং উপনাম ব্যবহার করে

কমান্ড লাইনে পড়া সহজ করার জন্য আপনি আপনার বিল্ড সেটিং লক্ষ্য পথের জন্য একটি উপনাম সেট করতে পারেন। উপনামগুলি নেটিভ পতাকার মতোই কাজ করে এবং ডাবল-ড্যাশ বিকল্প সিনট্যাক্স ব্যবহার করে।

আপনার .bazelrc--flag_alias=ALIAS_NAME=TARGET_PATH যোগ করে একটি উপনাম সেট করুন। উদাহরণস্বরূপ, coffee একটি উপনাম সেট করতে:

# .bazelrc
build --flag_alias=coffee=//experimental/user/starlark_configurations/basic_build_setting:coffee-temp

সর্বোত্তম অভ্যাস: একটি উপনাম একাধিকবার সেট করার ফলে সবচেয়ে সাম্প্রতিকটি অগ্রাধিকার পায়। অনিচ্ছাকৃত পার্সিং ফলাফল এড়াতে অনন্য উপনাম নাম ব্যবহার করুন।

উপনাম ব্যবহার করতে, বিল্ড সেটিং লক্ষ্য পথের জায়গায় এটি টাইপ করুন। ব্যবহারকারীর .bazelrccoffee সেটের উপরের উদাহরণ সহ:

$ bazel build //my/target --coffee=ICED

পরিবর্তে

$ bazel build //my/target --//experimental/user/starlark_configurations/basic_build_setting:coffee-temp=ICED

সর্বোত্তম অভ্যাস: কমান্ড লাইনে উপনাম সেট করা সম্ভব হলেও, .bazelrc এ রেখে কমান্ড লাইনের বিশৃঙ্খলা হ্রাস করে।

লেবেল-টাইপ বিল্ড সেটিংস

শেষ থেকে শেষ উদাহরণ

অন্যান্য বিল্ড সেটিংস থেকে ভিন্ন, লেবেল-টাইপ করা সেটিংস build_setting নিয়ম প্যারামিটার ব্যবহার করে সংজ্ঞায়িত করা যায় না। পরিবর্তে, বেজেলের দুটি অন্তর্নির্মিত নিয়ম রয়েছে: label_flag এবং label_setting । এই নিয়মগুলি প্রকৃত লক্ষ্যের প্রদানকারীদের ফরোয়ার্ড করে যেখানে বিল্ড সেটিং সেট করা হয়েছে। label_flag এবং label_setting ট্রানজিশন দ্বারা পড়তে/লিখতে পারে এবং label_flag ব্যবহারকারী দ্বারা অন্যান্য build_setting নিয়মের মতো সেট করা যেতে পারে। তাদের একমাত্র পার্থক্য হল তারা কাস্টমলি সংজ্ঞায়িত করতে পারে না।

লেবেল-টাইপ করা সেটিংস শেষ পর্যন্ত দেরী-বাউন্ড ডিফল্টের কার্যকারিতা প্রতিস্থাপন করবে। লেট-বাউন্ড ডিফল্ট অ্যাট্রিবিউট হল লেবেল-টাইপ করা অ্যাট্রিবিউট যার চূড়ান্ত মান কনফিগারেশন দ্বারা প্রভাবিত হতে পারে। Starlark-এ, এটি configuration_field API-কে প্রতিস্থাপন করবে।

# example/rules.bzl
MyProvider = provider(fields = ["my_field"])

def _dep_impl(ctx):
    return MyProvider(my_field = "yeehaw")

dep_rule = rule(
    implementation = _dep_impl
)

def _parent_impl(ctx):
    if ctx.attr.my_field_provider[MyProvider].my_field == "cowabunga":
        ...

parent_rule = rule(
    implementation = _parent_impl,
    attrs = { "my_field_provider": attr.label() }
)

# example/BUILD
load("//example:rules.bzl", "dep_rule", "parent_rule")

dep_rule(name = "dep")

parent_rule(name = "parent", my_field_provider = ":my_field_provider")

label_flag(
    name = "my_field_provider",
    build_setting_default = ":dep"
)

সেটিংস তৈরি করুন এবং নির্বাচন করুন()

শেষ থেকে শেষ উদাহরণ

ব্যবহারকারীরা select() ব্যবহার করে বিল্ড সেটিংসে বৈশিষ্ট্যগুলি কনফিগার করতে পারেন। বিল্ড সেটিং লক্ষ্যগুলি config_setting এর flag_values ​​অ্যাট্রিবিউটে পাস করা যেতে পারে। কনফিগারেশনের সাথে মেলার মানটি একটি String হিসাবে পাস করা হয় তারপর ম্যাচিংয়ের জন্য বিল্ড সেটিংসের প্রকারে পার্স করা হয়।

config_setting(
    name = "my_config",
    flag_values = {
        "//example:favorite_flavor": "MANGO"
    }
)

ব্যবহারকারী-সংজ্ঞায়িত ট্রানজিশন

একটি কনফিগারেশন ট্রানজিশন বিল্ড গ্রাফের মধ্যে একটি কনফিগার করা লক্ষ্য থেকে অন্য রূপান্তরকে ম্যাপ করে।

যে নিয়মগুলি তাদের সেট করে তাতে অবশ্যই একটি বিশেষ বৈশিষ্ট্য অন্তর্ভুক্ত থাকতে হবে:

  "_allowlist_function_transition": attr.label(
      default = "@bazel_tools//tools/allowlists/function_transition_allowlist"
  )

ট্রানজিশন যোগ করে আপনি আপনার বিল্ড গ্রাফের আকার সহজেই বিস্ফোরিত করতে পারেন। এটি প্যাকেজগুলির একটি অনুমোদিত তালিকা সেট করে যেখানে আপনি এই নিয়মের লক্ষ্যগুলি তৈরি করতে পারেন। উপরের কোডব্লকের ডিফল্ট মান সবকিছুকে অনুমোদন করে। কিন্তু আপনি যদি আপনার নিয়ম কে ব্যবহার করছে তা সীমাবদ্ধ করতে চান, তাহলে আপনি সেই বৈশিষ্ট্যটিকে আপনার নিজস্ব কাস্টম অনুমোদন তালিকায় নির্দেশ করতে সেট করতে পারেন। পরিবর্তনগুলি কীভাবে আপনার বিল্ড কর্মক্ষমতাকে প্রভাবিত করতে পারে তা বোঝার জন্য আপনি যদি পরামর্শ বা সহায়তা চান তাহলে bazel-discuss@googlegroups.com-এর সাথে যোগাযোগ করুন৷

সংজ্ঞায়িত

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

আনুষ্ঠানিকভাবে, একটি রূপান্তর হল একটি ইনপুট কনফিগারেশন থেকে এক বা একাধিক আউটপুট কনফিগারেশনে একটি ফাংশন। বেশিরভাগ ট্রানজিশন হল 1:1 যেমন " --cpu=ppc দিয়ে ইনপুট কনফিগারেশন ওভাররাইড করুন"। 1:2+ ট্রানজিশনও থাকতে পারে তবে বিশেষ সীমাবদ্ধতার সাথে আসতে পারে।

স্টারলার্ক-এ, রূপান্তরগুলিকে অনেকটা নিয়মের মতো সংজ্ঞায়িত করা হয়, একটি সংজ্ঞায়িত transition() ফাংশন এবং একটি বাস্তবায়ন ফাংশন সহ।

# example/transitions/transitions.bzl
def _impl(settings, attr):
    _ignore = (settings, attr)
    return {"//example:favorite_flavor" : "MINT"}

hot_chocolate_transition = transition(
    implementation = _impl,
    inputs = [],
    outputs = ["//example:favorite_flavor"]
)

transition() ফাংশনটি একটি ইমপ্লিমেন্টেশন ফাংশন, পড়ার জন্য বিল্ড সেটিংসের একটি সেট ( inputs ) এবং লেখার জন্য বিল্ড সেটিংসের একটি সেট ( outputs ) নেয়। বাস্তবায়ন ফাংশন দুটি পরামিতি, settings এবং attr আছে। settings হল একটি অভিধান { String : Object } যা inputs প্যারামিটারে transition() থেকে ঘোষণা করা হয়েছে।

attr হল নিয়মের গুণাবলী এবং মানগুলির একটি অভিধান যার সাথে রূপান্তর সংযুক্ত করা হয়েছে। আউটগোয়িং এজ ট্রানজিশন হিসাবে সংযুক্ত করা হলে, এই অ্যাট্রিবিউটের মানগুলি সমস্ত পোস্ট-select() রেজোলিউশনে কনফিগার করা হয়। যখন একটি ইনকামিং এজ ট্রানজিশন হিসাবে সংযুক্ত করা হয়, তখন attr এ এমন কোনো বৈশিষ্ট্য অন্তর্ভুক্ত থাকে না যা তাদের মান সমাধান করতে একটি নির্বাচক ব্যবহার করে। যদি --foo এ একটি ইনকামিং এজ ট্রানজিশন অ্যাট্রিবিউট bar পড়ে এবং তারপরে অ্যাট্রিবিউট bar সেট করতে --foo তেও নির্বাচন করে, তাহলে ইনকামিং এজ ট্রানজিশনের জন্য ট্রানজিশনে bar ভুল মান পড়ার সুযোগ রয়েছে।

বাস্তবায়ন ফাংশন প্রয়োগ করার জন্য নতুন বিল্ড সেটিংস মানগুলির একটি অভিধান (বা একাধিক আউটপুট কনফিগারেশনের সাথে রূপান্তরের ক্ষেত্রে অভিধানের তালিকা) ফেরত দিতে হবে। প্রত্যাবর্তিত অভিধান কীসেটে অবশ্যই ট্রানজিশন ফাংশনের outputs প্যারামিটারে পাস করা বিল্ড সেটিংসের সেট থাকতে হবে। ট্রানজিশনের সময় একটি বিল্ড সেটিং আসলে পরিবর্তিত না হলেও এটি সত্য - এর আসল মান অবশ্যই প্রত্যাবর্তিত অভিধানে স্পষ্টভাবে পাস করতে হবে।

1:2+ রূপান্তর সংজ্ঞায়িত করা

শেষ থেকে শেষ উদাহরণ

আউটগোয়িং এজ ট্রানজিশন একটি একক ইনপুট কনফিগারেশনকে দুই বা ততোধিক আউটপুট কনফিগারেশনে ম্যাপ করতে পারে। মাল্টি-আর্কিটেকচার কোড বান্ডিল করে এমন নিয়ম সংজ্ঞায়িত করার জন্য এটি কার্যকর।

1:2+ রূপান্তরগুলি রূপান্তর বাস্তবায়ন ফাংশনে অভিধানগুলির একটি তালিকা ফিরিয়ে দিয়ে সংজ্ঞায়িত করা হয়।

# example/transitions/transitions.bzl
def _impl(settings, attr):
    _ignore = (settings, attr)
    return [
        {"//example:favorite_flavor" : "LATTE"},
        {"//example:favorite_flavor" : "MOCHA"},
    ]

coffee_transition = transition(
    implementation = _impl,
    inputs = [],
    outputs = ["//example:favorite_flavor"]
)

তারা কাস্টম কী সেট করতে পারে যা নিয়ম বাস্তবায়ন ফাংশন পৃথক নির্ভরতা পড়তে ব্যবহার করতে পারে:

# example/transitions/transitions.bzl
def _impl(settings, attr):
    _ignore = (settings, attr)
    return {
        "Apple deps": {"//command_line_option:cpu": "ppc"},
        "Linux deps": {"//command_line_option:cpu": "x86"},
    }

multi_arch_transition = transition(
    implementation = _impl,
    inputs = [],
    outputs = ["//command_line_option:cpu"]
)

ট্রানজিশন সংযুক্ত করা হচ্ছে

শেষ থেকে শেষ উদাহরণ

ট্রানজিশন দুটি জায়গায় সংযুক্ত করা যেতে পারে: ইনকামিং প্রান্ত এবং বহির্গামী প্রান্ত। কার্যকরীভাবে এর অর্থ হল নিয়মগুলি তাদের নিজস্ব কনফিগারেশন (আগত প্রান্তের স্থানান্তর) এবং তাদের নির্ভরতাগুলির কনফিগারেশন (আউটগোয়িং এজ ট্রানজিশন) স্থানান্তর করতে পারে।

দ্রষ্টব্য: বর্তমানে স্টারলার্ক ট্রানজিশনগুলিকে নেটিভ নিয়মে সংযুক্ত করার কোন উপায় নেই। আপনার যদি এটি করার প্রয়োজন হয়, তাহলে সমাধান খুঁজে বের করতে সহায়তার জন্য bazel-discuss@googlegroups.com-এ যোগাযোগ করুন।

ইনকামিং প্রান্ত পরিবর্তন

ইনকামিং এজ ট্রানজিশন একটি transition অবজেক্ট সংযুক্ত করে সক্রিয় করা হয় ( transition() ) দ্বারা Rule( rule() এর cfg প্যারামিটারে:

# example/rules.bzl
load("example/transitions:transitions.bzl", "hot_chocolate_transition")
drink_rule = rule(
    implementation = _impl,
    cfg = hot_chocolate_transition,
    ...

ইনকামিং এজ ট্রানজিশন অবশ্যই 1:1 ট্রানজিশন হতে হবে।

বহির্গামী প্রান্ত পরিবর্তন

আউটগোয়িং এজ ট্রানজিশনগুলি একটি অ্যাট্রিবিউটের cfg প্যারামিটারে একটি transition অবজেক্ট ( transition() ) এর মাধ্যমে সংযুক্ত করে সক্রিয় করা হয়:

# example/rules.bzl
load("example/transitions:transitions.bzl", "coffee_transition")
drink_rule = rule(
    implementation = _impl,
    attrs = { "dep": attr.label(cfg = coffee_transition)}
    ...

আউটগোয়িং এজ ট্রানজিশন 1:1 বা 1:2+ হতে পারে।

এই কীগুলি কীভাবে পড়তে হয় তার জন্য ট্রানজিশন সহ অ্যাট্রিবিউট অ্যাক্সেস করা দেখুন।

নেটিভ অপশনে ট্রানজিশন

শেষ থেকে শেষ উদাহরণ

স্টারলার্ক ট্রানজিশনগুলি বিকল্প নামের একটি বিশেষ উপসর্গের মাধ্যমে নেটিভ বিল্ড কনফিগারেশন বিকল্পগুলিতে রিড এবং রাইট ঘোষণা করতে পারে।

# example/transitions/transitions.bzl
def _impl(settings, attr):
    _ignore = (settings, attr)
    return {"//command_line_option:cpu": "k8"}

cpu_transition = transition(
    implementation = _impl,
    inputs = [],
    outputs = ["//command_line_option:cpu"]

অসমর্থিত নেটিভ বিকল্প

Bazel "//command_line_option:define" এর সাথে --define এ রূপান্তর সমর্থন করে না। পরিবর্তে, একটি কাস্টম বিল্ড সেটিং ব্যবহার করুন। সাধারণভাবে, --define এর নতুন ব্যবহার বিল্ড সেটিংসের পক্ষে নিরুৎসাহিত করা হয়।

Bazel --config এ রূপান্তর সমর্থন করে না। কারণ --config হল একটি "সম্প্রসারণ" পতাকা যা অন্যান্য ফ্ল্যাগে প্রসারিত হয়।

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

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

ট্রানজিশন একাধিক বিল্ড সেটিংসের অনুমতি দেয়

একাধিক মান অনুমোদন করে এমন বিল্ড সেটিংস সেট করার সময়, সেটিংটির মান একটি তালিকার সাথে সেট করতে হবে।

# example/buildsettings/build_settings.bzl
string_flag = rule(
    implementation = _impl,
    build_setting = config.string(flag = True, allow_multiple = True)
)
# example/BUILD
load("//example/buildsettings:build_settings.bzl", "string_flag")
string_flag(name = "roasts", build_setting_default = "medium")
# example/transitions/rules.bzl
def _transition_impl(settings, attr):
    # Using a value of just "dark" here will throw an error
    return {"//example:roasts" : ["dark"]},

coffee_transition = transition(
    implementation = _transition_impl,
    inputs = [],
    outputs = ["//example:roasts"]
)

নো-অপ ট্রানজিশন

যদি একটি ট্রানজিশন {} , [] , বা None ফেরত দেয়, তাহলে এটি সমস্ত সেটিংসকে তাদের মূল মানগুলিতে রাখার জন্য সংক্ষিপ্ত বিবরণ। প্রতিটি আউটপুটকে স্পষ্টভাবে সেট করার চেয়ে এটি আরও সুবিধাজনক হতে পারে।

# example/transitions/transitions.bzl
def _impl(settings, attr):
    _ignore = (attr)
    if settings["//example:already_chosen"] is True:
      return {}
    return {
      "//example:favorite_flavor": "dark chocolate",
      "//example:include_marshmallows": "yes",
      "//example:desired_temperature": "38C",
    }

hot_chocolate_transition = transition(
    implementation = _impl,
    inputs = ["//example:already_chosen"],
    outputs = [
        "//example:favorite_flavor",
        "//example:include_marshmallows",
        "//example:desired_temperature",
    ]
)

ট্রানজিশন সহ বৈশিষ্ট্যগুলি অ্যাক্সেস করা

শেষ থেকে শেষ উদাহরণ

একটি বহির্গামী প্রান্তে একটি রূপান্তর সংযুক্ত করার সময় (পরিবর্তনটি 1:1 বা 1:2+ রূপান্তর যাই হোক না কেন), ctx.attr একটি তালিকা হতে বাধ্য হয় যদি এটি ইতিমধ্যে না থাকে। এই তালিকার উপাদানগুলির ক্রম অনির্দিষ্ট।

# example/transitions/rules.bzl
def _transition_impl(settings, attr):
    return {"//example:favorite_flavor" : "LATTE"},

coffee_transition = transition(
    implementation = _transition_impl,
    inputs = [],
    outputs = ["//example:favorite_flavor"]
)

def _rule_impl(ctx):
    # Note: List access even though "dep" is not declared as list
    transitioned_dep = ctx.attr.dep[0]

    # Note: Access doesn't change, other_deps was already a list
    for other dep in ctx.attr.other_deps:
      # ...


coffee_rule = rule(
    implementation = _rule_impl,
    attrs = {
        "dep": attr.label(cfg = coffee_transition)
        "other_deps": attr.label_list(cfg = coffee_transition)
    })

যদি রূপান্তরটি 1:2+ হয় এবং কাস্টম কী সেট করে, ctx.split_attr প্রতিটি কী-এর জন্য পৃথক ডিপ পড়তে ব্যবহার করা যেতে পারে:

# example/transitions/rules.bzl
def _impl(settings, attr):
    _ignore = (settings, attr)
    return {
        "Apple deps": {"//command_line_option:cpu": "ppc"},
        "Linux deps": {"//command_line_option:cpu": "x86"},
    }

multi_arch_transition = transition(
    implementation = _impl,
    inputs = [],
    outputs = ["//command_line_option:cpu"]
)

def _rule_impl(ctx):
    apple_dep = ctx.split_attr.dep["Apple deps"]
    linux_dep = ctx.split_attr.dep["Linux deps"]
    # ctx.attr has a list of all deps for all keys. Order is not guaranteed.
    all_deps = ctx.attr.dep

multi_arch_rule = rule(
    implementation = _rule_impl,
    attrs = {
        "dep": attr.label(cfg = multi_arch_transition)
    })

এখানে সম্পূর্ণ উদাহরণ দেখুন।

প্ল্যাটফর্ম এবং টুলচেইনের সাথে একীকরণ

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

মেমরি এবং কর্মক্ষমতা বিবেচনা

আপনার বিল্ডে ট্রানজিশন যোগ করা, এবং সেইজন্য নতুন কনফিগারেশনগুলি খরচ করে: বড় বিল্ড গ্রাফ, কম বোধগম্য বিল্ড গ্রাফ এবং ধীর বিল্ড। আপনার বিল্ড নিয়মে রূপান্তর ব্যবহার করার সময় বিবেচনা করার সময় এই খরচগুলি বিবেচনা করা মূল্যবান। কিভাবে একটি ট্রানজিশন আপনার বিল্ড গ্রাফের সূচকীয় বৃদ্ধি তৈরি করতে পারে তার একটি উদাহরণ নিচে দেওয়া হল।

খারাপ আচরণ করা তৈরি করে: একটি কেস স্টাডি

Scalability graph

চিত্র 1. স্কেলেবিলিটি গ্রাফ একটি শীর্ষ স্তরের লক্ষ্য এবং এর নির্ভরতা দেখাচ্ছে।

এই গ্রাফটি একটি শীর্ষ স্তরের লক্ষ্য দেখায়, //pkg:app, যা দুটি লক্ষ্যের উপর নির্ভর করে, a //pkg:1_0 এবং //pkg:1_1। এই উভয় লক্ষ্য দুটি লক্ষ্যের উপর নির্ভর করে, //pkg:2_0 এবং //pkg:2_1। এই উভয় লক্ষ্য দুটি লক্ষ্যের উপর নির্ভর করে, //pkg:3_0 এবং //pkg:3_1। এটি //pkg:n_0 এবং //pkg:n_1 পর্যন্ত চলতে থাকে, যা উভয়ই একটি একক লক্ষ্যের উপর নির্ভর করে, //pkg:dep।

বিল্ডিং //pkg:app জন্য প্রয়োজন \(2n+2\) টার্গেট:

  • //pkg:app
  • //pkg:dep
  • //pkg:i_0 এবং //pkg:i_1 \(i\) \([1..n]\)এ

কল্পনা করুন যে আপনি প্রয়োগ করেছেন ) একটি পতাকা --//foo:owner=<STRING> এবং //pkg:i_b প্রযোজ্য

depConfig = myConfig + depConfig.owner="$(myConfig.owner)$(b)"

অন্য কথায়, //pkg:i_b এর সমস্ত ডিপের জন্য --owner এর পুরানো মানের সাথে b যোগ করে।

এটি নিম্নলিখিত কনফিগার করা লক্ষ্যগুলি তৈরি করে:

//pkg:app                              //foo:owner=""
//pkg:1_0                              //foo:owner=""
//pkg:1_1                              //foo:owner=""
//pkg:2_0 (via //pkg:1_0)              //foo:owner="0"
//pkg:2_0 (via //pkg:1_1)              //foo:owner="1"
//pkg:2_1 (via //pkg:1_0)              //foo:owner="0"
//pkg:2_1 (via //pkg:1_1)              //foo:owner="1"
//pkg:3_0 (via //pkg:1_0 → //pkg:2_0)  //foo:owner="00"
//pkg:3_0 (via //pkg:1_0 → //pkg:2_1)  //foo:owner="01"
//pkg:3_0 (via //pkg:1_1 → //pkg:2_0)  //foo:owner="10"
//pkg:3_0 (via //pkg:1_1 → //pkg:2_1)  //foo:owner="11"
...

//pkg:dep dep \(2^n\) কনফিগার করা লক্ষ্যগুলি তৈরি করে: config.owner= l10n-placeholder7-এ সমস্ত \(b_i\) এর জন্য config.owner= "\(b_0b_1...b_n\)\(\{0,1\}\)।

এটি বিল্ড গ্রাফটিকে লক্ষ্য গ্রাফের চেয়ে দ্রুতগতিতে বড় করে, সংশ্লিষ্ট মেমরি এবং কর্মক্ষমতা ফলাফল সহ।

TODO: এই সমস্যাগুলির পরিমাপ এবং প্রশমনের জন্য কৌশল যোগ করুন।

আরও পড়া

বিল্ড কনফিগারেশন পরিবর্তন করার বিষয়ে আরো বিস্তারিত জানার জন্য, দেখুন: