Bazel

参考:

官网: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

1、概述

        Bazel是一个类似于Make,Maven和Gradle的开源构建和测试工具。Bazel支持多种语言的项目,并为多个平台构建输出。Bazel支持跨多个存储库和大量用户的大型代码库。

具有高级构建语言、快速可靠、多平台、扩展性强、规模大等优点。

1.1 使用bazel步骤

要使用Bazel构建或测试项目,通常需要执行以下操作:

  1. 设置Bazel。下载并安装Bazel。https://docs.bazel.build/versions/master/install.html。

  2. 建立项目工作区Workspace。每个工作空间中有一个WORKSPACE文件,来描述工作空间所使用到的信息。

  3. 创建一个BUILD文件。每个程序包package中包含一个BUILD文件,此文件中描述了此工具包的生成构建方式。

    您使用Starlark(一种特定于域的语言 https://docs.bazel.build/versions/master/skylark/language.html)声明构建目标来编写BUILD文件 。(见例子  https://github.com/bazelbuild/bazel/blob/master/examples/cpp/BUILD )

  4. 运行Bazel。Bazel将输出放在工作区内。

除了构建之外,您还可以使用Bazel运行 测试并查询构建以跟踪代码中的依赖项。

1.2 Bazel运作原理

运行构建或测试时,Bazel执行以下操作:

  1. 加载与目标相关的BUILD文件

  2. 分析输入及其 依赖关系,应用指定的构建规则,并生成操作 图。

  3. 对输入执行构建操作,直到生成最终构建输出。

由于所有以前的构建工作都是缓存的,因此Bazel可以识别并重用缓存的工件,只重建或重新测试更改的内容。

2、Bazel项目结构

        和Makefile一样,使用bazel编译也必须满足它的项目结构要求。这也许是为什么bazel还不够普及的原因所在吧。bazel顶层,也就是根目录下为工作区workspace,workspace下包含多个package,每个package又包含多个编译目标target。

        Bazel根据在称为workspace的目录中组织的源代码构建软件。Wokspace中的源文件以包的嵌套层次结构进行组织,其中每个包都是包含一组相关源文件和一个BUILD文件的目录。BUILD文件指定可以从源构建哪些软件输出。

2.1  工作区workspace

         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目录

2.2 包package

       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

2.3 目标Target

        包package是一个容器,组成它的元素称为目标Target。绝大部分的target属于两种基本类型中的一种,文件file和规则rule。另外还有一种其他的target类型package group,一般很少见。文件分为两种,一种为程序员写的源代码,一种为构建工具生成的文件。规则定义了如何利用输入来构建得到输出,如上面的BUILD。输入一般是源文件,库文件等,输出则一般是生成的构建目标文件。

Bazel_第1张图片

 

 

Bazel编译C++项目:https://blog.csdn.net/elaine_bao/article/details/78668657

你可能感兴趣的:(C++编程)