الأنظمة الأساسية

يستطيع Bazel إنشاء الرموز واختبارها على مجموعة متنوعة من الأجهزة وأنظمة التشغيل وإعدادات النظام باستخدام العديد من الإصدارات المختلفة من أدوات الإنشاء مثل الرابطات وبرامج التجميع. للمساعدة في إدارة هذا التعقيد، يتّبع Bazel مفهومًا مثل القيود والمنصات. ويتمثّل القيد في البُعد الذي قد تختلف فيه بيئات الإنشاء أو الإنتاج، مثل بنية وحدة المعالجة المركزية (CPU)، أو توفّر وحدة معالجة رسومات (GPU) أو عدمها، أو إصدار برنامج التجميع المثبّت على النظام. النظام الأساسي هو مجموعة معيّنة من الخيارات لهذه القيود، وتمثّل الموارد المحدّدة المتوفرة في بعض البيئات.

إنّ وضع نموذج للبيئة كمنصّة يساعد Bazel في اختيار سلاسل الأدوات المناسبة تلقائيًا لتنفيذ إجراءات الإصدار. يمكن أيضًا استخدام الأنظمة الأساسية مع القاعدة config_setting لكتابة سمات قابلة للضبط.

يتعرّف Bazel على ثلاثة أدوار قد تؤديها المنصة:

  • المضيف: النظام الأساسي الذي يتم تشغيل Bazel نفسه عليه.
  • التنفيذ - نظام أساسي تُستخدم فيه أدوات الإصدار لتنفيذ إجراءات الإصدار بهدف إنتاج المخرجات المتوسطة والنهائية.
  • Target - هي نظام أساسي يتم فيه تنفيذ الناتج النهائي وتنفيذه.

يدعم Bazel سيناريوهات الإصدار التالية في ما يتعلّق بالمنصّات:

  • إصدارات النظام الأساسي الواحد (التلقائية) هي أنّ المضيف والتنفيذ والمنصّات المستهدفة هي نفسها. على سبيل المثال، يمكنك إنشاء ملف Linux تنفيذي على Ubuntu قيد التشغيل على وحدة معالجة مركزية من Intel من فئة x64.

  • نُسخ التجميع المتبادل: إنّ منصّات المضيف والتنفيذ متماثلة، إلا أنّ المنصّة المستهدفة مختلفة. على سبيل المثال، إنشاء تطبيق iOS على نظام التشغيل macOS يعمل على MacBook Pro.

  • الإصدارات ذات المنصات المتعددة: تختلف كل من المنصات والتنفيذ والمنصّات المستهدفة.

تحديد القيود والمنصّات

يتم تحديد مساحة الاختيارات المحتملة للمنصات باستخدام قاعدتي constraint_setting وconstraint_value ضمن ملفات BUILD. تُنشئ constraint_setting بُعدًا جديدًا، بينما ينشئ constraint_value قيمة جديدة لبُعد معيّن. ويحدّد هذان المنتجان معًا أحد التعدادات وقيمه المحتملة. على سبيل المثال، في المقتطف التالي لملف BUILD، يتم فرض قيود على إصدار glibc في النظام مع قيمتَين محتملتَين.

constraint_setting(name = "glibc_version")

constraint_value(
    name = "glibc_2_25",
    constraint_setting = ":glibc_version",
)

constraint_value(
    name = "glibc_2_26",
    constraint_setting = ":glibc_version",
)

يمكن تحديد القيود وقيمها في مختلف الحِزم في مساحة العمل. وتتم الإشارة إليها من خلال تصنيف وتخضع لعناصر التحكم المعتادة في الظهور. يمكنك توسيع نطاق قيود حالية، إذا كان مستوى الرؤية يسمح بذلك، من خلال تحديد قيمةك الخاصة له.

