تتناول هذه الصفحة كيفية إنشاء برنامج باستخدام Bazel وبناء بنية أوامر وبنية أنماط مستهدفة.
البدء السريع
لتشغيل Bazel، انتقِل إلى دليل مساحة العمل الأساسي أو إلى أي من الأدلة الفرعية واكتب bazel
. يمكنك الاطّلاع على إصدار إذا كنت بحاجة إلى إنشاء مساحة عمل جديدة.
bazel help
[Bazel release bazel version]
Usage: bazel command options ...
الطلبات المتاحة
analyze-profile
: لتحليل بيانات الملفات الشخصيةaquery
: تنفّذ طلب بحث في الرسم البياني للإجراء ما بعد التحليل.build
: ينشئ الأهداف المحدّدة.canonicalize-flags
: إزالة أعلام Bazel.clean
: يؤدي هذا الإجراء إلى إزالة ملفات الإخراج وإيقاف الخادم اختياريًا.cquery
: تنفيذ طلب رسم بياني لـ ما بعد التحليل.dump
: يحذف الحالة الداخلية لعملية خادم Bazel.help
: تساعد الصور المطبوعة على تنفيذ الأوامر أو الفهرس.info
: يعرض معلومات عن وقت تشغيل الخادم.fetch
: لجلب جميع التبعيات الخارجية لأحد الأهداف.mobile-install
: يثبّت التطبيقات على الأجهزة الجوّالة.query
: تنفّذ طلب رسم بياني للاعتمادية.run
: يشغِّل الهدف المحدّد.shutdown
: لإيقاف خادم Bazeltest
: لإنشاء أهداف الاختبار المحدّدة وتشغيلها.version
: يعرض معلومات إصدار Bazel.
الحصول على المساعدة
bazel help command
: مساعدة بشأن الصور المطبوعة وخيارات حولcommand
bazel help
startup_options
: خيارات JVM التي تستضيف Bazelbazel help
target-syntax
: توضّح البنية لتحديد الأهداف.bazel help info-keys
: يتم عرض قائمة بالمفاتيح التي يستخدمها أمر المعلومات.
ينفّذ أداة bazel
العديد من الوظائف، وهي تُسمى الأوامر. bazel build
وbazel test
الأكثر استخدامًا. يمكنك تصفّح رسائل المساعدة
على الإنترنت باستخدام bazel help
.
إنشاء هدف واحد
قبل أن تتمكّن من بدء عملية إنشاء، ستحتاج إلى مساحة عمل. مساحة العمل هي شجرة دليل تتضمن كل الملفات المصدر اللازمة لإنشاء التطبيق. تسمح لك أداة Bazel بإنشاء إصدار من مجلد مخصّص للقراءة فقط.
لإنشاء برنامج باستخدام Bazel، اكتب bazel build
متبوعًا
بالهدف الذي تريد إنشاءه.
bazel build //foo
بعد إصدار الأمر لإنشاء //foo
، ستظهر لك نتائج مشابهة لما يلي:
INFO: Analyzed target //foo:foo (14 packages loaded, 48 targets configured).
INFO: Found 1 target...
Target //foo:foo up-to-date:
bazel-bin/foo/foo
INFO: Elapsed time: 9.905s, Critical Path: 3.25s
INFO: Build completed successfully, 6 total actions
أولاً، يعمل Bazel على تحميل كل الحِزم في الرسم البياني للاعتمادية. ويتضمّن ذلك الاعتماديات المُعلَن عنها والملفات المُدرَجة مباشرةً في ملف BUILD
BUILD
الخاص بالهدف والاعتماديات الانتقالية والملفات المُدرَجة في ملفات BUILD
من تبعياتك المستهدَفة. بعد تحديد جميع التبعيات، تعمل أداة Bazel على تحليل عناصر الأداء بشكل صحيح، كما تُنشئ إجراءات الإصدار. وأخيرًا، ينفّذ "بازيل" العارضين
وأدوات التجميع الأخرى.
أثناء مرحلة التنفيذ، يطبع Bazel رسائل مستوى التقدّم. تشمل رسائل مستوى التقدّم خطوة الإصدار الحالية (مثل برنامج التجميع أو أداة الربط) عند بدئها، وعدد الأرقام التي اكتملت على إجمالي عدد إجراءات الإصدار. ومع بداية الإصدار، غالبًا ما يرتفع عدد الإجراءات عندما يكتشف محرّك البحث Bazel الرسم البياني للحركة بالكامل، ولكن يستقر الرقم في غضون بضع ثوانٍ.
في نهاية الإصدار، يطبع Bazel الأهداف المطلوبة، سواء تم إنشاؤها بنجاح أم لا، وفي حال العثور عليها، يمكن العثور على ملفات الإخراج. يمكن للنصوص البرمجية التي تشغّل إصدارات تحليل هذا الإخراج بشكل موثوق. ويمكنك الاطّلاع على
--show_result
لمعرفة المزيد من التفاصيل.
إذا كتبت الأمر نفسه مرة أخرى، سينتهي الإصدار بشكل أسرع.
bazel build //foo
INFO: Analyzed target //foo:foo (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
Target //foo:foo up-to-date:
bazel-bin/foo/foo
INFO: Elapsed time: 0.144s, Critical Path: 0.00s
INFO: Build completed successfully, 1 total action
هذا إصدار فارغ. نظرًا لعدم حدوث أي تغيير، لا حاجة إلى إعادة تحميل الحِزم ولا خطوات تنفيذ للتنفيذ. إذا حدث تغيير في 'foo' أو المهام التابعة له، فسيعيد Bazel تنفيذ بعض إجراءات الإصدار أو يكمل إصدارًا متزايدًا.
إنشاء عدّة استهدافات
تسمح الميزتين بعدد من الطرق لتحديد الأهداف التي سيتم إنشاؤها. ويُطلق على هذه الإعدادات إجمالاً اسم
الأنماط المستهدفة. تُستخدم هذه البنية في طلبات مثل
build
أو test
أو query
.
بينما تُستخدَم التصنيفات لتحديد أهداف فردية، مثل بيان التبعيات في ملفات BUILD
، تحدّد أنماط Bazel's الاستهدافات المتعددة. أنماط الأهداف هي تعميم بنية التصنيف لمجموعات الأهداف، باستخدام أحرف البدل. في أبسط الحالات، يمثل أي تصنيف صالح نمط استهداف صالحًا يُحدد مجموعة من هدف واحد بالضبط.
تم حل جميع الأنماط المستهدفة التي تبدأ بـ //
بالنسبة إلى
مساحة العمل الحالية.
//foo/bar:wiz |
الهدف الوحيد هو //foo/bar:wiz . |
//foo/bar |
هذا الرمز مكافئ للرمز //foo/bar:bar . |
//foo/bar:all |
جميع أهداف القاعدة في الحزمة foo/bar . |
//foo/... |
كل استهدافات القواعد في كل الحِزم أسفل الدليل foo |
//foo/...:all |
كل استهدافات القواعد في كل الحِزم أسفل الدليل foo |
//foo/...:* |
جميع الاستهدافات (القواعد والملفات) في كل الحِزم أسفل الدليل foo . |
//foo/...:all-targets |
جميع الاستهدافات (القواعد والملفات) في كل الحِزم أسفل الدليل foo . |
//... |
جميع الاستهدافات في الحِزم في مساحة العمل. ولا يشمل ذلك الأهداف من المستودعات الخارجية. |
//:all |
جميع الاستهدافات في حزمة المستوى الأعلى، إذا كان هناك ملف "BUILD" في جذر مساحة العمل. |
يتم التعامل مع الأنماط المستهدفة التي لا تبدأ بـ //
بالنسبة إلى
دليل العمل الحالي. تفترض الأمثلة التالية دليلاً صالحًا للعمل foo
:
:foo |
هذا الرمز مكافئ للرمز //foo:foo . |
bar:wiz |
هذا الرمز مكافئ للرمز //foo/bar:wiz . |
bar/wiz |
يعادل:
|
bar:all |
هذا الرمز مكافئ للرمز //foo/bar:all . |
:all |
هذا الرمز مكافئ للرمز //foo:all . |
...:all |
هذا الرمز مكافئ للرمز //foo/...:all . |
... |
هذا الرمز مكافئ للرمز //foo/...:all . |
bar/...:all |
هذا الرمز مكافئ للرمز //foo/bar/...:all . |
بشكل تلقائي، تتم متابعة روابط الدليل للأنماط المستهدفة المتكررة، باستثناء تلك التي تشير إلى أسفل قاعدة الإخراج، مثل الروابط المناسبة التي يتم إنشاؤها في الدليل الجذري لمساحة العمل.
بالإضافة إلى ذلك، لا يتّبع Bazel الرموز الرمزية عند تقييم أنماط الأهداف المتكررة في أي دليل يحتوي على ملف اسمه على النحو التالي:
DONT_FOLLOW_SYMLINKS_WHEN_TRAVERSING_THIS_DIRECTORY_VIA_A_RECURSIVE_TARGET_PATTERN
foo/...
هو حرف بدل فوق الحِزم، ويشير إلى جميع الحِزم
بشكل متكرر تحت الدليل foo
(لكل جذور مسار الحزمة). :all
هي حرف بدل عن الأهداف تتطابق مع جميع القواعد ضمن حزمة. قد يتمّ دمج الاثنين معًا، كما في foo/...:all
، وعند استخدام حرفَي البدل، يمكن اختصار هذا الاختصار إلى foo/...
.
بالإضافة إلى ذلك، فإن :*
(أو :all-targets
) حرف بدل يطابق كل هدف في الحزم المطابقة، بما في ذلك الملفات التي لم يتم إنشاؤها عادةً بواسطة أي قاعدة، مثل ملفات _deploy.jar
المرتبطة بقواعد java_binary
.
يعني ذلك أن :*
يشير إلى مجموعة من :all
. وفي حين يُحتمل أن تكون هذه
البنية مُربكة، فإنّه يسمح باستخدام حرف البدل :all
المعتاد،
للإصدارات النموذجية، حيث لا يكون الهدف من بناء المبنى مثل _deploy.jar
.
بالإضافة إلى ذلك، تسمح Bazel باستخدام الشرطة المائلة بدلاً من النقطتين المطلوبتين من خلال بنية التصنيف، وغالبًا ما يكون ذلك مناسبًا عند استخدام توسيع اسم ملف Bash.
على سبيل المثال، يعادل foo/bar/wiz
السمة //foo/bar:wiz
(إذا كانت هناك
حزمة foo/bar
) أو //foo:bar/wiz
(إذا كان هناك حزمة foo
).
تقبل العديد من أوامر Bazel قائمة بالأنماط المستهدفة كوسيطات، وجميعها تتوافق مع عامل تشغيل بادئة البادئة -
. ويمكن استخدام هذا لطرح مجموعة من الأهداف من المجموعة المحدّدة في الوسيطات السابقة. ملاحظة: هذا يعني
أنّ الطلب مهم. على سبيل المثال:
bazel build foo/... bar/...
يعني "إنشاء جميع الاستهدافات أسفل foo
وجميع الأهداف ضمن bar
" بينما
bazel build -- foo/... -foo/bar/...
وتعني "إنشاء جميع الاستهدافات أسفل foo
باستثناء تلك التي تندرج ضمن foo/bar
" (يتم استخدام الوسيطة --
لمنع الوسيطات اللاحقة التي تبدأ بـ -
من تفسيرها كخيارات إضافية.)
يجب الإشارة إلى أنّ طرح الاستهدافات بهذه الطريقة لا يضمن ضمان عدم إنشائها، لأنها قد تكون اعتمادًا على الأهداف التي لم يتم طرحها. على سبيل المثال، إذا كان هناك هدف //foo:all-apis
يعتمد على //foo/bar:api
، سيُبنى الأخير على أنه جزء من المبنى السابق.
لا يتم تضمين الاستهدافات مع tags = ["manual"]
في أنماط أهداف حرف البدل
(...
و:*
و:all
وما إلى ذلك) عند تحديدها في أوامر مثل
bazel build
وbazel test
، ويجب تحديد هذه
الأهداف التجريبية ذات أنماط الاستهداف الصريحة في سطر الأوامر إذا كنت تريد من Bazel
إنشاءها أو اختبارها. في المقابل، لا يُجري bazel query
أي هذه الفلترة تلقائيًا (التي قد تُلغي الغرض من bazel query
).
جارٍ استرجاع المهام الخارجية
سيعمل Bazel تلقائيًا على تنزيل العناصر التابعة الخارجية وربطها ببعضها أثناء عملية الإصدار. ومع ذلك، قد يكون هذا غير مرغوب فيه، إما لأنك تريد معرفة عند إضافة تبعيات خارجية جديدة أو لأنك تريد الحصول على تبعيات مثل ";"pre fetch"مقولة (على سبيل المثال، قبل رحلة طيران، ستكون غير متصل فيها). إذا كنت تريد منع إضافة المهام التابعة الجديدة أثناء الإصدارات، يمكنك تحديد العلامة --fetch=false
. يُرجى العِلم أنّ هذه العلامة لا تنطبق إلا
على قواعد المستودع التي لا تشير إلى دليل في
نظام الملفات المحلي. على سبيل المثال، التغييرات التي يتم إجراؤها على local_repository
،
new_local_repository
وقواعد Android SDK ومستودع NDK
ستدخل دائمًا حيز التنفيذ بغض النظر عن القيمة --fetch
.
إذا لم تسمح بجلب الإصدارات أثناء عثور Bazel على ارتباطات خارجية جديدة، سيتعذّر إتمام عملية الإنشاء.
يمكنك جلب الارتباطات يدويًا من خلال تشغيل bazel fetch
. في حال
عدم السماح أثناء الجلب أثناء الإصدار، يجب تشغيل bazel fetch
:
- قبل الإنشاء للمرة الأولى.
- بعد إضافة تبعية خارجية جديدة.
بعد تشغيله، لن تحتاج إلى تشغيله مرة أخرى حتى يتغير الملف WORKSPACE.
يحتوي fetch
على قائمة بالأهداف المطلوب الحصول عليها من التبعيات. على سبيل المثال، يؤدي ذلك إلى جلب العناصر التابعة اللازمة لإنشاء //foo:bar
و//bar:baz
:
bazel fetch //foo:bar //bar:baz
لاسترجاع جميع المهام التابعة الخارجية لمساحة عمل، نفِّذ ما يلي:
bazel fetch //...
ولست بحاجة إلى تشغيل استرجاع البازلاء على الإطلاق إذا كانت لديك كل الأدوات التي تستخدمها (من جرّارات المكتبة إلى JDK نفسها) ضمن جذر مساحة العمل.
في المقابل، إذا كنت تستخدم أي شيء خارج دليل مساحة العمل، سيعمل Bazel تلقائيًا على bazel fetch
قبل تشغيلهbazel build
.
ذاكرة التخزين المؤقت للمستودع
يحاول Bazel تجنّب استرجاع الملف نفسه عدّة مرات، حتى إذا كانت هناك حاجة إلى ملف واحد في مساحات عمل مختلفة، أو إذا تغيّر تعريف مستودع خارجي ولكنّه لا يزال بحاجة إلى الملف نفسه لتنزيله. لإجراء ذلك، يعمل Bazel على تخزين جميع الملفات التي تم تنزيلها في ذاكرة التخزين المؤقت للمستودع، والتي تكون متاحة تلقائيًا في ~/.cache/bazel/_bazel_$USER/cache/repos/v1/
. يمكن تغيير الموقع الجغرافي من خلال الخيار --repository_cache
. تتم مشاركة ذاكرة التخزين المؤقت بين جميع مساحات العمل وإصدارات البازيل المثبّتة.
يتم أخذ إدخال من ذاكرة التخزين المؤقت إذا أدرك "بازل" أن لديه نسخة من الملف الصحيح، أي إذا كان طلب التنزيل يحتوي على مجموع SHA256 من الملف المحدّد وأن ملفًا يحمل التجزئة مع ذاكرة التخزين المؤقت. وبالتالي، فإن تحديد تجزئة لكل ملف خارجي
ليس من الأفكار الجيدة من منظور الأمان فحسب، بل سيساعدك أيضًا على تجنب
عمليات التنزيل غير الضرورية.
بعد كل نتيجة لذاكرة التخزين المؤقت، يتم تحديث وقت تعديل الملف في ذاكرة التخزين المؤقت. وبهذه الطريقة، يمكن تحديد الاستخدام الأخير لملف في دليل ذاكرة التخزين المؤقت بسهولة، على سبيل المثال، لتنظيف ذاكرة التخزين المؤقت يدويًا. لا يتم تنظيف ذاكرة التخزين المؤقت تلقائيًا لأنها قد تحتوي على نسخة من ملف لم يعد متاحًا للتنزيل.
أدلة ملفات التوزيع
دليل التوزيع هو آلية أخرى البازل لتجنُّب عمليات التنزيل غير الضرورية. يبحث Bazel عن أدلة التوزيع قبل ذاكرة التخزين المؤقت للمستودع. يتمثل الاختلاف الأساسي في أن دليل التوزيع يتطلب التحضير اليدوي.
باستخدام الخيار
--distdir=/path/to-directory
، يمكنك تحديد أدلة إضافية للقراءة فقط للبحث عن الملفات
بدلاً من استرجاعها. يتم أخذ الملف من هذا الدليل إذا كان اسم الملف مساويًا للاسم الأساسي لعنوان URL، بالإضافة إلى أن تجزئة الملف مساوية لما تم تحديده في طلب التنزيل. لا يعمل هذا الإجراء إلا إذا تم تحديد تجزئة الملف في تعريف WORKSPACE.
على الرغم من أن الحالة في اسم الملف ليست ضرورية للتحقق من صحتها، فإنها تحدّ من عدد ملفات المرشح في ملف واحد لكل دليل محدّد. وبهذه الطريقة، يبقى تحديد أدلة ملفات التوزيع فعّالاً، حتى إذا ازداد عدد الملفات في هذا الدليل.
مبنى Bazel يركّز في بيئة مكسوة بالهواء
للحفاظ على حجم البرنامج الثنائي Bazel'2، يتم جلب تبعيّة Bazel' الضمنية عبر الشبكة أثناء تشغيلها للمرة الأولى. تحتوي هذه الارتباطات الضمنية على سلاسل أدوات وقواعد قد لا تكون ضرورية للجميع. على سبيل المثال، لا يتم تجميع أدوات Android واسترجاعها إلا عند إنشاء مشاريع Android.
ومع ذلك، قد تتسبب هذه الارتباطات الضمنية في حدوث مشاكل عند تشغيل Bazel في بيئة بها فجوات هوائية، حتى إذا كنت قد مورّدت كل اعتمادياتك على Workspace. لحل ذلك، يمكنك إعداد دليل توزيع يحتوي على هذه الارتباطات على جهاز يمكنه الوصول إلى الشبكة، ثم نقلها إلى بيئة غير منظّمة باستخدام نهج بلا اتصال بالإنترنت.
لإعداد دليل التوزيع، استخدِم
العلامة --distdir
. ستحتاج إلى تنفيذ هذا الإجراء مرة واحدة لكل إصدار ثنائي جديد من Bazel، حيث يمكن أن تختلف الارتباطات الضمنية لكل إصدار.
لإنشاء الاعتماديات هذه خارج البيئة التي ثمة فجوات هوائية، يجب أولاً الاطّلاع على شجرة مصدر Bazel في الإصدار الصحيح:
git clone https://github.com/bazelbuild/bazel "$BAZEL_DIR"
cd "$BAZEL_DIR"
git checkout "$BAZEL_VERSION"
بعد ذلك، صمِّم لعبة tarball تحتوي على تبعيات وقت التشغيل الضمنية لإصدار Bazel المحدّد:
bazel build @additional_distfiles//:archives.tar
صدّر كرة التارا هذه إلى دليل يمكن نسخه إلى بيئتك الهوائية. يُرجى ملاحظة علامة --strip-components
، لأن --distdir
يمكن أن يكون صعبًا إلى حد كبير مع مستوى دمج الدليل:
tar xvf bazel-bin/external/additional_distfiles/archives.tar \
-C "$NEW_DIRECTORY" --strip-components=3
وأخيرًا، عند استخدام Bazel في بيئتك المكثّفة، مرِّر علامة --distdir
للإشارة إلى الدليل. لتسهيل الأمر، يمكنك إضافته كإدخال .bazelrc
:
build --distdir=path/to/directory
إنشاء الإعدادات والتجميع المتبادل
يمكن تقسيم جميع المدخلات التي تحدد السلوك ونتيجة تصميم معيّن إلى فئتين مختلفتين. النوع الأول هو المعلومات الجوهرية المخزّنة في ملفات BUILD
لمشروعك: قاعدة الإصدار، وسماته، والمجموعة الكاملة للاعتماديات المباشرة أو غير المباشرة.
النوع الثاني هو البيانات الخارجية أو البيئية، ويتم توفيرها من قِبل المستخدم أو من خلال أداة الإصدار: اختيار البنية المستهدفة وخيارات التجميع والربط، وخيارات ضبط سلسلة الأدوات الأخرى. إننا نشير إلى مجموعة كاملة من البيانات البيئية كعمليات ضبط.
وفي أي إصدار، قد يكون هناك أكثر من إعداد واحد. يمكنك استخدام تنسيق التجميع المتبادل، حيث تنشئ ملف //foo:bin
تنفيذيًا لبنية 64 بت، إلا أنّ محطة العمل هي جهاز بحجم 32 بت. من الواضح أنّ هذا الإصدار سيتطلب بناء المبنى //foo:bin
باستخدام سلسلة أدوات يمكنها إنشاء 64 بت قابلة للتنفيذ، ولكن يجب أن ينشئ نظام الإصدار أيضًا أدوات متنوعة يتم استخدامها أثناء الإصدار، مثل الأدوات التي يتم إنشاؤها من المصدر، ثم يتم استخدامها لاحقًا في قاعدة أساسية، كما يجب إنشاء هذه الأدوات للتشغيل على محطة العمل. وبالتالي
يمكننا تحديد مجموعتَين من الإعدادات: ضبط المضيف الذي يُستخدم
لإنشاء أدوات يتم تشغيلها أثناء عملية الإنشاء والضبط المستهدف
(أو ضبط الطلب)، ولكننا نشير غالبًا إلى "target;" على الرغم من أنّ هذه الكلمة لها العديد من المعاني)، والتي يتم استخدامها لإنشاء
الملف الثنائي الذي طلبته في النهاية.
يتوفّر عادةً العديد من المكتبات التي تمثّل متطلّبات أساسية لكلٍّ من هدف التصميم المطلوب (//foo:bin
) وواحدة أو أكثر من أدوات المضيف، مثل بعض المكتبات الأساسية. ويجب إنشاء هذه المكتبات مرتين، مرة لضبط المضيف ومرة للضبط المستهدف. وتهتم "بازل" بضمان إنشاء كلتا النسختَين مختلفة، كما يتم الفصل بين الملفات مشتقة منها لتجنُّب التداخل، وعادةً ما يمكن إنشاء مثل هذه الأهداف في الوقت نفسه، لأنّها مستقلة عن بعضها البعض. إذا ظهرت لك رسائل تقدم تشير إلى أنه يتم إنشاء هدف معيّن مرتين، هذا على الأرجح التفسير.
يستخدم Bazel إحدى الطريقتين التاليتين لضبط إعدادات المضيف، استنادًا إلى
الخيار --distinct_host_configuration
. هذا الخيار المنطقي دقيق إلى حد ما، وقد يحسّن الإعداد (أو أسوأ) من سرعة الإصدارات لديك.
--distinct_host_configuration=false
عندما يكون هذا الخيار خاطئًا، ستكون إعدادات المضيف والمضيف متطابقة: سيتم إنشاء جميع الأدوات المطلوبة أثناء الإصدار بالطريقة نفسها تمامًا التي يتم بها إنشاء برامج مستهدفة. يعني هذا الإعداد أنه لن تكون هناك حاجة إلى إنشاء مكتبات مرتين أثناء عملية تصميم واحدة.
ومع ذلك، يعني هذا أنّ أي تغيير في ضبط طلبك يؤثر أيضًا في إعدادات المضيف، ما يؤدي إلى إعادة إنشاء كل الأدوات، ثمّ أي تغيير يعتمد على مخرجات الأداة. ولهذا السبب، مثلاً، قد يؤدي تغيير خيار رابط بين الإصدارات إلى إعادة ربط كل الأدوات، ثم إعادة تنفيذ جميع الإجراءات التي تستخدمها، وما إلى ذلك، ما يؤدي إلى إعادة بناء كبيرة جدًا.
--distinct_host_configuration=true
(تلقائي)
إذا كان هذا الخيار صحيحًا، سيتم استخدام إعداد مضيف مختلف تمامًا، بدلاً من استخدام الإعداد نفسه للمضيف والطلب. يتم استنتاج إعداد المضيف من الضبط المستهدَف على النحو التالي:
- استخدِم الإصدار نفسه من أداة Crosstool (
--crosstool_top
) كما هو محدّد في إعداد الطلب، ما لم يتم تحديد--host_crosstool_top
. - استخدِم القيمة
--host_cpu
في--cpu
(القيمة التلقائية:k8
). - استخدِم القيم نفسها للخيارات كما هو محدّد في إعداد
الطلب:
--compiler
و--use_ijars
وإذا تم استخدام--host_crosstool_top
، سيتم استخدام قيمة--host_cpu
للبحث عنdefault_toolchain
في Crosstool (مع تجاهل--compiler
) لضبط المضيف. - استخدام القيمة
--host_javabase
في--javabase
- استخدام القيمة
--host_java_toolchain
في--java_toolchain
- يُرجى استخدام الإصدارات المحسَّنة لرمز C++ (
-c opt
). - عدم إنشاء أي معلومات تصحيح أخطاء (
--copt=-g0
) - إزالة معلومات تصحيح الأخطاء من الملفات التنفيذية والمكتبات المشتركة
(
--strip=always
) - ضَع جميع الملفات مشتقة في مكان خاص، بعيدًا عن الملف الذي تستخدمه أي عملية إعداد طلب محتملة.
- منع طباعة الطوابع الثنائية باستخدام بيانات الإصدار (الاطّلاع على خيارات
--embed_*
) - تظل جميع القيم الأخرى كما هي.
هناك عدّة أسباب قد تدفعك إلى اختيار إعدادات ضبط مضيف مختلفة عن إعدادات الطلب. بعض هذه المصطلحات مبكّر جدًا ولا يمكن الإشارة إليه هنا، ولكن يجب الإشارة إلى اثنَيهما.
أولاً، باستخدام البرامج الثنائية المُجمَّعة والمُحسَّنة، يمكنك تقليل الوقت الذي تقضيه في ربط الأدوات وتنفيذها، ومساحة القرص التي تشغلها الأدوات، ووقت مؤتمر I/O في الإصدارات الموزَّعة.
ثانيًا، من خلال إلغاء ربط المضيف وطلب عمليات الضبط في جميع الإصدارات، ستتجنّب عمليات إعادة الإنشاء مكلفة جدًا والتي قد ينتج عنها إجراء تغييرات طفيفة على إعدادات الطلب (مثل تغيير خيارات أداة الربط)، كما هو موضّح سابقًا.
مع ذلك، بالنسبة إلى الإصدارات المحدّدة، قد يكون هذا الخيار بمثابة عقبة. وعلى وجه الخصوص، قد لا تستفيد من هذا الإصدار الإصدارات التي تكون فيها تغييرات الضبط غير متكرّرة (خاصةً في حال استخدام إصدارات معيّنة من لغة Java)، وكذلك الإصدارات التي يكون فيها حجم الرمز الذي يجب إنشاؤه في كل من إعدادات المضيف والمضيف المستهدف كبيرًا.
عمليات إعادة الإنشاء التدريجي الصحيحة
تتمثّل إحدى الأهداف الأساسية لمشروع Bazel في ضمان إعادة البناء التدريجي بشكل صحيح. إنّ أدوات الإصدار السابقة، وخاصةً تلك التي تستند إلى "العلامة التجارية"، تضع افتراضات غير مسموعة في تنفيذ الإصدارات التدريجية.
أولاً، تزيد الطوابع الزمنية للملفات بشكل أحادي. في حين أن هذه هي الحالة النموذجية، من السهل جدًا أن تتناقض مع هذا الافتراض، حيث تؤدي المزامنة مع نسخة سابقة من الملف إلى انخفاض وقت تعديل الملف، ولن تتم إعادة إنشاء الأنظمة المستندة إلى العلامة التجارية.
بشكل عام، بينما يرصد "إجراء تغييرات" على الملفات، لا يرصد التغييرات في الأوامر. إذا غيّرت الخيارات التي يتم تمريرها إلى المُجمِّع في خطوة إصدار معينة، لن يُعيد "أداة التشغيل" تشغيل برنامج التجميع، وسيكون من الضروري تجاهل النتائج غير الصالحة للإصدار السابق باستخدام make clean
.
فضلاً عن ذلك، لا تكون أداة "ماركة" قوية بجانب الإنهاء غير الناجح لإحدى العمليات الفرعية التابعة له بعد أن تبدأ هذه العملية الفرعية في الكتابة إلى ملف الناتج. على الرغم من أنّ التنفيذ الحالي لـ "ماركة Play" سيتعذّر إتمامه، فإن الاستدعاء اللاحق لـ "ماركة Google" يفترض بشكلٍ صريح أن ملف الإخراج المقتطع صالح (لأنه أحدث من مدخلاته)، ولن تتم إعادة تصميمه. وبالمثل، إذا تم قتل عملية التصميم، يمكن أن يحدث وضع مشابه.
يتجنّب "بازل" هذه الافتراضات وغيرها. يحتفظ Bazel بقاعدة بيانات تتضمّن جميع الأعمال التي تم إنجازها من قبل، ولن يحذف سوى خطوة إصدار إذا اكتشف أنّ مجموعة ملفات الإدخال (والطوابع الزمنية) لها تظهر في خطوة الإنشاء، ويتطابق أمر التجميع لتلك الخطوة في قاعدة البيانات، وتطابق مجموعة ملفات المخرجات (والطوابع الزمنية) لها في قاعدة البيانات تمامًا مع الطوابع الزمنية للملفات على القرص. سيؤدي أي تغيير في ملفات الإدخال أو ملفات المخرجات، أو إلى الأمر نفسه، إلى إعادة تنفيذ خطوة الإصدار.
الفائدة التي يستفيد منها المستخدمون من الإصدارات التدريجية الصحيحة هي هدر الوقت مع تقليل
الارتباك. (أيضًا، قلت المدة المستغرقة في انتظار عمليات إعادة الإنشاء الناتجة عن استخدام make
clean
، سواء كان ذلك ضروريًا أم استباقيًا).
إنشاء الإصدارات بشكل متّسق ومتزايد
نُعرِّف رسميًا حالة الإصدار على أنها متناسقة في حال توفُّر جميع ملفات المخرجات المتوقّعة وصحة محتواها، كما هو موضّح في الخطوات أو القواعد المطلوبة لإنشائها. عند تعديل ملف مصدر، يُقال إنّ حالة الإصدار لا تتسّق، وتظلّ غير متسقة إلى أن تشغّل أداة الإصدار إلى الخطوة التالية بنجاح. يصف هذا الموقف عدم الاتساق، لأنه مؤقت فقط، وتتم استعادة الاتساق من خلال تشغيل أداة الإصدار.
هناك نوع آخر من التناقض وهو المحتوى الضارّ: الثابتة. إذا وصل الإصدار إلى حالة غير متسقة، لن يستدعي الاستدعاء المتكرر لأداة الإصدار تكراره: تمت إضافة الإصدار، "وST;"; ولا تزال النتائج غير صحيحة. تُعدّ الحالات الثابتة غير المستقرة
السبب الرئيسي وراء كتابة مستخدمي ماركة (وأدوات إنشاء أخرى) make clean
.
يمكن أن يستغرق اكتشاف أداة الإنشاء التي فشلت بهذه الطريقة (وبعدها استردادها) وقتًا طويلاً وقد يكون مزعجًا للغاية.
من الناحية النظرية، إن أبسط طريقة لتحقيق بنية متسقة هي التخلص من جميع مخرجات الإصدار السابق والبدء من جديد: إنشاء كل مبنى بتصميم سهل. من الواضح أن هذا النهج يستغرق وقتًا طويلاً للغاية بحيث لا يكون عمليًا (باستثناء بالنسبة إلى مهندسي الإصدار)، وبالتالي يجب أن تكون أداة الإصدار قادرة على تنفيذ الإصدارات المتزايدة بدون المساس بالاتساق.
يُعدّ الاعتماد المتزايد الصحيح على الاعتمادية صعبًا، وكما هو موضّح أعلاه، تؤدي العديد من أدوات الإنشاء الأخرى أداءً ضعيفًا لتجنُّب الحالات الثابتة غير المستقرة أثناء الإصدارات المتزايدة. في المقابل، توفر Bazel الضمان التالي: بعد الاستدعاء الناجح لأداة الإنشاء التي لم يتم إجراء التعديلات من خلالها، سيكون الإصدار في حالة متسقة. (إذا عدّلت ملفات المصدر أثناء إحدى الإصدارات، لا تضمن Bazel الاتساق لنتيجة التصميم الحالي. ولكنه يضمن أن نتائج الإصدار التالي ستحافظ على الاتساق).
كما هو الحال مع جميع الضمانات، هناك بعض المطبوعات الدقيقة: هناك بعض الطرق المعروفة للوصول إلى حالة مستقرة غير متسقة مع Bazel. لا نضمن التحقيق في تلك المشاكل الناشئة عن المحاولات المتعمّدة للعثور على أخطاء في تحليل الاعتمادية المتزايد، لكننا سنبذل قصارى جهدنا لحلّ جميع الحالات غير المستقرة الناتجة عن الاستخدام العادي أو أداة "عرض الأسعار"
إذا رصدت حالة غير متسقة ثابتة مع Bazel، يُرجى الإبلاغ عن الخطأ.
التنفيذ باستخدام وضع الحماية
يستخدم Bazel وضع الحماية لضمان تنفيذ الإجراءات بشكلٍ سليم وصحيح. يعمل Bazel على ألعاب (تحدُّث بإحكام: الإجراءات) في أوضاع الحماية والتي تحتوي فقط على أقل مجموعة من الملفات التي تطلبها الأداة لتنفيذ مهامها. يعمل وضع الحماية حاليًا على الإصدار 3.12 من نظام التشغيل Linux أو الإصدارات الأحدث مع تفعيل الخيار CONFIG_USER_NS
، وكذلك على الإصدار 10.11 من نظام التشغيل macOS أو الإصدارات الأحدث.
سيطبع Bazel تحذيرًا في حال لم يكن نظام التشغيل لديك يدعم وضع الحماية لتنبيهك بأنّه لا يمكن ضمان أن تكون الإصدارات مزخرفة وقد تؤثر على النظام المضيف بطرق غير معروفة. لإيقاف هذا التحذير، يمكنك تمرير
علامة --ignore_unsupported_sandboxing
إلى Bazel.
في بعض الأنظمة الأساسية، مثل عُقد المجموعة Google Kubernetes
Engine أو Debian،
يتم إيقاف مساحات أسماء المستخدمين تلقائيًا بسبب مخاوف تتعلق بالأمان. يمكن التحقّق من ذلك من خلال الاطّلاع على الملف
/proc/sys/kernel/unprivileged_userns_clone
: إذا كان متوفّرًا ويحتوي على 0،
يمكن تفعيل مساحات أسماء المستخدمين باستخدام
sudo sysctl kernel.unprivileged_userns_clone=1
.
في بعض الحالات، يفشل وضع الحماية في Bazel في تنفيذ القواعد بسبب إعداد النظام. المشكلة هي بشكل عام الإخفاق في الحصول على رسالة مشابهة لـ
namespace-sandbox.c:633: execvp(argv[0], argv): No such file or directory
.
في هذه الحالة، حاوِل إيقاف وضع الحماية للقواعد العامة باستخدام
--strategy=Genrule=standalone
ولقواعد أخرى مع
--spawn_strategy=standalone
. يُرجى أيضًا الإبلاغ عن الخطأ في "أداة تتبّع المشاكل" والإشارة إلى توزيع Linux الذي تستخدمه حتى نتمكّن من التحقيق في المشاكل وحلّها في إصدار لاحق.
مراحل المبنى
في Bazel، يتم تصميم الإصدار على ثلاث مراحل مختلفة، وبصفتك مستخدمًا، يساعدك فهم الفرق بينها على فهم الخيارات التي تتحكّم في إصدار معيّن (انظر أدناه).
مرحلة التحميل
الأمر الأول هو التحميل الذي يتم خلاله تحميل جميع ملفات BUILD اللازمة للأهداف الأولية، وإغلاقها بشكل مؤقت (تبعية) عند تحميلها، وتحليلها، وتقييمها، وتخزينها مؤقتًا.
بالنسبة إلى الإصدار الأول بعد بدء خادم Bazel، عادةً ما تستغرق مرحلة التحميل عدة ثوانٍ حيث يتم تحميل العديد من ملفات BUILD من نظام الملفات. في الإصدارات اللاحقة، وخاصةً في حال عدم تغيير ملفات BUILD، يتم التحميل بسرعة كبيرة.
تتضمّن الأخطاء التي تم الإبلاغ عنها خلال هذه المرحلة: لم يتم العثور على الحزمة، ولم يتم العثور على الهدف، والأخطاء النحوية والنحوية في ملف BUILD، وأخطاء التقييم.
مرحلة التحليل
تتضمن المرحلة الثانية، التحليل، التحليل الدلالي والتحقّق من كل قاعدة إصدار، وإنشاء رسم بياني لاعتمادية الإصدار، وتحديد العمل الذي يجب إنجازه بالضبط في كل خطوة من الإصدار.
كما هو الحال في التحميل، يستغرق تحليل البيانات عدة ثوانٍ أيضًا عند حسابها بالكامل. مع ذلك، يخزّن Bazel الرسم البياني للاعتمادية من مبنى إلى آخر ويحلّل فقط ما يحتاج إليه، ما قد يجعل الإصدارات التدريجية سريعة للغاية في حال عدم تغيّر الحِزم منذ الإصدار السابق.
تتضمّن الأخطاء التي تم الإبلاغ عنها في هذه المرحلة ما يلي: المهام التابعة غير الملائمة، والإدخالات غير الصالحة إلى قاعدة، وجميع رسائل الخطأ الخاصة بالقاعدة.
تتميّز مراحل التحميل والتحليل بالسرعة لأنّ Bazel يتجنّب مؤتمر I/O للملفات غير الضرورية في هذه المرحلة، حيث يتم قراءة ملفات BUILD فقط لتحديد العمل الذي سيتم تنفيذه. ويُعدّ هذا تصميمًا يجعل Bazel أساسًا جيدًا لأدوات التحليل، مثل أمر query الذي يُطبق على مرحلة التحميل.
مرحلة التنفيذ
المرحلة الثالثة والأخيرة من التصميم هي تنفيذ. تضمن هذه المرحلة أن تكون مخرجات كل خطوة في الإصدار متوافقة مع مدخلاته وأدوات التشغيل وإعادة التجميع/الربط وما إلى ذلك حسب الضرورة. ويستغرق هذا الإصدار معظم الوقت في الإنشاء، حيث يتراوح بين بضع ثوانٍ وساعة واحدة لتصميم كبير. وتشمل الأخطاء التي تم الإبلاغ عنها خلال هذه المرحلة: ملفات المصدر المفقودة أو الأخطاء في أداة تم تنفيذها من خلال بعض إجراءات الإصدار أو تعذّر تشغيل الأداة ضمن مجموعة النتائج المتوقّعة.