الإعدادات

تغطي هذه الصفحة المزايا والاستخدامات الأساسية لتهيئات Starlark، Bazel's API لتخصيص تخصيص تصميم مشروعك. ويشمل ذلك كيفية تحديد إعدادات الإصدار وتقديم أمثلة.

ويتيح ذلك ما يلي:

  • تحديد علامات مخصّصة لمشروعك، بدون الحاجة إلى استخدام --define
  • كتابة انتقالات لإعداد الانخفاضات في عمليات الضبط المختلفة عن العناصر الرئيسية (مثل --compilation_mode=opt أو --cpu=arm)
  • الحصول على إعدادات تلقائية أفضل في القواعد (مثل إنشاء //my:android_app تلقائيًا باستخدام حزمة تطوير برامج (SDK) محدَّدة)

والمزيد، وكل ذلك من ملفات .bzl (لا حاجة إلى إصدار Bazel). اطّلِع على العمود bazelbuild/examples للاطّلاع على أمثلة.

إعدادات الإصدار التي يحددها المستخدم

إنّ إعداد الإصدار هو جزء واحد من معلومات الضبط. يمكنك اعتبار عملية الضبط كخريطة مفتاح/قيمة. ينتج عن ضبط --cpu=ppc و--copt="-DFoo" إعدادًا يشبه {cpu: ppc, copt: "-DFoo"}. كل إدخال هو إعداد إصدار.

العلامات التقليدية مثل cpu وcopt هي إعدادات محلية، ويتم تحديد مفاتيحها ويتم ضبط قيمها داخل رمز JavaScript المحلي للبازارات. ولا يمكن لمستخدمي Bazel الاطّلاع عليها وكتابتها إلا من خلال سطر الأوامر وواجهات برمجة التطبيقات الأخرى التي يتم الاحتفاظ بها في الأساس. يتطلب تغيير العلامات الأصلية وواجهات برمجة التطبيقات التي تعرضها إصدارًا من البازلاء. يتم تحديد إعدادات الإصدار التي يحددها المستخدم في ملفات .bzl (وبالتالي، لا تحتاج إلى إصدار مخبأ لتسجيل التغييرات). ويمكن تحديدها أيضًا من خلال سطر الأوامر (إذا كان قد تم تصنيفها على أنها flags، يمكنك الاطّلاع على المزيد أدناه)، ولكن يمكن ضبطها أيضًا من خلال عمليات النقل التي يحدّدها المستخدم.

تعريف إعدادات الإصدار

مثال مفصّل

المعلَمة build_setting rule()

إعدادات الإصدار هي قواعد مثل أي قاعدة أخرى ويتم التفريق بينها باستخدام الدالة Starlark rule() build_setting.

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

تستخدم السمة build_setting دالة تحدّد نوع إعداد الإصدار. يقتصر النوع على مجموعة من أنواع Starlark الأساسية، مثل bool وstring. ولمزيد من التفاصيل، يمكنك الاطّلاع على مستندات وحدة config. يمكن إجراء كتابة أكثر تعقيدًا في قاعدة تنفيذ القاعدة. المزيد من المعلومات أدناه.

تستخدم وظائف config الخاصة بالوحدة "'s" معلَمة منطقية اختيارية، flag، والتي يتم ضبطها على "خطأ" تلقائيًا. وإذا تم ضبط flag على "صحيح"، يمكن للمستخدمين أيضًا ضبط إعداد الإصدار على سطر الأوامر وعلى كتّاب القواعد عبر القيم التلقائية والانتقالات. يجب ألا يكون المستخدمون قادرين على ضبط جميع الإعدادات. على سبيل المثال، إذا كنت ككاتب قواعد لديك بعض وضع تصحيح الأخطاء الذي تريد تشغيله داخل قواعد الاختبار، فإنك لا تريد منح المستخدمين القدرة على تفعيل هذه الميزة بشكل عشوائي ضمن قواعد أخرى غير اختبارية.

استخدام ctx.build_setting_value

مثل جميع القواعد، تتضمن قواعد الإعداد وظائف التنفيذ. يمكن الوصول إلى القيمة الأساسية من نوع Starlark لإعدادات الإصدار باستخدام الطريقة 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 مجموعة من الإعدادات المحددة مسبقًا التي يمكنك إنشاء مثيل لها بدون الحاجة إلى كتابة Starlark مخصّص.

مثلاً، لتحديد إعداد يقبل مجموعة محدودة من قيم السلسلة:

# 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 لم يعد موجودًا ككائن ثابت في عالم إعداد Starlark، فإن إحدى طرق ترجمة هذا المفهوم هي استخدام مجموعات من السمات الضمنية الشائعة. على سبيل المثال:

# 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

استخدام الأسماء المستعارة لإعدادات الإصدار

يمكنك تحديد اسم مستعار لمسار هدف إعداد الإصدار لتسهيل قراءته في سطر الأوامر. وتعمل الأسماء المستعارة بشكل مماثل للعلامات الأصلية وتستفيد أيضًا من بنية خيار الشرطة المزدوجة.

يمكنك ضبط الاسم المستعار من خلال إضافة --flag_alias=ALIAS_NAME=TARGET_PATH إلى .bazelrc . مثلاً، لضبط الاسم المستعار على coffee:

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

أفضل الممارسات: يؤدي تحديد اسم مستعار للبريد الإلكتروني عدة مرات إلى الأولوية على أحدثها. يمكنك استخدام أسماء مستعارة فريدة لتجنّب نتائج التحليل غير المقصودة.

لاستخدام الاسم المستعار، اكتبه بدلاً من مسار استهداف إعداد الإصدار. باستخدام المثال أعلاه لعنصر coffee الذي تم ضبطه في .bazelrc للمستخدم:

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

# 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(). يمكن تمرير أهداف إعداد الإصدار إلى السمة flag_values في config_setting. يتم تمرير قيمة مطابقة الضبط إلى شكل 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-talk@googlegroups.com إذا كنت تريد الحصول على نصائح أو مساعدة لفهم كيفية تأثير عمليات النقل في أداء تطبيقك.

التعريف

تحدد الانتقالات تغييرات الضبط بين القواعد. على سبيل المثال، يتم التعامل مع طلب مثل &quot؛الاعتمادية على وحدة معالجة مركزية (CPU) مختلفة عن وحدة المعالجة المركزية (CPU) التابعة لها وما يليها: عملية نقل.

رسميًا، عملية النقل هي وظيفة من تهيئة إدخال إلى تهيئة إخراج واحدة أو أكثر. وتكون معظم الانتقالات 1:1، مثل "إلغاء ضبط التهيئة مع --cpu=ppc&;;;;. ويمكن أيضًا وجود انتقالات 1:2 أو أكثر ولكن مع فرض قيود خاصة.

في Starlark، يتم تحديد عمليات النقل إلى حد كبير مثل القواعد، مع خاصية 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 هو قاموس للسمات وقيم القاعدة التي يتم ربط عملية النقل بها. عندما يتم إرفاقها باعتبارها انتقالًا حوافًا صادرًا، تكون جميع قيم هذه السمات قد تم إعدادها بدقة بعد post-select(). وعند إرفاقها كعملية انتقال على الحافة، لا يتضمن attr أي سمات تستخدم أداة اختيار لحل قيمتها. إذا كان انتقال الحواف الواردة على --foo يقرأ السمة bar ثم يختارها أيضًا على --foo لضبط السمة bar، ثمّة فرصة للانتقال إلى الحافة الواردة لقراءة القيمة غير الصحيحة لـ 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"]
)

