官网:https://www.bazel.build/
github:https://github.com/bazelbuild/bazel
https://docs.bazel.build/versions/master/bazel-overview.html
https://blog.csdn.net/u013510838/article/details/80102438
https://www.jianshu.com/p/4e778df3c13b
Bazel是一个类似于Make,Maven和Gradle的开源构建和测试工具。Bazel支持多种语言的项目,并为多个平台构建输出。Bazel支持跨多个存储库和大量用户的大型代码库。
具有高级构建语言、快速可靠、多平台、扩展性强、规模大等优点。
要使用Bazel构建或测试项目,通常需要执行以下操作:
设置Bazel。下载并安装Bazel。https://docs.bazel.build/versions/master/install.html。
建立项目工作区Workspace。每个工作空间中有一个WORKSPACE文件,来描述工作空间所使用到的信息。
创建一个BUILD
文件。每个程序包package中包含一个BUILD文件,此文件中描述了此工具包的生成构建方式。
您使用Starlark(一种特定于域的语言 https://docs.bazel.build/versions/master/skylark/language.html)声明构建目标来编写BUILD文件 。(见例子 https://github.com/bazelbuild/bazel/blob/master/examples/cpp/BUILD )
运行Bazel。Bazel将输出放在工作区内。
除了构建之外,您还可以使用Bazel运行 测试并查询构建以跟踪代码中的依赖项。
运行构建或测试时,Bazel执行以下操作:
加载与目标相关的BUILD
文件。
分析输入及其 依赖关系,应用指定的构建规则,并生成操作 图。
对输入执行构建操作,直到生成最终构建输出。
由于所有以前的构建工作都是缓存的,因此Bazel可以识别并重用缓存的工件,只重建或重新测试更改的内容。
和Makefile一样,使用bazel编译也必须满足它的项目结构要求。这也许是为什么bazel还不够普及的原因所在吧。bazel顶层,也就是根目录下为工作区workspace,workspace下包含多个package,每个package又包含多个编译目标target。
Bazel根据在称为workspace的目录中组织的源代码构建软件。Wokspace中的源文件以包的嵌套层次结构进行组织,其中每个包都是包含一组相关源文件和一个BUILD文件的目录。BUILD文件指定可以从源构建哪些软件输出。
workspace是你的文件系统,它包含了要构建的软件,以及符号链接到包含生成输出目录中的源文件的目录。每个worksapce目录都有一个名为的文本文件WORKSPACE
,该文件可能为空,或者可能包含对构建输出所需的外部依赖项( https://docs.bazel.build/versions/master/external.html)引用。
以下为小米公司移动开源框架MACE 源码根目录下的WORKSPACE。https://github.com/XiaoMi/mace
workspace(name = "mace")
# generate version and opencl kernel code.
load("//repository/git:git_configure.bzl", "git_version_repository")
load("//repository/opencl-kernel:opencl_kernel_configure.bzl", "encrypt_opencl_kernel_repository")
git_version_repository(name = "local_version_config")
encrypt_opencl_kernel_repository(name = "local_opencl_kernel_encrypt")
# proto_library rules implicitly depend on @com_google_protobuf//:protoc,
# which is the proto-compiler.
# This statement defines the @com_google_protobuf repo.
http_archive(
name = "com_google_protobuf",
sha256 = "d7a221b3d4fb4f05b7473795ccea9e05dab3b8721f6286a95fffbffc2d926f8b",
strip_prefix = "protobuf-3.6.1",
urls = [
"https://cnbj1.fds.api.xiaomi.com/mace/third-party/protobuf/protobuf-3.6.1.zip",
"https://github.com/google/protobuf/archive/v3.6.1.zip",
],
)
new_http_archive(
name = "gtest",
build_file = "third_party/googletest/googletest.BUILD",
sha256 = "f3ed3b58511efd272eb074a3a6d6fb79d7c2e6a0e374323d1e6bcbcc1ef141bf",
strip_prefix = "googletest-release-1.8.0",
urls = [
"https://cnbj1.fds.api.xiaomi.com/mace/third-party/googletest/googletest-release-1.8.0.zip",
"https://github.com/google/googletest/archive/release-1.8.0.zip",
],
)
new_http_archive(
name = "opencl_headers",
build_file = "third_party/opencl-headers/opencl-headers.BUILD",
sha256 = "b2b813dd88a7c39eb396afc153070f8f262504a7f956505b2049e223cfc2229b",
strip_prefix = "OpenCL-Headers-f039db6764d52388658ef15c30b2237bbda49803",
urls = [
"https://cnbj1.fds.api.xiaomi.com/mace/third-party/OpenCL-Headers/f039db6764d52388658ef15c30b2237bbda49803.zip",
"https://github.com/KhronosGroup/OpenCL-Headers/archive/f039db6764d52388658ef15c30b2237bbda49803.zip",
],
)
new_http_archive(
name = "opencl_clhpp",
build_file = "third_party/opencl-clhpp/opencl-clhpp.BUILD",
sha256 = "dab6f1834ec6e3843438cc0f97d63817902aadd04566418c1fcc7fb78987d4e7",
strip_prefix = "OpenCL-CLHPP-4c6f7d56271727e37fb19a9b47649dd175df2b12",
urls = [
"https://cnbj1.fds.api.xiaomi.com/mace/third-party/OpenCL-CLHPP/OpenCL-CLHPP-4c6f7d56271727e37fb19a9b47649dd175df2b12.zip",
"https://github.com/KhronosGroup/OpenCL-CLHPP/archive/4c6f7d56271727e37fb19a9b47649dd175df2b12.zip",
],
)
new_http_archive(
name = "half",
build_file = "third_party/half/half.BUILD",
sha256 = "0f514a1e877932b21dc5edc26a148ddc700b6af2facfed4c030ca72f74d0219e",
strip_prefix = "half-code-356-trunk",
urls = [
"https://cnbj1.fds.api.xiaomi.com/mace/third-party/half/half-code-356-trunk.zip",
"https://sourceforge.net/code-snapshots/svn/h/ha/half/code/half-code-356-trunk.zip",
],
)
new_http_archive(
name = "eigen",
build_file = "third_party/eigen3/eigen.BUILD",
sha256 = "ca7beac153d4059c02c8fc59816c82d54ea47fe58365e8aded4082ded0b820c4",
strip_prefix = "eigen-eigen-f3a22f35b044",
urls = [
"http://cnbj1.fds.api.xiaomi.com/mace/third-party/eigen/f3a22f35b044.tar.gz",
"http://mirror.bazel.build/bitbucket.org/eigen/eigen/get/f3a22f35b044.tar.gz",
"https://bitbucket.org/eigen/eigen/get/f3a22f35b044.tar.gz",
],
)
http_archive(
name = "gemmlowp",
sha256 = "4e9cd60f7871ae9e06dcea5fec1a98ddf1006b32a85883480273e663f143f303",
strip_prefix = "gemmlowp-master-66fb41a7cafd2034a50e0b32791359897d657f7a",
urls = [
"https://cnbj1.fds.api.xiaomi.com/mace/third-party/gemmlowp/gemmlowp-master-66fb41a7cafd2034a50e0b32791359897d657f7a.zip",
],
)
http_archive(
name = "tflite",
sha256 = "c886d46ad8c91fcafed2d910ad9e7bc5aeb29856c387bdf9b6b4903cc16e6e60",
strip_prefix = "tensorflow-mace-ffc8cc7e8c9d1894753509e88b17e251bc6255e3",
urls = [
"https://cnbj1.fds.api.xiaomi.com/mace/third-party/tflite/tensorflow-mace-ffc8cc7e8c9d1894753509e88b17e251bc6255e3.zip",
],
)
new_http_archive(
name = "six_archive",
build_file = "third_party/six/six.BUILD",
sha256 = "105f8d68616f8248e24bf0e9372ef04d3cc10104f1980f54d57b2ce73a5ad56a",
strip_prefix = "six-1.10.0",
urls = [
"https://cnbj1.fds.api.xiaomi.com/mace/third-party/six/six-1.10.0.tar.gz",
"http://mirror.bazel.build/pypi.python.org/packages/source/s/six/six-1.10.0.tar.gz",
"https://pypi.python.org/packages/source/s/six/six-1.10.0.tar.gz",
],
)
bind(
name = "six",
actual = "@six_archive//:six",
)
http_archive(
# v2.2.0 + fix of include path
name = "com_github_gflags_gflags",
sha256 = "16903f6bb63c00689eee3bf7fb4b8f242934f6c839ce3afc5690f71b712187f9",
strip_prefix = "gflags-30dbc81fb5ffdc98ea9b14b1918bfe4e8779b26e",
urls = [
"https://cnbj1.fds.api.xiaomi.com/mace/third-party/gflags/gflags-30dbc81fb5ffdc98ea9b14b1918bfe4e8779b26e.zip",
"https://github.com/gflags/gflags/archive/30dbc81fb5ffdc98ea9b14b1918bfe4e8779b26e.zip",
],
)
bind(
name = "gflags",
actual = "@com_github_gflags_gflags//:gflags",
)
bind(
name = "gflags_nothreads",
actual = "@com_github_gflags_gflags//:gflags_nothreads",
)
# Set up Android NDK
android_ndk_repository(
name = "androidndk",
# Android 5.0
api_level = 21,
)
# Set up default cross compilers for arm linux
new_http_archive(
name = "gcc_linaro_7_3_1_arm_linux_gnueabihf",
build_file = "third_party/compilers/arm_compiler.BUILD",
sha256 = "7248bf105d0d468887a9b8a7120bb281ac8ad0223d9cb3d00dc7c2d498485d91",
strip_prefix = "gcc-linaro-7.3.1-2018.05-x86_64_arm-linux-gnueabihf",
urls = [
"https://cnbj1.fds.api.xiaomi.com/mace/third-party/gcc-linaro/gcc-linaro-7.3.1-2018.05-x86_64_arm-linux-gnueabihf.tar.xz",
"https://releases.linaro.org/components/toolchain/binaries/latest/arm-linux-gnueabihf/gcc-linaro-7.3.1-2018.05-x86_64_arm-linux-gnueabihf.tar.xz",
],
)
new_http_archive(
name = "gcc_linaro_7_3_1_aarch64_linux_gnu",
build_file = "third_party/compilers/aarch64_compiler.BUILD",
sha256 = "73eed74e593e2267504efbcf3678918bb22409ab7afa3dc7c135d2c6790c2345",
strip_prefix = "gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu",
urls = [
"https://cnbj1.fds.api.xiaomi.com/mace/third-party/gcc-linaro/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu.tar.xz",
"https://releases.linaro.org/components/toolchain/binaries/latest/aarch64-linux-gnu/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu.tar.xz",
],
)
如上所示,语法类似Python,进行了多个方法调用,我们来看各个方法调用的含义。
http_archive:下载bazel文件,然后解压它,这个bazel 目录文件中必须包含BUILD文件。上面的http_archive中指明了要下载io_bazel_rules_closure文件,以及它的下载地址
new_http_archive: 下载文件,然后解压它,然后和其中包含的build_file一起创建bazel目录
load:从.bzl文件中加载一些内容
android_ndk_repository:构建Android app时使用,指定Android ndk目录
workspace中代码组织的主要单元是package。一个workspace工作区下可以包括多个包package,每个package可以实现一个子模块,从而让各个模块进行解耦。package是相关文件的集合,以及它们之间的依赖关系的规范。package被定义为包含名为BUILD
或BUILD.bazel的文件的目录,该文件位于workspace中的顶层目录下。包中包含其目录中的所有文件,以及其下的所有子目录,除了那些本身包含BUILD文件的子目录。BUILD文件指定package的编译构建规则。
例如,在以下目录树中有两个package:my/app
,和子包my/app/tests
。请注意,my/app/data
它不是包,而是属于包的目录my/app
。
src/my/app/BUILD
src/my/app/app.cc
src/my/app/data/input.txt
src/my/app/tests/BUILD
src/my/app/tests/test.cc
下面为MACE源码中一个BUILD文件。
# Description:
# Mace core.
#
package(
default_visibility = ["//visibility:public"],
)
licenses(["notice"]) # Apache 2.0
load(
"//mace:mace.bzl",
"if_android",
"if_hexagon_enabled",
"if_not_hexagon_enabled",
"if_openmp_enabled",
"if_neon_enabled",
"if_opencl_enabled",
"if_quantize_enabled",
)
cc_library(
name = "core",
srcs = glob(
[
"*.cc",
"runtime/cpu/*.cc",
],
exclude = [
"*_test.cc",
],
) + if_opencl_enabled(glob(
[
"runtime/opencl/*.cc",
],
)) + if_hexagon_enabled(glob([
"runtime/hexagon/*.cc",
])),
hdrs = glob([
"*.h",
"runtime/cpu/*.h",
]) + if_opencl_enabled(glob(
[
"runtime/opencl/*.h",
],
)) + if_hexagon_enabled(glob(["runtime/hexagon/*.h"])),
copts = [
"-Werror",
"-Wextra",
"-Wno-missing-field-initializers",
] + if_openmp_enabled([
"-fopenmp",
"-DMACE_ENABLE_OPENMP",
]) + if_opencl_enabled([
"-DMACE_ENABLE_OPENCL",
]) + if_quantize_enabled([
"-DMACE_ENABLE_QUANTIZE",
]) + if_hexagon_enabled([
"-DMACE_ENABLE_HEXAGON",
]) + if_neon_enabled([
"-DMACE_ENABLE_NEON",
]),
linkopts = ["-ldl"] + if_android([
"-pie",
"-lm",
]),
deps = [
"//mace/codegen:generated_version",
"//mace/proto:mace_cc",
"//mace/utils",
"@half//:half",
] + if_opencl_enabled([
":opencl_headers",
"//mace/codegen:generated_opencl",
]) + if_quantize_enabled([
"@gemmlowp",
]) + if_hexagon_enabled([
"//third_party/nnlib:libhexagon",
]),
)
cc_library(
name = "opencl_headers",
hdrs = glob([
"runtime/opencl/*.h",
]),
copts = [
"-Werror",
"-Wextra",
"-Wno-missing-field-initializers",
],
deps = [
"@opencl_clhpp",
"@opencl_headers//:opencl20_headers",
],
)
cc_library(
name = "test_benchmark_main",
testonly = 1,
srcs = [
"testing/test_benchmark.cc",
"testing/test_benchmark_main.cc",
],
hdrs = [
"testing/test_benchmark.h",
],
copts = [
"-Werror",
"-Wextra",
"-Wno-missing-field-initializers",
] + if_openmp_enabled(["-fopenmp"]) + if_opencl_enabled([
"-DMACE_ENABLE_OPENCL",
]),
deps = [
":core",
"//external:gflags_nothreads",
"//mace/ops:test",
"//mace/utils",
],
)
cc_library:库文件编译规则,name指定了编译为库文件后的文件名,srcs和hdrs指定源文件和头文件,deps指定需要依赖的其他文件
package:通用方法,定义的值会作用到下面的每个子rule中。default_visibility指定了这个包的默认可见规则。可见的情况下才能被其他package调用。
licenses:通用方法,默认的license
load:通用方法,加载.bzl文件
更多常用方法可以参看bazel文档:https://docs.bazel.build/versions/master/be/c-cpp.html#cc_binary.linkopts
包package是一个容器,组成它的元素称为目标Target。绝大部分的target属于两种基本类型中的一种,文件file和规则rule。另外还有一种其他的target类型package group,一般很少见。文件分为两种,一种为程序员写的源代码,一种为构建工具生成的文件。规则定义了如何利用输入来构建得到输出,如上面的BUILD。输入一般是源文件,库文件等,输出则一般是生成的构建目标文件。
Bazel编译C++项目:https://blog.csdn.net/elaine_bao/article/details/78668657