构建工具:bazel

目录

目录结构

workspace 工作空间

Repositories 代码仓库

Packages 包

Targets 目标

Labels(标签)

Rules(规则)

BUILD files(BUILD文件)

加载插件

规则分类

外部依赖

依赖外部bazel项目

依赖非bazel项目

依赖外部包

获取依赖

影子依赖

在命令行中覆盖仓库

离线构建


目录结构

一个代码库是一个目录,设为代码根目录'/',根目录下可以有多个子目录,子目录中可以继续嵌套子目录。

在根目录下要有一个workspace文件,根目录和每个代码子目录下得有BUILD文件。 这种有BUILD的文件目录称作一个包。

 

核心概念 workspace、packages、targets

一个工作空间,多个包,多个目标。

 

workspace 工作空间

工作空间就是代码根目录,目录里必须有个WORKSPACE文件。可以是空文件,或者在文件里包含一个外部依赖的信息。 根目录下同样会有一些软链接,链接到编译产物。

如果子目录中还有workspace文件,那么bazel会忽略此目录。

同时文件名可以是WORKSPACE.bazel,且优先级高很多。

 

 

Repositories 代码仓库

代码以多个仓库的形式组织。包含WORKSPACE文件的目录是主仓库根目录,也叫@。其他外部仓库是按一定规则定义在WORKSPACE文件中。

WORKSPACE规则:

外部范仓库有自己的WORKSPACE文件,这都被bazel忽略。

 

 

Packages 包

包是代码仓库里组织代码的基本单元。 包是一些相关文件的集合加上一些特定的依赖规则。包是在workspace目录下的一个包含有BUILD或者BUILD.bazel的子目录。

 

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

my/app和my/app/tests是包。my/app/data不是包,是my/app包的子目录。

 

 

Targets 目标

包是容器,其中的元素叫目标。目标分为三类:files(文件),rules(规则), package groups(包组)。

files(文件)进一步分为Source files(源文件)和derived files(派生文件)。源文件是人写的,派生文件是构建工具根据源文件和特定规则生成的。

rules(规则)指定了一组输入文件和输出文件之间的关系,包括必要的步骤。规则的输出只能是生成的文件,但是规则的输出既可以是源文件,也能是生成的文件。这就导致一个规则的输出成为另一个规则的输入,并允许构建成规则链。

规则的输入是源文件还是派生文件根本不重要,重要的是文件内容。对于一些复杂的文件,可以用规则生成,也不影响依赖此文件的其他规则。

规则的输入也可能包含其他规则。具体的关系可能很复杂,且和语言和规则相关。比如一个c++的库A的规则可能依赖另一个c++库B的规则 作为输入。这种依赖达到的效果是在编译器B的头文件对A可用;链接期B的符号对A可用;运行期B的数据对A可用。

不变的是所有规则产生的文件只属于规则自己所在的包,不可能给其他包产生文件。一个规则的输入来自其他的包的情况也不常见。

 

Package Groups是一组包的集合,目的是用来限制可访问范围。用package_group 函数来定义。有两个属性,一个是一系列的包名,一个是自己的名字。唯一允许的引用方式是通过规则的visibility属性,或者package 函数的default_visibility 属性。包组不产生或者依赖文件。

 

 

Labels(标签)

所有的目标属于一个包。目标的名字叫label,简洁的标签如下:

@myrepo//my/app/main:app_binary

如果标签是指向的目标在自己的仓库,就可能省略@myrepo,写成

//my/app/main:app_binary

每个标签由两部分构成,包名(/my/app/main)和目标名(app_binary)。一个标签唯一确定一个目标。冒号后边的名称也能省略,省略后目标名就和包名的最后一部分相同。如下两个标签是等价的。

//my/app

//my/app:app

标签总是以//开头,包名从不以//开头。因此,my/app是一个包,他包含//my/app这个标签。

在BUIL文件中,包名和冒号都可以被省略。因此,包my/app中的BUILD文件,//my/app:BUILD中的标签可以如下:

//my/app:app

//my/app

:app

app

此包下的文件的标签也能简写为:

generate.cc

testdata/input.txt

但是其他包里,或者命令里,这些目标都要写全名://my/app:genereate.cc.相对标签不能用在其他包里,也不能用相对标签表示子包中的标签。

