تتناول هذه الصفحة أساسيات استخدام وحدات الماكرو، وتشمل حالات استخدام نموذجية وتصحيح الأخطاء والاصطلاحات.
وحدة الماكرو هي دالة تُسمى من ملف BUILD يمكنها إنشاء قواعد.
تُستخدم وحدات الماكرو بشكل أساسي لتغليف الرموز الحالية وإعادة استخدامها للرموز ووحدات أخرى أخرى. في نهاية
مرحلة التحميل، لم تعد وحدات الماكرو موجودة، ولا يطّلع Bazel إلا على المجموعة الملموسة من القواعد التي تم إنشاء مثيل لها.
الاستخدام
تتمثل حالة الاستخدام النموذجية لوحدة الماكرو عندما تريد إعادة استخدام قاعدة.
على سبيل المثال، تُنشئ Gerule في ملف BUILD ملفًا باستخدام //:generator باستخدام وسيطة some_arg تم ترميزها نهائيًا في الأمر:
genrule(
name = "file",
outs = ["file.txt"],
cmd = "$(location //:generator) some_arg > $@",
tools = ["//:generator"],
)
إذا أردت إنشاء المزيد من الملفات باستخدام وسيطات مختلفة، يمكنك استخراج هذا الرمز إلى دالة ماكرو. لنطلب ماكرو file_generator الذي يضمّ معلَمتَي name وarg. استبدِل قاعدة السمات بما يلي:
load("//path:generator.bzl", "file_generator")
file_generator(
name = "file",
arg = "some_arg",
)
file_generator(
name = "file-two",
arg = "some_arg_two",
)
file_generator(
name = "file-three",
arg = "some_arg_three",
)
يمكنك هنا تحميل الرمز file_generator من ملف .bzl يقع في حزمة //path. بوضع تعريفات الدوال الكبيرة في ملف
.bzl منفصل، تحافظ على ملفات BUILD نظيفة وبيانات تعريفية، ويمكن تحميل الملف .bzl
من أي حزمة في مساحة العمل.
وأخيرًا، في نظام التشغيل path/generator.bzl، اكتب تعريف وحدة الماكرو لتلخيص تعريف المعلّمة الأصلية ومعلّمته:
def file_generator(name, arg, visibility=None):
native.genrule(
name = name,
outs = [name + ".txt"],
cmd = "$(location //:generator) %s > $@" % arg,
tools = ["//:generator"],
visibility = visibility,
)
يمكنك أيضًا استخدام وحدات الماكرو لسلسلة القواعد معًا. يعرض هذا المثال السلسلة ذات القواعد العامة، حيث تستخدم قاعدة التوزيع مخرجات قاعدة سابقة كإدخالات:
def chained_genrules(name, visibility=None):
native.genrule(
name = name + "-one",
outs = [name + ".one"],
cmd = "$(location :tool-one) $@",
tools = [":tool-one"],
visibility = ["//visibility:private"],
)
native.genrule(
name = name + "-two",
srcs = [name + ".one"],
outs = [name + ".two"],
cmd = "$(location :tool-two) $< $@",
tools = [":tool-two"],
visibility = visibility,
)
يحدّد المثال قيمة مستوى رؤية للقاعدة الثانية فقط. ويسمح ذلك لمؤلفي وحدات الماكرو بإخفاء مخرجات القواعد المتوسطة من الاعتماد عليها من خلال أهداف أخرى في مساحة العمل.
توسيع وحدات الماكرو
إذا أردت التعرّف على وظيفة وحدة ماكرو، استخدِم الأمر query مع --output=build للاطّلاع على النموذج الموسّع:
$ bazel query --output=build :file
# /absolute/path/test/ext.bzl:42:3
genrule(
name = "file",
tools = ["//:generator"],
outs = ["//test:file.txt"],
cmd = "$(location //:generator) some_arg > $@",
)
إنشاء مثيل للقواعد المدمجة مع المحتوى
يمكن تنفيذ القواعد المدمجة مع المحتوى (القواعد التي لا تحتاج إلى بيان load())
من الوحدة الرئيسية.
def my_macro(name, visibility=None):
native.cc_library(
name = name,
srcs = ["main.cc"],
visibility = visibility,
)
إذا كنت بحاجة إلى معرفة اسم الحزمة (على سبيل المثال، ملف BUILD الذي يستدعي وحدة الماكرو)، استخدِم الدالة original.package_name().
تجدر الإشارة إلى أنه لا يمكن استخدام native إلا في ملفات .bzl، وليس في ملفات WORKSPACE أو
BUILD.
دقة التصنيف في وحدات الماكرو
بما أنه يتم تقييم وحدات الماكرو في مرحلة التحميل،
يتم تفسير سلاسل التصنيفات، مثل "//foo:bar" التي تحدث في وحدة ماكرو،
بالاستناد إلى ملف BUILD الذي يتم فيه استخدام وحدة الماكرو بدلاً من
ملف .bzl الذي يتم تحديده. وبشكل عام، هذا السلوك غير مرغوب فيه لوحدات الماكرو التي يُقصد استخدامها في مستودعات أخرى، مثلاً لأنها جزء من مجموعة Starlark المنشورة.
للحصول على السلوك نفسه كما هو الحال مع قواعد Starlark، عليك وضع سلاسل التصنيفات باستخدام
أداة إنشاء Label:
# @my_ruleset//rules:defs.bzl
def my_cc_wrapper(name, deps = [], **kwargs):
native.cc_library(
name = name,
deps = deps + select({
# Due to the use of Label, this label is resolved within @my_ruleset,
# regardless of its site of use.
Label("//config:needs_foo"): [
# Due to the use of Label, this label will resolve to the correct target
# even if the canonical name of @dep_of_my_ruleset should be different
# in the main workspace, such as due to repo mappings.
Label("@dep_of_my_ruleset//tools:foo"),
],
"//conditions:default": [],
}),
**kwargs,
)
تصحيح الأخطاء
سيوضّح لك
bazel query --output=build //my/path:allالشكل الذي يظهر به ملفBUILDبعد التقييم. يتم توسيع جميع وحدات الماكرو والكرات الأرضية والحلقات. الحد المعروف: لا يتم عرض تعبيراتselectحاليًا في الإخراج.ويمكنك فلترة النتائج استنادًا إلى
generator_function(الدالة التي أنشأت القواعد) أوgenerator_name(سمة الاسم لوحدة الماكرو):bash $ bazel query --output=build 'attr(generator_function, my_macro, //my/path:all)'لمعرفة مكان إنشاء القاعدة
fooبالضبط في ملفBUILD، يمكنك تجربة الخدعة التالية. أدرِج هذا السطر بالقرب من أعلى ملفBUILD:cc_library(name = "foo"). تشغيل Bazel وستحصل على استثناء عند إنشاء القاعدةfoo(بسبب تعارض في الاسم)، الذي سيعرض لك تتبُّع تسلسل استدعاء الدوال البرمجية بالكامل.يمكنك أيضًا استخدام الطباعة لتصحيح الأخطاء. وتعرض الرسالة كسطر سجلّ
DEBUGأثناء مرحلة التحميل. باستثناء حالات نادرة، يمكنك إزالة استدعاءاتprintأو جعلها مشروطة ضمن معلَمةdebuggingالتي يتم ضبطها تلقائيًا علىFalseقبل إرسال الرمز إلى المستودع.
الأخطاء
إذا أردت حدوث خطأ، استخدِم الدالة fail.
اشرح للمستخدم بوضوح الخطأ الذي حدث، وكيفية إصلاح ملف BUILD.
لا يمكن اكتشاف خطأ.
def my_macro(name, deps, visibility=None):
if len(deps) < 2:
fail("Expected at least two values in deps")
# ...
مؤتمرات
جميع الدوال العامة (الدوال التي لا تبدأ بشرطة سفلية) التي يجب أن تتضمّن وسيطة
name. يجب ألا تكون هذه الوسيطة اختيارية (بدون't تقديم قيمة تلقائية).يجب أن تستخدم الدوال العامة سلسلة نصية تتبع اصطلاحات Python.
في الملفات
BUILD، يجب أن تكون وسيطةnameلوحدات الماكرو وحدات وسيطة للكلمات الرئيسية (وليس وسيطة موضعية).يجب أن تتضمن سمة
nameللقواعد التي يتم إنشاؤها بواسطة وحدة ماكرو وسيطة الاسم كبادئة. على سبيل المثال، تستطيعmacro(name = "foo")إنشاءcc_libraryfooوقاعدة عامةfoo_gen.في معظم الحالات، يجب أن تكون المعلّمات الاختيارية ذات قيمة تلقائية
None. يمكن تمريرNoneمباشرةً إلى القواعد الأصلية، حيث يتم التعامل معها بالطريقة نفسها كما لو لم يتم تمريرها في أي وسيطة. وبالتالي، لا حاجة إلى استبدالها بـ0أوFalseأو[]لهذا الغرض. وبدلاً من ذلك، يجب أن تؤكّد وحدة الماكرو القواعد التي تنشئها، لأن الإعدادات التلقائية قد تكون معقّدة أو قد تتغير بمرور الوقت. وبالإضافة إلى ذلك، تبدو المعلّمة التي يتم ضبطها صراحةً على قيمتها التلقائية مختلفة عن معلَمة لم يتم ضبطها مطلقًا (أو تم ضبطها علىNone) عند الوصول إليها من خلال لغة طلب البحث أو العناصر الداخلية في نظام الإصدار.يجب أن تحتوي وحدات الماكرو على وسيطة
visibilityاختيارية.