الحالات الشائعة لاستخدام C++

في ما يلي بعض حالات الاستخدام الأكثر شيوعًا لإنشاء مشاريع C++ باستخدام Bazel. في حال لم يسبق لك البدء، يمكنك البدء في إنشاء مشاريع C++ مع Bazel من خلال إكمال البرنامج التعليمي. مقدمة عن Bazel: إنشاء مشروع C++.

للحصول على معلومات عن ملفات عناوين cc_library وhdrs، راجع cc_library.

تضمين ملفات متعددة في هدف

يمكنك تضمين ملفات متعددة في هدف واحد باستخدام glob. مثال:

cc_library(
    name = "build-all-the-files",
    srcs = glob(["*.cc"]),
    hdrs = glob(["*.h"]),
)

باستخدام هذا الهدف، سينشئ Bazel جميع ملفات .cc و.h التي يعثر عليها في الدليل نفسه كملف BUILD الذي يحتوي على هذا الهدف (باستثناء الأدلة الفرعية).

استخدام العنصر الانتقالي

إذا كان الملف يتضمن عنوانًا، يجب أن تعتمد أي قاعدة مع هذا الملف على مصدر (أي، أن يكون هذا الملف في السمة srcs أو hdrs أو textual_hdrs). في قاعدة مكتبة العنوان المضمّن. وعلى العكس، يجب تحديد تبعيات مباشرة فقط. على سبيل المثال، لنفترض أنّ sandwich.h يشمل bread.h وbread.h يتضمن flour.h. لا تتضمن الخاصية sandwich.h flour.h (التي تريد الدقيق في شطيرتها؟)، وبالتالي يبدو ملف BUILD على النحو التالي:

cc_library(
    name = "sandwich",
    srcs = ["sandwich.cc"],
    hdrs = ["sandwich.h"],
    deps = [":bread"],
)

cc_library(
    name = "bread",
    srcs = ["bread.cc"],
    hdrs = ["bread.h"],
    deps = [":flour"],
)

cc_library(
    name = "flour",
    srcs = ["flour.cc"],
    hdrs = ["flour.h"],
)

هنا، تعتمد مكتبة sandwich على مكتبة bread، التي تعتمد على مكتبة flour.

إضافة مسارات تضمين

في بعض الأحيان، لا يمكنك (أو لا تريد) تضمين المسارات في جذر مساحة العمل. قد تتضمن المكتبات الحالية دليل تضمين لا يتطابق مع مسارها في مساحة العمل. على سبيل المثال، لنفترض أن لديك بنية الدليل التالية:

└── my-project
    ├── legacy
    │   └── some_lib
    │       ├── BUILD
    │       ├── include
    │       │   └── some_lib.h
    │       └── some_lib.cc
    └── WORKSPACE

يتوقع البازيل تضمين some_lib.h كـ legacy/some_lib/include/some_lib.h، ولكن لنفترض أن some_lib.cc يتضمن "some_lib.h". لجعل هذا المسار صالحًا، يجب أن يحدد legacy/some_lib/BUILD أن الدليل some_lib/include هو دليل تضمين:

cc_library(
    name = "some_lib",
    srcs = ["some_lib.cc"],
    hdrs = ["include/some_lib.h"],
    copts = ["-Ilegacy/some_lib/include"],
)

ويُعدّ ذلك مفيدًا بشكل خاص للاعتمادات الخارجية، حيث يجب تضمين ملفات العناوين مع بادئة /.

تضمين المكتبات الخارجية

لنفترض أنك تستخدم اختبار Google. يمكنك استخدام إحدى وظائف المستودع في ملف WORKSPACE لتنزيل Google Test وإتاحته في المستودع:

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

http_archive(
    name = "gtest",
    url = "https://github.com/google/googletest/archive/release-1.10.0.zip",
    sha256 = "94c634d499558a76fa649edb13721dce6e98fb1e7018dfaeba3cd7a083945e91",
    build_file = "@//:gtest.BUILD",
)

