Bazel教程

*使用工作区* 
Bazel builds应该在一个工作区内运行,这个工作区应该包括源代码和build输出目录的符号链接(eg: bazel-bin、bazel-out)。工作区目录的位置是可以随意,但工作区的根目录必须包含一个名为WORKSPACE的工作区配置文件,工作区配置文件可以是一个空文件,也可以包含引用外部构建输出所需的依赖关系。在一个工作区内,可以根据需求共享多个项目。

  $ touch WORKSPACE

*创建Build文件* 
Bazel通过检查BUIDL文件可以知道那些目标文件被创建在项目中,这些BUILD文件采用与Python相似的语法所写,这种语言通常是一系列规则的声明,每个规则指定相应的输入、输出以及实现输入到输出的方法。

为了进一步了解bazel的使用,在这里分别以Java和C++进行介绍。

Java教程 
假设目录中已经有了一个项目,对应 ~/gitroot/my-project/ 目录,先创建一个空的 ~/gitroot/my-project/WORKSPACE 工作区配置文件,用于表示这是Bazel项目对应的根目录。 
*创建自己的Build构建文件* 
使用下面的命令创建一个简单的Java项目:

$ # If you're not already there, move to your workspace directory.
$ cd ~/gitroot/my-project
$ mkdir -p src/main/java/com/example
$ cat > src/main/java/com/example/ProjectRunner.java <<'EOF'
package com.example;

public class ProjectRunner {
    public static void main(String args[]) {
        Greeting.sayHi();
    }
}
EOF
$ cat > src/main/java/com/example/Greeting.java <<'EOF'
package com.example;

public class Greeting {
    public static void sayHi() {
        System.out.println("Hi!");
    }
}
EOF
  • Bazel通过工作区中所有名为 BUILD 的文件来解析需要构建项目的信息,因此,需要先在 ~/gitroot/my-project 目录创建一个 BUILD 构建文件。下面是BUILD构建文件的内容:
# ~/gitroot/my-project/BUILD
java_binary(
    name = "my-runner",
    srcs = glob(["**/*.java"]),
    main_class = "com.example.ProjectRunner",
)

java_binary 是一个构建规则,其中 glob([“*/.java”])表示递归包含每个子目录中以每个.java为后缀名的文件,. 
其中 name 对应一个构建目标的标识符,可用用它来向Bazel指定构建哪个项目。srcs 对应一个源文件列表,Bazel需要将这些源文件编译为二进制文件。其中 glob([“*/.java”]) 表示递归包含每个子目录中以每个 .java 为后缀名的文件。com.example.ProjectRunner 指定包含main方法的类。 
现在用下面的命令构建这个Java程序了:

$ cd ~/gitroot/my-project
$ bazel build //:my-runner
INFO: Found 1 target...
Target //:my-runner up-to-date:
  bazel-bin/my-runner.jar
  bazel-bin/my-runner
INFO: Elapsed time: 1.021s, Critical Path: 0.83s
$ bazel-bin/my-runner
Hi!

恭喜你刚刚成功构建了第一个Bazel项目了! 
*添加依赖关系* 
对于一个小项目,创建一个规则就可以了,但随着项目的变大,则需要分别构建项目的不同部件,最终再组装成产品。这种构建方式能避免因为局部细小的改变而重构整个应用,同时不同的构建步骤可以很好地并发执行以提高构建的效率。 
现在将一个项目拆分不同的部件独立构建,同时设置他们之间的依赖关系。基于上面的例子,重写BUILD构建文件:

java_binary(
    name = "my-other-runner",
    srcs = ["src/main/java/com/example/ProjectRunner.java"],
    main_class = "com.example.ProjectRunner",
    deps = [":greeter"],
)

java_library(
    name = "greeter",
    srcs = ["src/main/java/com/example/Greeting.java"],
)
  • 尽管源文件一样,但是现在Bazel将采用不同的方式来构建:首先构建 greeter 库,然后构建 my-other-runner。在构建成功后运行 //:my-other-runner:
$ bazel run //:my-other-runner
INFO: Found 1 target...
Target //:my-other-runner up-to-date:
  bazel-bin/my-other-runner.jar
  bazel-bin/my-other-runner
INFO: Elapsed time: 2.454s, Critical Path: 1.58s

INFO: Running command line: bazel-bin/my-other-runner
Hi!

