Ở đây, bạn sẽ tìm thấy một số trường hợp sử dụng phổ biến nhất để xây dựng dự án C++ bằng Bazel. Nếu bạn chưa thực hiện việc này, hãy bắt đầu tạo dự án C++ bằng Bazel bằng cách hoàn thành phần hướng dẫn Giới thiệu về Bazel: Xây dựng dự án C++.
Để biết thông tin về các tệp tiêu đề cc_library và hdrs, hãy xem cc_library.
Đưa nhiều tệp vào một đích
Bạn có thể đưa nhiều tệp vào một mục tiêu bằng glob. Ví dụ:
cc_library(
name = "build-all-the-files",
srcs = glob(["*.cc"]),
hdrs = glob(["*.h"]),
)
Với mục tiêu này, Bazel sẽ tạo tất cả các tệp .cc
và .h
mà công cụ này tìm thấy trong
cùng thư mục với tệp BUILD
chứa mục tiêu này (ngoại trừ
thư mục con).
Sử dụng bắc cầu bao gồm
Nếu một tệp có tiêu đề, thì mọi quy tắc có tệp đó dưới dạng nguồn (nghĩa là có tệp đó trong thuộc tính srcs
, hdrs
hoặc textual_hdrs
) sẽ phụ thuộc vào quy tắc thư viện của tiêu đề được đưa vào. Ngược lại, bạn chỉ cần chỉ định các phần phụ thuộc trực tiếp dưới dạng các phần phụ thuộc. Ví dụ: Giả sử sandwich.h
bao gồm bread.h
và bread.h
bao gồm flour.h
. sandwich.h
không bao gồm flour.h
(những người muốn dùng bột mì trong bánh mì?), tệp BUILD
sẽ có dạng như sau:
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"],
)
Ở đây, thư viện sandwich
phụ thuộc vào thư viện bread
, thư viện này phụ thuộc
vào thư viện flour
.
Thêm đường dẫn bao gồm
Đôi khi, bạn không thể (hoặc không muốn) thư mục gốc bao gồm đường dẫn ở thư mục gốc không gian làm việc. Các thư viện hiện có có thể đã có thư mục include không khớp với đường dẫn trong thư mục trong không gian làm việc. Ví dụ, giả sử bạn có cấu trúc thư mục sau:
└── my-project
├── legacy
│ └── some_lib
│ ├── BUILD
│ ├── include
│ │ └── some_lib.h
│ └── some_lib.cc
└── WORKSPACE
Bazel dự kiến sẽ bao gồm some_lib.h
dưới dạng legacy/some_lib/include/some_lib.h
, nhưng giả sử some_lib.cc
bao gồm "some_lib.h"
. Để đường dẫn đó bao gồm hợp lệ,
legacy/some_lib/BUILD
cần chỉ định rằng thư mục some_lib/include
là một thư mục đi kèm:
cc_library(
name = "some_lib",
srcs = ["some_lib.cc"],
hdrs = ["include/some_lib.h"],
copts = ["-Ilegacy/some_lib/include"],
)
Điều này đặc biệt hữu ích cho các phần phụ thuộc bên ngoài vì tệp tiêu đề phải được thêm vào sau tiền tố /
.
Bao gồm các thư viện bên ngoài
Giả sử bạn đang sử dụng Google Test.
Bạn có thể sử dụng một trong các hàm lưu trữ trong tệp WORKSPACE
để tải Google Test xuống và cung cấp hàm đó trong kho lưu trữ của bạn:
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",
)
Sau đó, hãy tạo gtest.BUILD
, một tệp BUILD
dùng để biên dịch Google Test.
Google Test có một số yêu cầu "đặc biệt" khiến quy tắc cc_library
của nó trở nên phức tạp hơn:
googletest-release-1.10.0/src/gtest-all.cc
#include
tất cả các tệp khác tronggoogletest-release-1.10.0/src/
: loại trừ tệp đó khỏi quá trình biên dịch để ngăn các lỗi liên kết cho những ký hiệu trùng lặp.Công cụ này sử dụng các tệp tiêu đề tương ứng với thư mục
googletest-release-1.10.0/include/
("gtest/gtest.h"
), vì vậy bạn phải thêm thư mục đó vào các đường dẫn bao gồm.Nó cần liên kết trong
pthread
, vì vậy hãy thêm nó dưới dạnglinkopt
.
Do đó, quy tắc cuối cùng sẽ có dạng như sau:
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"],
)
Điều này hơi lộn xộn: mọi thứ đều có tiền tố googletest-release-1.10.0
như một sản phẩm phụ của cấu trúc tệp lưu trữ. Bạn có thể đặt http_archive
bỏ tiền tố này bằng cách thêm thuộc tính 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",
)
Sau đó, gtest.BUILD
sẽ có dạng như sau:
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"],
)
Hiện tại, các quy tắc cc_
có thể phụ thuộc vào @gtest//:main
.
Viết và chạy kiểm thử C++
Ví dụ: bạn có thể tạo một ./test/hello-test.cc
kiểm thử, chẳng hạn như:
#include "gtest/gtest.h"
#include "main/hello-greet.h"
TEST(HelloTest, GetGreet) {
EXPECT_EQ(get_greet("Bazel"), "Hello Bazel");
}
Sau đó, hãy tạo tệp ./test/BUILD
cho các kiểm thử của bạn:
cc_test(
name = "hello-test",
srcs = ["hello-test.cc"],
copts = ["-Iexternal/gtest/include"],
deps = [
"@gtest//:main",
"//main:hello-greet",
],
)
Để hiển thị hello-greet
cho hello-test
, bạn phải thêm
"//test:__pkg__",
vào thuộc tính visibility
trong ./main/BUILD
.
Bây giờ, bạn có thể sử dụng bazel test
để chạy kiểm thử.
bazel test test:hello-test
Thao tác này sẽ tạo ra kết quả sau:
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.
Thêm phần phụ thuộc vào các thư viện đã biên dịch trước
Nếu muốn sử dụng một thư viện mà bạn chỉ có phiên bản được biên dịch (ví dụ:
tiêu đề và tệp .so
), hãy gói thư viện đó vào quy tắc cc_library
:
cc_library(
name = "mylib",
srcs = ["mylib.so"],
hdrs = ["mylib.h"],
)
Bằng cách này, các mục tiêu C++ khác trong không gian làm việc của bạn có thể phụ thuộc vào quy tắc này.