البرنامج التعليمي بازيل: إنشاء مشروع C++

مقدمة

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

Bazel هو نظام إصدار يتوافق مع إصدارات بلغات متعددة، إلا أنّ هذا البرنامج التعليمي يستخدم مشروع C++ كمثال، كما يوفّر إرشادات عامة وتدفقًا ينطبق على معظم اللغات.

المدة المقدّرة للاكتمال: 30 دقيقة.

المتطلّبات الأساسية

ابدأ بتثبيت Bazel، إذا لم يسبق لك ذلك. يستخدم هذا البرنامج التعليمي أداة Git للتحكّم في المصدر، لذلك للحصول على أفضل النتائج، ثبِّت Git أيضًا.

بعد ذلك، يمكنك استرداد نموذج المشروع من مستودع Bazel' GitHub من خلال تشغيل ما يلي في أداة سطر الأوامر التي تختارها:

git clone https://github.com/bazelbuild/examples

يتوفر نموذج المشروع لهذا البرنامج التعليمي في الدليل examples/cpp-tutorial.

يُرجى الاطّلاع أدناه على كيفية تنظيم بنية البيانات:

examples
└── cpp-tutorial
    ├──stage1
    │  ├── main
    │  │   ├── BUILD
    │  │   └── hello-world.cc
    │  └── WORKSPACE
    ├──stage2
    │  ├── main
    │  │   ├── BUILD
    │  │   ├── hello-world.cc
    │  │   ├── hello-greet.cc
    │  │   └── hello-greet.h
    │  └── WORKSPACE
    └──stage3
       ├── main
       │   ├── BUILD
       │   ├── hello-world.cc
       │   ├── hello-greet.cc
       │   └── hello-greet.h
       ├── lib
       │   ├── BUILD
       │   ├── hello-time.cc
       │   └── hello-time.h
       └── WORKSPACE

هناك ثلاث مجموعات من الملفات، كل مجموعة تمثل مرحلة في هذا البرنامج التعليمي. في المرحلة الأولى، عليك إنشاء هدف واحد متوفّر في حزمة واحدة. وفي المرحلة الثانية، عليك إنشاء كل من برنامج ثنائي ومكتبة من حزمة واحدة. وفي المرحلة الثالثة والأخيرة، سيكون عليك إنشاء مشروع يضم حِزم متعدّدة وبناءً عليه أهداف متعددة.

الملخص: مقدمة

من خلال تثبيت Bazel (وGit) ونسخ مستودع هذا البرنامج التعليمي، مهّدت أساسًا لإصدارك الأول مع Bazel. يمكنك المتابعة إلى القسم التالي لتحديد بعض العبارات وإعداد مساحة العمل.

البدء

إعداد مساحة العمل

قبل إنشاء مشروع، عليك إعداد مساحة عمل له. مساحة العمل هي دليل يضم ملفات المصدر الخاصة بمشروعك وملفات Bazel&#39s، ويتم إنشاؤها بسهولة. ويتضمّن الملف أيضًا هذه الملفات المهمة:

  • WORKSPACE file ، التي تعرّف الدليل ومحتواه كمساحة عمل في Bazel وتقع في جذر بنية الدليل.
  • نوع واحد أو أكثر من ملفات BUILD files ، وهو ما يُخبر بازل كيفية إنشاء أجزاء مختلفة من المشروع. الدليل ضمن مساحة العمل التي تحتوي على ملف BUILD هو حزمة. (المزيد في الحِزم لاحقًا في هذا البرنامج التعليمي)

في المشاريع المستقبلية، لتصنيف دليل على أنه مساحة عمل Bazel، يمكنك إنشاء ملف فارغ باسم WORKSPACE في هذا الدليل. لأغراض هذا البرنامج التعليمي، يتوفّر ملف WORKSPACE في كل مرحلة.

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

فهم ملف BUILD

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

اطّلِع على الملف BUILD في الدليل cpp-tutorial/stage1/main:

cc_binary(
    name = "hello-world",
    srcs = ["hello-world.cc"],
)

