Tại đây, bạn sẽ tìm thấy một số trường hợp sử dụng phổ biến nhất để tạo các dự án C++ bằng Bazel. Nếu chưa thực hiện, hãy bắt đầu xây dựng các dự án C++ bằng Bazel bằng cách hoàn tất hướng dẫn Giới thiệu về Bazel: Xây dựng dự án C++.
Để biết thông tin về tệp tiêu đề cc_library và hdrs, hãy xem phần cc_library.
Thêm nhiều tệp vào một mục tiêu
Bạn có thể đưa nhiều tệp vào một đích duy nhất 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à nó tìm thấy trong cùng thư mục với tệp BUILD
chứa mục tiêu này (không bao gồm các thư mục con).
Sử dụng các lệnh include bắc cầu
Nếu một tệp có tiêu đề, thì mọi quy tắc có tệp đó làm nguồn (tức là có tệp đó trong thuộc tính srcs
, hdrs
hoặc textual_hdrs
) đều phải 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 làm 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
(ai muốn bột trong bánh mì kẹp?), vì vậy, 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 lại 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) đặt đường dẫn gốc bao gồm tại thư mục gốc của không gian làm việc. Các thư viện hiện có có thể đã có một thư mục include không khớp với đường dẫn của thư viện đó trong không gian làm việc của bạn. 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 sẽ mong đợi some_lib.h
được đưa vào 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
sẽ cần chỉ định rằng thư mục some_lib/include
là một thư mục bao gồ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ì các tệp tiêu đề của chúng phải được đưa vào bằng 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 kho lưu trữ trong tệp WORKSPACE
để tải Google Test xuống và cung cấp trong kho lưu trữ của mình:
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
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 này khỏi quá trình biên dịch để ngăn lỗi liên kết cho các biểu tượng trùng lặp.Thư viện 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.Bạn cần liên kết trong
pthread
, vì vậy hãy thêmpthread
làmlinkopt
.
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 có phần 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 lưu trữ. Bạn có thể khiến http_archive
loại 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"],
)
Giờ đây, các quy tắc cc_
có thể phụ thuộc vào @gtest//:main
.
Viết và chạy các bài 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",
],
)
Để hello-greet
hiển thị cho hello-test
, bạn phải thêm "//test:__pkg__",
vào thuộc tính visibility
trong ./main/BUILD
.
Giờ đây, bạn có thể dùng bazel test
để chạy kiểm thử.
bazel test test:hello-test
Kết quả sẽ như 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 các phần phụ thuộc vào thư viện được biên dịch sẵn
Nếu muốn sử dụng một thư viện mà bạn chỉ có phiên bản đã biên dịch (ví dụ: tiêu đề và tệp .so
), hãy gói thư viện đó trong một 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.