以@//开头的标签代表着主仓库,即使在外部仓库中这么写。因此在外部仓库中@//a/b/c和//a/b/c是不同的。前者代表主仓库,后者代表外部仓库自己。所以在主仓库中写规则的时候要注意,此主仓库将来会不会作为另一个仓库的外部仓库使用。

 

 

Rules(规则)

规则指定了输入和输出之间的关系和构建输出的步骤。规则有很多种,能编译生成可执行文件和库,测试用的可执行文件。

规则有一个name(名字),可以任意指定,但是最好指定为生成文件的名字。名字在*_binary和*_test规则中就是可执行文件的名字。

 

cc_binary(

    name = "my_app",

    srcs = ["my_app.cc"],

    deps = [

        "//absl/base",

        "//absl/strings",

    ],

)

 

每个规则有一组属性。上述srcs就是规则cc_binary的属性名,属性值是一个由任意个源文件标签构成的的列表。deps也是属性名,值是一个标签列表。srcs和outs最终形成以目标为结点的有向无环图,称为目标图或者目标依赖图。

 

 

BUILD files(BUILD文件)

上文对包,目标,标签,构建依赖图进行了抽象的描述,这一节我们看一下定义一个包的具体语法。

每个包有一个BUILD文件,内容是一个简单的程序。 是用命令式的语言Starlark写成的。被解析为一系列有序的语句。通常来说顺序不重要,但是变量必须要使用前定义。大多数情况下只用关心声明了哪些规则,当规则执行完成时生产了哪些值。例如cc_library这个规则执行后会在目标图中生成一个新的目标,这个目标后续就能用标签来引用了。为了鼓励代码和数据清晰分离,BUILD文件中不能用函数定义。

 

加载插件

load("//foo/bar:file.bzl", "some_library")

load("//foo/bar:file.bzl", library_alias = "some_library")

load(":my_rules.bzl", "some_rule", nice_alias = "some_other_rule")

 

规则分类

*_binary

*_test

*_library

 

外部依赖

在WORKSPACE文件里添加如下代码。

 

依赖外部bazel项目

 local_repository, git_repository or http_archive 

 

local_repository(

    name = "coworkers_project",

    path = "/path/to/coworkers-project",

)

 

依赖非bazel项目

需要给这个项目写个BUILD文件,这样就能在BUILD文件中用了:@coworkers_project//:some-lib

 

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"],

)

 

 

依赖外部包

主要用于Maven,rules_jvm_external .

 

 

获取依赖

bazel build时会获取。此外bazel fetch, bazel sync也能获取。

 

 

影子依赖

myproject/WORKSPACE

workspace(name = "myproject")

 

local_repository(

    name = "A",

    path = "../A",

)

local_repository(

    name = "B",

    path = "../B",

)

A/WORKSPACE

workspace(name = "A")

 

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

http_archive(

    name = "testrunner",

    urls = ["https://github.com/testrunner/v1.zip"],

    sha256 = "...",

)

B/WORKSPACE

workspace(name = "B")

 

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

http_archive(

    name = "testrunner",

    urls = ["https://github.com/testrunner/v2.zip"],

    sha256 = "..."

)

Both dependencies A and B depend on testrunner, but they depend on different versions of testrunner. There is no reason for these test runners to not peacefully coexist within myproject, however they will clash with each other since they have the same name. To declare both dependencies, update myproject/WORKSPACE:

workspace(name = "myproject")

 

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

http_archive(

    name = "testrunner-v1",

    urls = ["https://github.com/testrunner/v1.zip"],

    sha256 = "..."

)

http_archive(

    name = "testrunner-v2",

    urls = ["https://github.com/testrunner/v2.zip"],

    sha256 = "..."

)

local_repository(

    name = "A",

    path = "../A",

    repo_mapping = {"@testrunner" : "@testrunner-v1"}

)

local_repository(

    name = "B",

    path = "../B",

    repo_mapping = {"@testrunner" : "@testrunner-v2"}

)

 

在命令行中覆盖仓库

覆盖@foo

--override_repository=foo=/path/to/local/foo

 

离线构建

 --nofetch

 

本文翻译自官网:

https://docs.bazel.build/versions/4.1.0/build-ref.html

https://docs.bazel.build/versions/4.1.0/external.html#shadowing-dependencies

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值