في المثال هنا، ينشئ هدف hello-world مثيل Bazel's المضمّنcc_binary rule. تطلب القاعدة من Bazel إنشاء برنامج ثنائي قابل للتنفيذ مستقل من ملف المصدر hello-world.cc بدون تبعيات.

الملخص: البدء

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

المرحلة 1: استهداف واحد وحزمة واحدة

حان الوقت لإنشاء الجزء الأول من المشروع. كمرجع مرئي، بنية البند 1 من المشروع هي:

examples
└── cpp-tutorial
    └──stage1
       ├── main
       │   ├── BUILD
       │   └── hello-world.cc
       └── WORKSPACE

شغِّل ما يلي للانتقال إلى دليل cpp-tutorial/stage1:

cd cpp-tutorial/stage1

الخطوة التالية:

bazel build //main:hello-world

في التصنيف المستهدف، يكون الجزء //main: هو موقع الملف BUILD بالنسبة إلى جذر مساحة العمل، وhello-world هو الاسم المستهدف في الملف BUILD.

وتنشئ Bazel ما يبدو على النحو التالي:

INFO: Found 1 target...
Target //main:hello-world up-to-date:
  bazel-bin/main/hello-world
INFO: Elapsed time: 2.267s, Critical Path: 0.25s

لقد أنشأت للتو هدف Bazel الأول. تُنشئ أماكن Bazel مخرجات في دليل bazel-bin في جذر مساحة العمل.

يمكنك الآن اختبار البرنامج الثنائي الذي تم إنشاؤه حديثًا، وهو:

bazel-bin/main/hello-world

يؤدي ذلك إلى ظهور رسالة "Hello world" مطبوعة.

في ما يلي رسم بياني للاعتمادية للمرحلة 1:

يعرض الرسم البياني للمهام التابعة لمرحبًا بالعالم هدفًا واحدًا مع ملف مصدر واحد.

الملخّص: المرحلة 1

الآن بعد الانتهاء من الإصدار الأول، أصبحت لديك فكرة أساسية عن كيفية تنظيم الإصدار. في المرحلة التالية، ستضيف تعقيدًا من خلال إضافة هدف آخر.

المرحلة 2: استهدافات تصميم متعددة

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

في ما يلي الدليل الذي تستخدمه مع المرحلة الثانية:

    ├──stage2
    │  ├── main
    │  │   ├── BUILD
    │  │   ├── hello-world.cc
    │  │   ├── hello-greet.cc
    │  │   └── hello-greet.h
    │  └── WORKSPACE

يمكنك الاطّلاع على ملف BUILD أدناه في الدليل cpp-tutorial/stage2/main:

cc_library(
    name = "hello-greet",
    srcs = ["hello-greet.cc"],
    hdrs = ["hello-greet.h"],
)

cc_binary(
    name = "hello-world",
    srcs = ["hello-world.cc"],
    deps = [
        ":hello-greet",
    ],
)