إرفاق عمليات النقل

مثال مفصّل

يمكن إرفاق التحويلات. ويعني هذا بشكل فعّال أن القواعد يمكن أن تنقل عمليات الضبط الخاصة بها (الانتقال الداخلي) وتحقيق الربح من عمليات الاعتمادية&#39؛ وعمليات الضبط (الانتقال الحاد).

ملاحظة: لا تتوفّر حاليًا طريقة لإرفاق عمليات النقل من Starlark إلى القواعد الأصلية. إذا احتجت إلى إجراء ذلك، يُرجى التواصل مع bazel-مناقشة@googlegroups.com للحصول على مساعدة في إيجاد الحلول.

انتقالات الحواف الواردة

يتم تفعيل عمليات نقل الحواف الواردة من خلال إرفاق عنصر transition (تم إنشاؤه من قِبل transition()) إلى معلَمة rule()'s cfg:

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

يجب أن تكون انتقالات الحواف الواردة هي عمليات انتقال بين شخصين.

عمليات نقل الحواف الصادرة

يتم تفعيل عمليات نقل الحواف الصادرة من خلال إرفاق عنصر transition (تم إنشاؤه من خلال transition()) إلى معلَمة cfg للسمة:

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

اطّلِع على الوصول إلى السمات باستخدام عمليات النقل للتعرّف على كيفية قراءة هذه المفاتيح.