现在如果修改ProjectRunner.java代码并重新构建my-other-runner,Greeting.java文件将不会重重新被编译。 
*使用多个包* 
对于大的项目 
For larger projects, you will often be dealing with several directories. You can refer to targets defined in other BUILD files using the syntax //path/to/directory:target-name. For example, suppose src/main/java/com/example/ has a cmdline/ subdirectory with the following file:

对于更大的项目,通常需要将它们拆分到多个目录中。可以用类似//path/to/directory:target-name的名字引用在其他BUILD文件定义的目标。例如,假设src/main/java/com/example/有一个cmdline/子目录,包含下面的文件:

$ mkdir -p src/main/java/com/example/cmdline
$ cat > src/main/java/com/example/cmdline/Runner.java <<'EOF'
package com.example.cmdline;

import com.example.Greeting;

public class Runner {
    public static void main(String args[]) {
        Greeting.sayHi();
    }
}
EOF
  • Runner.java依赖com.example.Greeting,因此需要在src/main/java/com/example/cmdline/BUILD构建文件中添加相应的依赖规则:
# ~/gitroot/my-project/src/main/java/com/example/cmdline/BUILD
java_binary(
    name = "runner",
    srcs = ["Runner.java"],
    main_class = "com.example.cmdline.Runner",
    deps = ["//:greeter"]
)

然而,在默认情况下构建目标都是私有的。也就是说,只能在同一个BUILD文件中被引用,这可以避免将很多实现的细节暴漏给公共的接口,但是也意味着我们需要手工允许runner所依赖的//:greeter目标。类似下面这个在构建runner目标时遇到的错误:

$ bazel build //src/main/java/com/example/cmdline:runner
ERROR: /home/user/gitroot/my-project/src/main/java/com/example/cmdline/BUILD:2:1:
  Target '//:greeter' is not visible from target '//src/main/java/com/example/cmdline:runner'.
  Check the visibility declaration of the former target if you think the dependency is legitimate.
ERROR: Analysis of target '//src/main/java/com/example/cmdline:runner' failed; build aborted.
INFO: Elapsed time: 0.091s

可用通过在BUILD文件增加visibility = level属性来改变目标的可见范围。下面是通过在~/gitroot/my-project/BUILD文件增加可见规则,来改变greeter目标的可见范围:

java_library(
    name = "greeter",
    srcs = ["src/main/java/com/example/Greeting.java"],
    visibility = ["//src/main/java/com/example/cmdline:__pkg__"],
)

这个规则使//:greeter目标对于//src/main/java/com/example/cmdline包是可见的。现在可以重新构建运行runner目标程序:

$ bazel run //src/main/java/com/example/cmdline:runner
INFO: Found 1 target...
Target //src/main/java/com/example/cmdline:runner up-to-date:
  bazel-bin/src/main/java/com/example/cmdline/runner.jar
  bazel-bin/src/main/java/com/example/cmdline/runner
INFO: Elapsed time: 1.576s, Critical Path: 0.81s

INFO: Running command line: bazel-bin/src/main/java/com/example/cmdline/runner
Hi!

可见性配置说明请参考文档。 
*部署* 
如果查看 bazel-bin/src/main/java/com/example/cmdline/runner.jar 的内容,可以看到只包含了Runner.class,并没有保护所依赖的Greeting.class:

$ jar tf bazel-bin/src/main/java/com/example/cmdline/runner.jar
META-INF/
META-INF/MANIFEST.MF
com/
com/example/
com/example/cmdline/
com/example/cmdline/Runner.class

这只能在本机正常工作(Bazel的runner脚本已经将greeter的jar添加到了classpath),但是如果将runner.jar单独复制到另一台机器上是不能正常运行。为了构建可用于部署发布的自包含所有依赖的目标,可以构建runner_deploy.jar目标(类似_deploy.jar以_deploy为后缀的名字对应可部署目标)。

$ bazel build //src/main/java/com/example/cmdline:runner_deploy.jar
INFO: Found 1 target...
Target //src/main/java/com/example/cmdline:runner_deploy.jar up-to-date:
  bazel-bin/src/main/java/com/example/cmdline/runner_deploy.jar
INFO: Elapsed time: 1.700s, Critical Path: 0.23s

runner_deploy.jar中将包含全部的依赖。

你可能感兴趣的:(编译)