Bazel
Project
├── main
│ ├── BUILD
│ ├── hello-world.cc
│ ├── hello-greet.cc
│ └── hello-greet.h
├── lib
│ ├── BUILD
│ ├── hello-time.cc
│ └── hello-time.h
└── WORKSPACE
Two files that Bazel recognizes as special:
-
The WORKSPACE file, which identifies the directory and its contents as a Bazel workspace and lives at the root of the project’s directory structure,
-
One or more BUILD files, which tell Bazel how to build different parts of the project. (A directory within the workspace that contains a BUILD file is a package.)
To designate a directory as a Bazel workspace, create an empty file named WORKSPACE in that directory.
Understand the BUILD file
A BUILD file contains several different types of instructions for Bazel. The most important type is the build rule, which tells Bazel how to build the desired outputs, such as executable binaries or libraries. Each instance of a build rule in the BUILD file is called a target and points to a specific set of source files and dependencies. A target can also point to other targets.
lib/BUILD file:
cc_library(
name = "hello-time",
srcs = ["hello-time.cc"],
hdrs = ["hello-time.h"],
visibility = ["//main:__pkg__"],
)
main/BUILD file:
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",
],
)
Notices we make the //lib:hello-time target in lib/BUILD explicitly visible to targets in main/BUILD using the visibility attribute. This is because by default targets are only visible to other targets in the same BUILD file.
build project
bazel build //main:hello-world
The //main:
means the location of our BUILD file, //
means the location of WORKSPACE file, hello-world
is our target name. Output is store is bazel-bin/main/hello-worl
cc_library
cc_library( name = "memory_store", srcs = glob([ "memory_store/*.cpp", ]), hdrs = glob([ "memory_store/*.hpp", ]), deps = [ "@com_github_google_glog//:glog", ], )
see dependency graph
First need install GraphViz
and xdot
|
|
bazel query --notool_deps --noimplicit_deps "deps(//main:hello-world)" \
--output graph
xdot <(bazel query --notool_deps --noimplicit_deps "deps(//main:hello-world)" \
--output graph)
Working with external dependencies
Dependencies from these other projects are called external dependencies.
Suppose there are two projects on a system:
/
home/
user/
project1/
WORKSPACE
BUILD
srcs/
...
project2/
WORKSPACE
BUILD
my-libs/
If project1 wanted to depend on a target, :foo, defined in /home/user/project2/BUILD, it could specify that a repository named project2 could be found at /home/user/project2. Then targets in /home/user/project1/BUILD could depend on @project2//:foo.
Depending on other Bazel projects
If you want to use targets from a second Bazel project, you can use local_repository
, git_repository
or http_archive
to symlink it from the local filesystem, reference a git repository or download it (respectively).
For example, suppose you are working on a project, my-project/, and you want to depend on targets from your coworker’s project, coworkers-project/. Both projects use Bazel, so you can add your coworker’s project as an external dependency and then use any targets your coworker has defined from your own BUILD files. You would add the following to my_project/WORKSPACE:
package(default_visibility = ["//visibility:public"])
local_repository(
name = "coworkers_project",
path = "/path/to/coworkers-project",
)
If your coworker has a target //foo:bar, your project can refer to it as @coworkers_project//foo:bar. External project names must be valid workspace names, so (valid) is used to replace (invalid) in the name coworkers_project.
Depending on non-Bazel projects
Rules prefixed with new_
, e.g., new_local_repository
, allow you to create targets from projects that do not use Bazel.
For example, suppose you are working on a project, my-project/, and you want to depend on your coworker’s project, coworkers-project/. Your coworker’s project uses make to build, but you’d like to depend on one of the .so files it generates. To do so, add the following to my_project/WORKSPACE
:
new_local_repository(
name = "coworkers_project",
path = "/path/to/coworkers-project",
build_file = "coworker.BUILD",
)
build_file specifies a BUILD file to overlay on the existing project, for example:
cc_library(
name = "some-lib",
srcs = glob(["**"]),
visibility = ["//visibility:public"],
)
You can then depend on @coworkers_project//:some-lib from your project’s BUILD files.
Depending on external packages
By default, external dependencies are fetched as needed during bazel build
. If you would like to prefetch the dependencies needed for a specific set of targets, use bazel fetch
. To unconditionally fetch all external dependencies, use bazel sync
. As fetched repositories are stored in the output base, fetching happens per workspace.
using with grpc
-
proto_library
:Recommended code organization:
- One proto_library rule per .proto file.
- A file named foo.proto will be in a rule named foo_proto, which is located in the same package.
- A [language]proto_library that wraps a proto_library named foo_proto should be called foo[language]_proto, and be located in the same package.
-
cc_proto_library
: cc_proto_library generates C++ code from .proto files. deps must point to proto_library rules.
proto_library(
name = "helloworld_proto",
srcs = ["helloworld.proto"],
)
cc_proto_library(name = "helloworld_cc_proto",
deps = [":helloworld_proto"],)
cc_grpc_library(
name = "helloworld_cc_grpc",
srcs = [":helloworld_proto"],
grpc_only = True,
deps = [":helloworld_cc_proto"],
)
cc_grpc_library
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
load("@rules_proto//proto:defs.bzl", "proto_library") load("//bazel:generate_cc.bzl", "generate_cc") load("//bazel:protobuf.bzl", "well_known_proto_libs") def cc_grpc_library( name, srcs, deps, proto_only = False, well_known_protos = False, generate_mocks = False, use_external = False, grpc_only = False, **kwargs): """Generates C++ grpc classes for services defined in a proto file. If grpc_only is True, this rule is compatible with proto_library and cc_proto_library native rules such that it expects proto_library target as srcs argument and generates only grpc library classes, expecting protobuf messages classes library (cc_proto_library target) to be passed in deps argument. By default grpc_only is False which makes this rule to behave in a backwards-compatible mode (trying to generate both proto and grpc classes). Assumes the generated classes will be used in cc_api_version = 2. Args: name (str): Name of rule. srcs (list): A single .proto file which contains services definitions, or if grpc_only parameter is True, a single proto_library which contains services descriptors. deps (list): A list of C++ proto_library (or cc_proto_library) which provides the compiled code of any message that the services depend on. proto_only (bool): If True, create only C++ proto classes library, avoid creating C++ grpc classes library (expect it in deps). Deprecated, use native cc_proto_library instead. False by default. well_known_protos (bool): Should this library additionally depend on well known protos. Deprecated, the well known protos should be specified as explicit dependencies of the proto_library target (passed in srcs parameter) instead. False by default. generate_mocks (bool): when True, Google Mock code for client stub is generated. False by default. use_external (bool): Not used. grpc_only (bool): if True, generate only grpc library, expecting protobuf messages library (cc_proto_library target) to be passed as deps. False by default (will become True by default eventually). **kwargs: rest of arguments, e.g., compatible_with and visibility """
grpc_cc_library
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
def grpc_cc_library( name, srcs = [], public_hdrs = [], hdrs = [], external_deps = [], defines = [], deps = [], select_deps = None, standalone = False, language = "C++", testonly = False, visibility = None, alwayslink = 0, data = [], use_cfstream = False, tags = [], linkstatic = False): """An internal wrapper around cc_library. Args: name: The name of the library. srcs: The source files. public_hdrs: The public headers. hdrs: The headers. external_deps: External depdendencies to be resolved. defines: Build defines to use. deps: cc_library deps. select_deps: deps included conditionally. standalone: Unused. language: The language of the library, e.g. C, C++. testonly: Whether the target is for tests only. visibility: The visibility of the target. alwayslink: Whether to enable alwayslink on the cc_library. data: Data dependencies. use_cfstream: Whether to use cfstream. tags: Tags to apply to the rule. linkstatic: Whether to enable linkstatic on the cc_library. """
cc_library
cc_library( name = "some_lib", srcs = ["some_lib.cc"], hdrs = ["some_lib.h"], copts = ["-Ithird_party/some_lib"], # 引入第三方头文件 )
依赖预编译的库
cc_library( name = "mylib", srcs = ["mylib.so"], hdrs = ["mylib.h"], )
- 利用 bazel 来使用 grpc 很方便,只需要在 WORKSPACE 文件添加如下:
workspace(name = "grpc_test")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "rules_proto",
sha256 = "66bfdf8782796239d3875d37e7de19b1d94301e8972b3cbd2446b332429b4df1",
strip_prefix = "rules_proto-4.0.0",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/rules_proto/archive/refs/tags/4.0.0.tar.gz",
"https://github.com/bazelbuild/rules_proto/archive/refs/tags/4.0.0.tar.gz",
],
)
load("@rules_proto//proto:repositories.bzl", "rules_proto_dependencies", "rules_proto_toolchains")
rules_proto_dependencies()
rules_proto_toolchains()
local_repository(
name = "com_github_grpc_grpc",
path = "/home/reas/Software/grpc"
)
load("@com_github_grpc_grpc//bazel:grpc_deps.bzl", "grpc_deps")
grpc_deps()
load("@com_github_grpc_grpc//bazel:grpc_extra_deps.bzl", "grpc_extra_deps")
grpc_extra_deps()
BUILD 文件:
package(default_visibility = ["//visibility:public"])
load("@com_github_grpc_grpc//bazel:grpc_build_system.bzl", "grpc_proto_library")
grpc_proto_library(
name = "helloworld",
srcs = ["helloworld.proto"],
)
cc_binary(
name = "greeter_client",
srcs = ["greeter_client.cc"],
defines = ["BAZEL_BUILD"],
deps = [
"@com_github_grpc_grpc//:grpc++",
":helloworld",
],
)
include third-libs
cc_library(
name = "some_lib",
srcs = ["some_lib.cc"],
hdrs = ["some_lib.h"],
copts = ["-Ithird_party/some_lib"],
)
bazel 命令
- run
bazel run //cpp:reas -- --head
其中的--
是必须要的,代表后面的为程序执行传入的参数。
bazelrc
.bazelrc 可以直接放到项目的根目录下。
build --cxxopt='--std=c++17'
build --test_tmpdir=/tmp/foo --verbose_failures
build --test_tmpdir=/tmp/bar
build --color=yes
编译 cython 代码
BUILD 文件中加入
package(default_visibility = ["//visibility:public"])
load("@rules_python//python:defs.bzl", "py_library")
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_proto_library", "cc_test")
load("@com_github_grpc_grpc//bazel:cc_grpc_library.bzl", "cc_grpc_library")
load("@com_github_grpc_grpc//bazel:cython_library.bzl", "pyx_library")
cc_library (
name = "c_driver",
srcs = ["driver/driver.cpp",],
hdrs = ["driver/driver.hpp"],
deps = [
"@com_github_grpc_grpc//:grpc++",
"@com_github_grpc_grpc//:grpc++_reflection",
"@com_github_google_glog//:glog",
"//grpc:task_grpc",
"//cpp:utils",
],
)
pyx_library (
name = "py_driver",
srcs = glob([
"driver/*.pxd",
"driver/*.pyx",
]),
deps = [
":c_driver",
],
)
更改 bazel output 目录
bazel --output_base=/tmp/bazel/output build ://main
Problems
- name 'git_repository' is not defined
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
- ERROR: /home/reas/Workspace/example/foo/BUILD:1:10: Linking of rule '//foo:foo' failed (Exit 1): gcc failed: error executing command /usr/bin/gcc @bazel-out/k8-fastbuild/bin/foo/foo-2.params
升级 bazel 至 4 以上
-
src/greeter_client.cc:24:10: fatal error: helloworld.grpc.pb.h: No such file or directory #include "helloworld.grpc.pb.h"
出现不能找到 .h 文件时,需要注意在代码中#include ""
的地址需要是相对于\\
项目地址 -
bring non-source tree absolute paths into your workspace It suggests to set up a local repository: WORKSPACE:
new_local_repository(
name = "llvm",
path = "/usr/lib/llvm-6.0/include",
build_file_content = """
package(default_visibility = ["//visibility:public"])
cc_library(
name = "headers",
hdrs = glob(["**/*.h"])
)
"""
)
BUILD:
cc_binary(
name = "my-llvm-project",
srcs = glob(["*.cc"]),
copts = ["-Iexternal/llvm"],
deps = ["@llvm//:headers"]
)
编译定义宏
bazel build --cxxopt=-DNDEBUG
以上定义了宏 NDEBUG
, 亦可在 .bazelrc
文件中加入
build --cxxopt=-DNDEBUG