构建工具Bazel入门
Bazel入门
安装
安装过程请参考: http://bazel.io/docs/install.html
使用工作区(workspace)
所有的Bazel构建都是基于一个 工作区(workspace) 概念,它是文件系统中一个保存了全部源代码的目录,同时还将包含一些构建后的输出目录的符号链接(例如:bazel-bin
和 bazel-out
等输出目录)。工作区目录可以随意放在哪里,但是工作区的根目录必须包含一个名为 WORKSPACE
的工作区配置文件。工作区配置文件可以是一个空文件,也可以包含引用外部构建输出所需的 依赖关系。
在一个工作区内,可以根据需要共享多个项目。为了简单,我们先从只有一个项目的工作区开始介绍。
先假设你已经有了一个项目,对应 ~/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",
)
BUILD文件采用类似Python的语法。虽然不能包含任意的Python语法,但是BUILD文件中的每个构建规则看起来都象是一个Python函数调用,而且你也可以用 "#"
开头来添加单行注释。
java_binary
是一个构建规则。其中 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
文件因为没有变化而不会重现编译。
使用多个包(Packages)
对于更大的项目,我们通常需要将它们拆分到多个目录中。你可以用类似//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
目标(类似<target-name>_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
中将包含全部的依赖。
下一步
现在,您可以创建自己的目标并组装最终产品了。接下来,可查看 相关教程 分别学习如何用Bazel构建一个服务器、Android和iOS应用。也可以参考 构建百科 和 用户手册获得更多的信息。如果有问题的话,可以到 bazel-discuss 论坛提问。
构建工具Bazel入门的更多相关文章
- Google软件构建工具Bazel原理及使用方法介绍
近期,Google开源了强大的自动化构建工具Bazel. 正好博主近期在使用china版的Bazel--腾讯自主开发的Blade,所以准备跟大家分享一下Google Bazel这个分布式构建系统的原理 ...
- Google软件构建工具Bazel FAQ
Google软件构建工具Bazel FAQ 本文是我的翻译,原文在这里.欢迎转载,转载请注名本文作者和原始链接 注:如果想了解Bazel的原理,可以看看我之前翻译的Google Blaze原理及使用方 ...
- (转)前端构建工具gulp入门教程
前端构建工具gulp入门教程 老婆婆 1.8k 2013年12月30日 发布 推荐 10 推荐 收藏 83 收藏,20k 浏览 本文假设你之前没有用过任何任务脚本(task runner)和命令行工具 ...
- Google软件构建工具Bazel
转载Google软件构建工具Bazel FAQ 本文是我的翻译,原文在这里.欢迎转载,转载请注名本文作者和原始链接注:如果想了解Bazel的原理,可以看看我之前翻译的Google Blaze原理及使用 ...
- 前端构建工具 Grunt 入门
之前也介绍过前端构建工具 Ant 和 Yeoman,其中 Yeoman 工具就包含了 Grunt 所以就不多说.那么与 Ant 相比 Grunt 有这么几个优点: Javascript 语法,相比 A ...
- gulp前端自动化构建工具新手入门篇
很久没有更新博文了. 经过了一次年前吐血的赶项目,终于在年后回血了.趁着有空,新学到了一个前端自动化构建工具-gulp. 现在我们通过这3个问题来学习一下: 1.什么是gulp? 2.为什么要用gul ...
- 前端项目自动化构建工具——Webpack入门教程
参考资料:https://www.webpackjs.com/(中文文档) https://www.webpackjs.com/(官方文档) 首先有必要说明一下,本文侧重讲解webpack基本配置 ...
- 前端构建工具gulp入门教程(share)
参考自:http://segmentfault.com/a/1190000000372547 资源: npm上得gulp组件 gulp的Github主页 官方package.json文档 gulp中文 ...
- 前端自动构建工具@gulp入门
gulp是一个自动化的前端工具.它可以利用自身的插件来实现一些功能,如sass.less编译:浏览器自动刷新,文件压缩.重命名.代码校验(个人使用sublime的插件进行校验)等功能.当然这些功能也可 ...
随机推荐
- js 当前时间和对比时间的比较
<!DOCTYPE><html> <head> <meta charset="utf-8" /> <title>功能:当 ...
- FTP Active & Passive
在主动模式下,FTP客户端随机开启一个大于1024的端口N向服务器的21号端口发起连接,然后开放N+1号端口进行监听,并向服务器发出PORT N+1命令.服务器接收到命令后,会用其本地的F ...
- 为什么程序员都不喜欢使用switch,而是大量的 if……else if ?
作者:熊爸爸 原文:http://3g.163.com/tech/article/E02RDE6C0511SDDL.html 请用5秒钟的时间查看下面的代码是否存在bug. OK,熟练的程序猿应该已经 ...
- service sshd start启动失败,Badly formatted port number.
在做xhell学习的时候,把端口号修改了,后面忘记修改回 来,导致 [root@MyRoth 桌面]# service sshd start 正在启动 sshd:/etc/ssh/sshd_confi ...
- 关于Unity中脚本
脚本编译: Unity可以把脚本编译为DLL,DLL将在运行时编译运行.这样可以提高执行 的速度,比传统的JavaScritp快20倍. 脚本具体的编译需要以下4步. 1: 所有的"Stan ...
- C语言进阶学习第二章
本章重点记录指针的各种概念: 1.地址与内容 2.非法的赋值 3.NULL指针:NULL指针作为一个特殊的指针变量,表示不指向任何东西,在对指针进行解引用操作之前,首先必须 确保它并非NULL指针. ...
- 2 _ 基本框架 _ 检测VMX环境
VT 是先开为大,谁先开谁上层,谁上层 谁权限大. 1 判断是否支持 VMX intel 白皮书 第3卷 传入 参数eax =1, 返回值 ecx 的第5位 = 1 则 surpported VMX. ...
- python spark环境配置
在配置Hadoop之前,应该先做以下配置 1.更改主机名 首先更改主机名,目的是为了方便管理. 输入:hostname 查看本机的名称 使用 hostname 修改当前主 ...
- [转]async & await 的前世今生(Updated)
async 和 await 出现在C# 5.0之后,给并行编程带来了不少的方便,特别是当在MVC中的Action也变成async之后,有点开始什么都是async的味道了.但是这也给我们编程埋下了一些隐 ...
- JOIN方法也是连贯操作方法之一
JOIN方法也是连贯操作方法之一,用于根据两个或多个表中的列之间的关系,从这些表中查询数据. 大理石平台规格 join通常有下面几种类型,不同类型的join操作会影响返回的数据结果. INNER JO ...