بعد ذلك، يمكنك إنشاء gtest.BUILD، ويتم استخدام ملف BUILD لتجميع اختبار Google. هناك عدة متطلبات "خاصة" لـ Google Test تجعل قاعدة cc_library أكثر تعقيدًا:

  • googletest-release-1.10.0/src/gtest-all.cc #includeجميع الملفات الأخرى في النطاق googletest-release-1.10.0/src/: يمكنك استبعادها من التجميع لتجنُّب أخطاء الربط للرموز المكرّرة.

  • يستخدم هذا الرأس ملفات العناوين ذات الصلة بدليل googletest-release-1.10.0/include/ ("gtest/gtest.h")، لذا عليك إضافة هذا الدليل إلى مسارات التضمين.

  • يلزم ربطه في pthread، لذلك أضِفه على أنه linkopt.

وبالتالي، تبدو القاعدة النهائية على النحو التالي:

cc_library(
    name = "main",
    srcs = glob(
        ["googletest-release-1.10.0/src/*.cc"],
        exclude = ["googletest-release-1.10.0/src/gtest-all.cc"]
    ),
    hdrs = glob([
        "googletest-release-1.10.0/include/**/*.h",
        "googletest-release-1.10.0/src/*.h"
    ]),
    copts = [
        "-Iexternal/gtest/googletest-release-1.10.0/include",
        "-Iexternal/gtest/googletest-release-1.10.0"
    ],
    linkopts = ["-pthread"],
    visibility = ["//visibility:public"],
)

هذا غير منظّم إلى حد ما: يبدأ كل عنصر بـ googletest-release-1.10.0 كنتيجة ثانوية لبنية الأرشيف. يمكنك جعل هذه البادئة http_archive شريطية من خلال إضافة السمة strip_prefix:

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

http_archive(
    name = "gtest",
    url = "https://github.com/google/googletest/archive/release-1.10.0.zip",
    sha256 = "94c634d499558a76fa649edb13721dce6e98fb1e7018dfaeba3cd7a083945e91",
    build_file = "@//:gtest.BUILD",
    strip_prefix = "googletest-release-1.10.0",
)

عندئذٍ، سيظهر gtest.BUILD على النحو التالي:

cc_library(
    name = "main",
    srcs = glob(
        ["src/*.cc"],
        exclude = ["src/gtest-all.cc"]
    ),
    hdrs = glob([
        "include/**/*.h",
        "src/*.h"
    ]),
    copts = ["-Iexternal/gtest/include"],
    linkopts = ["-pthread"],
    visibility = ["//visibility:public"],
)

يمكن أن تعتمد الآن قواعد cc_ على @gtest//:main.

كتابة اختبارات C++ وتنفيذها

على سبيل المثال، يمكنك إنشاء اختبار ./test/hello-test.cc، مثل:

#include "gtest/gtest.h"
#include "main/hello-greet.h"

TEST(HelloTest, GetGreet) {
  EXPECT_EQ(get_greet("Bazel"), "Hello Bazel");
}

بعد ذلك، عليك إنشاء ملف ./test/BUILD للاختبارات:

cc_test(
    name = "hello-test",
    srcs = ["hello-test.cc"],
    copts = ["-Iexternal/gtest/include"],
    deps = [
        "@gtest//:main",
        "//main:hello-greet",
    ],
)

لإظهار hello-greet لـ hello-test، عليك إضافة "//test:__pkg__", إلى السمة visibility في ./main/BUILD.

يمكنك الآن استخدام bazel test لإجراء الاختبار.

bazel test test:hello-test

ينتج عن ذلك الناتج التالي:

INFO: Found 1 test target...
Target //test:hello-test up-to-date:
  bazel-bin/test/hello-test
INFO: Elapsed time: 4.497s, Critical Path: 2.53s
//test:hello-test PASSED in 0.3s

Executed 1 out of 1 tests: 1 test passes.

إضافة العناصر الاعتمادية على المكتبات المجمّعة

إذا كنت تريد استخدام مكتبة ليس لديك إلا نسخة مجمّعة منها (على سبيل المثال، العناوين وملف .so)، يمكنك لفها في قاعدة cc_library:

cc_library(
    name = "mylib",
    srcs = ["mylib.so"],
    hdrs = ["mylib.h"],
)

وبهذه الطريقة، يمكن أن تعتمد أهداف C++ أخرى في مساحة العمل على هذه القاعدة.