تغطي هذه الصفحة المزايا والاستخدامات الأساسية لتهيئات 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 إذا كنت تريد الحصول على نصائح أو مساعدة لفهم كيفية تأثير عمليات النقل في أداء تطبيقك.
التعريف
تحدد الانتقالات تغييرات الضبط بين القواعد. على سبيل المثال، يتم التعامل مع طلب مثل "؛الاعتمادية على وحدة معالجة مركزية (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"]
)
إرفاق عمليات النقل
يمكن إرفاق التحويلات. ويعني هذا بشكل فعّال أن القواعد يمكن أن تنقل عمليات الضبط الخاصة بها (الانتقال الداخلي) وتحقيق الربح من عمليات الاعتمادية'؛ وعمليات الضبط (الانتقال الحاد).
ملاحظة: لا تتوفّر حاليًا طريقة لإرفاق عمليات النقل من 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\}\).
وهذا يجعل الرسم البياني للإصدار أكبر من الرسم البياني المستهدف بشكل سريع، مع الذاكرة المقابلة وعواقب الأداء.
المهام: يمكنك إضافة استراتيجيات لقياس هذه المشاكل والحد منها.
قراءة المزيد
لمزيد من التفاصيل حول تعديل عمليات ضبط الإصدار، يُرجى الاطِّلاع على:
- إصدار Starlark
- مخطّط شركة Bazel Configurability Road
- مجموعة كاملة من الأمثلة الشاملة