تقدِّم القاعدة platform منصة جديدة تتضمن خيارات معيّنة لقيم القيود. في ما يلي منصّة تُسمّى linux_x86، وتوضّح أنّها تصف أيّ بيئة تعمل بنظام تشغيل Linux على بنية x86_64 ذات إصدار عالمي من 2.25. (انظر أدناه لمعرفة المزيد من المعلومات حول القيود المفروضة على Bazel').

platform(
    name = "linux_x86",
    constraint_values = [
        "@platforms//os:linux",
        "@platforms//cpu:x86_64",
        ":glibc_2_25",
    ],
)

قيود ومنصات مفيدة بشكل عام

وللحفاظ على اتساق المنظومة المتكاملة، لدى فريق Bazel مستودعًا يتضمّن تعريفات محدودة لبنيات وحدة المعالجة المركزية (CPU) وأنظمة التشغيل الأكثر شيوعًا. وكل هذه الصفحات متوفرة على https://github.com/bazelbuild/platforms.

يتوفّر حلّ Bazel مع تعريف المنصة الخاص التالي: @local_config_platform//:host. هذه هي قيمة النظام الأساسي المضيف التي تم اكتشافها تلقائيًا - تمثّل النظام الأساسي الذي تم الكشف عنه تلقائيًا للنظام الذي تعمل به Bazel.

تحديد نظام أساسي لإصدار

يمكنك تحديد الأنظمة الأساسية والمستهدفة للمبنى باستخدام علامات سطر الأوامر التالية:

  • --host_platform - القيمة التلقائية هي @bazel_tools//platforms:host_platform
  • --platforms - القيمة التلقائية هي @bazel_tools//platforms:target_platform

تخطي الأهداف غير المتوافقة

عند إنشاء نظام أساسي محدد، من الأفضل غالبًا تخطي الأهداف التي لن تعمل أبدًا على ذلك النظام الأساسي. على سبيل المثال، من المرجّح أن يؤدي برنامج تشغيل جهاز Windows إلى إنشاء العديد من أخطاء برنامج التجميع عند الإنشاء على جهاز يعمل بنظام التشغيل Linux يتضمّن //.... استخدِم السمة target_compatible_with لإعلام Bazel بالقيود التي تفرضها المنصّة.

إنّ أبسط استخدام لهذه السمة يقتصر على استهداف منصّة واحدة. ولن يتم إنشاء الهدف لأي نظام أساسي لا يستوفي جميع القيود. يحدّد المثال التالي win_driver_lib.cc إلى 64 بت على نظام التشغيل Windows.

cc_library(
    name = "win_driver_lib",
    srcs = ["win_driver_lib.cc"],
    target_compatible_with = [
        "@platforms//cpu:x86_64",
        "@platforms//os:windows",
    ],
)

إنّ إصدار :win_driver_lib متوافق فقط مع الإصدار 64 بت من نظام التشغيل Windows، وغير متوافق مع أي نظام آخر. إنّ عدم التوافق غير ضروري. أي أهداف تعتمد بشكل عرضي على هدف غير متوافق تُعتبر نفسها غير متوافقة.

متى يتم تخطي الاستهدافات؟

يتم تخطّي الاستهدافات عندما تُعتبر غير متوافقة ويتم تضمينها في الإصدار كجزء من توسيع نمط الاستهداف. على سبيل المثال، يتجاوز الاستدعاءان التاليان أي استهدافات غير متوافقة تم العثور عليها في توسيع نمط الاستهداف.

$ bazel build --platforms=//:myplatform //...
$ bazel build --platforms=//:myplatform //:all

يتم تخطّي الاختبارات غير المتوافقة في test_suite بالطريقة نفسها إذا تم تحديد test_suite في سطر الأوامر باستخدام --expand_test_suites. بعبارة أخرى، تعمل test_suite الأهداف على سطر الأوامر كما يلي :all و .... ويؤدي استخدام السياسة --noexpand_test_suites إلى منع التوسّع ويتسبب في عدم توافق أهداف test_suite مع الاختبارات غير المتوافقة.

ويؤدي تحديد هدف غير متوافق صراحةً في سطر الأوامر إلى ظهور رسالة خطأ وتعذُّر الإصدار.

$ bazel build --platforms=//:myplatform //:target_incompatible_with_myplatform
...
ERROR: Target //:target_incompatible_with_myplatform is incompatible and cannot be built, but was explicitly requested.
...
FAILED: Build did NOT complete successfully

قيود أكثر تعبيرًا

لتحقيق المزيد من المرونة في التعبير عن القيود، استخدِم @platforms//:incompatible constraint_value التي لا تتوافق مع أي منصّة.

استخدِم select() مع @platforms//:incompatible للتعبير عن قيود أكثر تعقيدًا. على سبيل المثال، يمكنك استخدامه لتنفيذ المعيار OR المنطقي. في ما يلي علامة على مكتبة متوافقة مع macOS وLinux، وليس الأنظمة الأساسية الأخرى.

cc_library(
    name = "unixish_lib",
    srcs = ["unixish_lib.cc"],
    target_compatible_with = select({
        "@platforms//os:osx": [],
        "@platforms//os:linux": [],
        "//conditions:default": ["@platforms//:incompatible"],
    }),
)

يمكن تفسير ما يلي على النحو التالي:

  1. عند استهداف نظام التشغيل macOS، لا يمتلك الهدف قيودًا.
  2. عند استهداف نظام التشغيل Linux، لا يتم فرض قيود على الهدف.
  3. بخلاف ذلك، يحتوي الاستهداف على القيد @platforms//:incompatible. وبما أنّ @platforms//:incompatible ليس جزءًا من أي نظام أساسي، يُعدّ الهدف غير متوافق.

لجعل القيود أكثر وضوحًا، استخدِم skylib's selects.with_or().

يمكنك التعبير عن التوافق العكسي بطريقة مشابهة. يصف المثال التالي مكتبة متوافقة مع كل العناصر باستثناء مع تفعيل ARM.

cc_library(
    name = "non_arm_lib",
    srcs = ["non_arm_lib.cc"],
    target_compatible_with = select({
        "@platforms//cpu:arm": ["@platforms//:incompatible"],
        "//conditions:default": [],
    ],
)

رصد استهدافات غير متوافقة باستخدام bazel cquery

يمكنك استخدام IncompatiblePlatformProvider في تنسيق إخراج Starlark في bazel cquery' لتمييز الاستهدافات غير المتوافقة عن الأهداف المتوافقة.

ويمكن استخدام هذا لفلترة الأهداف غير المتوافقة. لن يطبع المثال التالي سوى التصنيفات للأهداف المتوافقة. لا تتم طباعة الاستهدافات غير المتوافقة.

$ cat example.cquery

def format(target):
  if "IncompatiblePlatformProvider" not in providers(target):
    return target.label
  return ""


$ bazel cquery //... --output=starlark --starlark:file=example.cquery

المشاكل المعروفة

الأهداف غير المتوافقة تجاهل قيود مستوى العرض.