الانتقالات في الخيارات المدمجة مع المحتوى

مثال مفصّل

يمكن أيضًا الانتقالات من Starlark إلى الإعلان والقراءة والكتابة على خيارات ضبط الإصدار الأصلي عبر بادئة خاصة إلى اسم الخيار.

# 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 النقل في --define باستخدام "//command_line_option:define". وبدلاً من ذلك، يمكنك استخدام إعداد إصدار مخصّص. بشكل عام، لا ننصح باستخدام الاستخدامات الجديدة لـ --define في ما يتعلّق بإعدادات الإصدار.

لا يدعم Bazel النقل في --config. ويرجع السبب في ذلك إلى أنّ --config هو علامة اقتباس &توسيع، وتكون قابلة للتوسع لتشمل علامات أخرى.

بشدة، قد يتضمن --config علامات لا تؤثر في إعداد الإصدار، مثل --spawn_strategy . ولا يمكن ربط هذه العلامات بالاستهدافات الفردية من خلال تصميم هذه البازلاء. وهذا يعني أنه لا توجد طريقة متناسقة لتطبيقها أثناء عمليات النقل.

كحل بديل، يمكنك تصنيف العلامات صراحةً التي تُعد جزءًا من الضبط في عملية النقل. ويتطلب ذلك الحفاظ على امتداد --config's في مكانين، وهو ما يشكّل مشكلة معروفة في واجهة المستخدم.

الانتقالات عند تفعيل إعدادات الإصدار المتعدّدة

عند ضبط إعدادات الإصدار التي تسمح بقيم متعدّدة، يجب ضبط قيمة الإعداد باستخدام قائمة.

# 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: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، بحلّ لسلسلة الأدوات. في المستقبل، من المرجح أن يتم استبدال عمليات النقل الصريحة على هذه الأنواع من العلامات بالانتقال إلى النظام الأساسي المستهدف.

اعتبارات الذاكرة والأداء

تأتي إضافة انتقالات، وبالتالي تهيئات جديدة إلى إصدارك مقابل تكلفة: مخططات رسومية أكبر ورسوم بيانية أقل شمولية وتصميمات أبطأ. ومن المفيد مراعاة هذه التكاليف عند التفكير في استخدام التحويلات في قواعد الإصدار. في ما يلي مثال على كيفية تأثير الانتقال في النمو الهائل في الرسم البياني للإصدار.

نماذج سيئة السلوك: دراسة حالة

الرسم البياني لقابلية التوسّع

الشكل 1. رسم بياني لقابلية التطور يعرض هدف المستوى الأعلى وتبعياته

يعرض هذا الرسم البياني هدف المستوى الأعلى، //pkg:app، الذي يعتمد على هدفين: //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 b بالقيمة القديمة "--owner" لجميع الانخفاضات.

وينتج عن الأهداف التي تم ضبطها التالية:

//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 \(2^n\) الأهداف التي تم إعدادها: config.owner= "\(b_0b_1...b_n\)" للجميع \(b_i\) في \(\{0,1\}\).

وهذا يجعل الرسم البياني للإصدار أكبر من الرسم البياني المستهدف بشكل سريع، مع الذاكرة المقابلة وعواقب الأداء.

المهام: يمكنك إضافة استراتيجيات لقياس هذه المشاكل والحد منها.

قراءة المزيد

لمزيد من التفاصيل حول تعديل عمليات ضبط الإصدار، يُرجى الاطِّلاع على: