موارد استفاده رایج ساخت C++

در اینجا تعدادی از رایج ترین موارد استفاده برای ساخت پروژه های C++ با Bazel را خواهید دید. اگر قبلاً این کار را انجام نداده‌اید، با تکمیل آموزش مقدمه Bazel: ساخت پروژه C++ با 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

Bazel انتظار 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 Test استفاده می کنید. می توانید از یکی از توابع مخزن در فایل 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 Test چندین الزام "ویژه" دارد که قانون cc_library آن را پیچیده تر می کند:

  • googletest-release-1.10.0/src/gtest-all.cc #include s تمام فایل های دیگر در 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 به عنوان محصول فرعی ساختار آرشیو است. می توانید با افزودن ویژگی strip_prefix ، http_archive strip این پیشوند را ایجاد کنید:

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++ در فضای کاری شما می توانند به این قانون وابسته باشند.