باستخدام ملف BUILD هذا، أنشأ Bazel مكتبة hello-greet لأول مرة (باستخدام Bazel's المضمّنة cc_library rule)، ثم برنامج ثنائي hello-world. تحدّد السمة deps في الهدف hello-world Bazel أن مكتبة hello-greet مطلوبة لإنشاء البرنامج الثنائي hello-world.

قبل إنشاء هذا الإصدار الجديد من المشروع، عليك تغيير الأدلة، والتبديل إلى دليل cpp-tutorial/stage2 من خلال تنفيذ ما يلي:

cd ../stage2

يمكنك الآن إنشاء برنامج ثنائي جديد باستخدام الأمر المألوف التالي:

bazel build //main:hello-world

مجددًا، ينشئ Bazel ما يشبه ما يلي:

INFO: Found 1 target...
Target //main:hello-world up-to-date:
  bazel-bin/main/hello-world
INFO: Elapsed time: 2.399s, Critical Path: 0.30s

يمكنك الآن اختبار البرنامج الثنائي الذي تم إنشاؤه حديثًا، والذي يعرض "Hello world" آخر:

bazel-bin/main/hello-world

إذا عدّلت hello-greet.cc الآن وأعدت إنشاء المشروع، سيجمّع Bazel هذا الملف فقط.

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

يُظهر الرسم البياني للمهام التابعة لـ "مرحبًا بالعالم" تغييرات البنية بعد تعديلها على الملف.

الملخّص: المرحلة 2

لقد أنشأت المشروع الآن باستخدام هدفين. ينشئ الهدف hello-world ملف مصدر واحدًا ويعتمد على هدف آخر واحد (//main:hello-greet)، ما يؤدي إلى إنشاء ملفَي مصدر إضافيَين. في القسم التالي، يمكنك اتخاذ خطوة أخرى وإضافة حزمة أخرى.

المرحلة 3: باقات متعددة

تضيف هذه المرحلة طبقة أخرى من التعقيدات، وتنشئ مشروعًا يحتوي على حِزم متعدّدة. يمكنك الاطّلاع على بنية دليل cpp-tutorial/stage3 ومحتواه:

└──stage3
   ├── main
   │   ├── BUILD
   │   ├── hello-world.cc
   │   ├── hello-greet.cc
   │   └── hello-greet.h
   ├── lib
   │   ├── BUILD
   │   ├── hello-time.cc
   │   └── hello-time.h
   └── WORKSPACE

يمكنك أن ترى أن هناك الآن دليلين فرعيين، ويحتوي كل منهما على ملف BUILD. لذلك، تضمّ مساحة العمل الآن حزمة Bazel تتضمّن حزمتَين: lib وmain.

يُرجى إلقاء نظرة على ملف lib/BUILD:

cc_library(
    name = "hello-time",
    srcs = ["hello-time.cc"],
    hdrs = ["hello-time.h"],
    visibility = ["//main:__pkg__"],
)

وفي ملف main/BUILD:

cc_library(
    name = "hello-greet",
    srcs = ["hello-greet.cc"],
    hdrs = ["hello-greet.h"],
)

cc_binary(
    name = "hello-world",
    srcs = ["hello-world.cc"],
    deps = [
        ":hello-greet",
        "//lib:hello-time",
    ],
)

يعتمد هدف hello-world في الحزمة الرئيسية على الهدف hello-time في الحزمة lib (بالتالي تصنيف التصنيف //lib:hello-time) - يعرف Bazel هذا من خلال السمة deps. وينعكس ذلك في الرسم البياني للاعتمادية:

يُظهر الرسم البياني للمهام التابعة لـ "مرحبًا بك في العالم" كيف يعتمد الاستهداف في الحزمة الرئيسية على الهدف في حزمة "lib".

لكي يعمل الإصدار بنجاح، يمكنك جعل الهدف //lib:hello-time في lib/BUILD مرئيًا بشكلٍ صريح في إعدادات main/BUILD باستخدام سمة مستوى الرؤية. ويرجع ذلك إلى أنّ الاستهدافات التلقائية لا تظهر إلا للأهداف الأخرى في ملف BUILD نفسه. يستخدم Bazel مستوى الرؤية المستهدف لمنع المشاكل مثل المكتبات التي تحتوي على تفاصيل التنفيذ التي يتم تسريبها إلى واجهات برمجة التطبيقات المتاحة للجميع.

والآن، أنشئ هذه النسخة النهائية من المشروع. يمكنك الانتقال إلى الدليل cpp-tutorial/stage3 من خلال تشغيل:

cd  ../stage3

شغِّل الأمر مرة أخرى:

bazel build //main:hello-world

وتنشئ Bazel ما يبدو على النحو التالي:

INFO: Found 1 target...
Target //main:hello-world up-to-date:
  bazel-bin/main/hello-world
INFO: Elapsed time: 0.167s, Critical Path: 0.00s

اختبِر الآن البرنامج الثنائي الأخير من هذا البرنامج التعليمي لرسالة Hello world نهائية:

bazel-bin/main/hello-world

الملخّص: المرحلة 3

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

الخطوات اللاحقة

لقد أكملت الآن إصدارك الأول من Bazel، ولكن هذا ليس سوى البداية. في ما يلي بعض المراجع الإضافية لمواصلة التعلّم باستخدام Bazel:

نتمنى لك مبنى سعيدًا!