aboutsummaryrefslogtreecommitdiffhomepage
path: root/docs/getting-started.md
blob: a7420e69431edb2295f9f42ffa17fecc163cdda3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
Getting Started with Bazel
==========================

Setup
-----

Every Bazel project is contained in a directory called a _build root_,
which holds the inputs, outputs, and build rules for the project. To create a
Bazel project, first clone the [Github repo](https://github.com/google/bazel)
and build Bazel (follow the instructions in the
[README](https://github.com/google/bazel/README.md) to install prerequisites):

```bash
$ git clone https://github.com/google/bazel.git
$ cd bazel
$ ./compile.sh
```

`./compile.sh` populates the _base_workspace_ subdirectory
with the tools Bazel needs to do builds.

Suppose that you have an existing project in a directory, say,
_~/gitroot/my-project/_. Recursively copy _base_workspace/_ and
all of its contents to wherever you'd like your build root and then move
_my-project/_ to be a subdirectory of _base_workspace/_:

```bash
$ cp -R ~/gitroot/bazel/base_workspace ~/gitroot
$ mv ~/gitroot/my-project ~/gitroot/base_workspace
```

At this point, you should have the following directory structure:

```
base_workspace/
  examples/
  my-project/
  tools/
  WORKSPACE
```

You can rename _base_workspace/_ to something more descriptive, if you prefer.

Sanity Check: Building an Example
---------------------------------

To make sure everything is set up correctly in your build root, build one of the
examples from the _examples/_ directory.

```bash
$ cd ~/gitroot/base_workspace
$ bazel build examples/java:hello-world
Extracting Blaze installation...
...........
INFO: Found 1 target...
Target //examples/java:hello-world up-to-date:
  bazel-bin/examples/java/hello-world.jar
  bazel-bin/examples/java/hello-world
INFO: Elapsed time: 3.040s, Critical Path: 1.14s
$ bazel-bin/examples/java/hello-world
Hello world
```

Bazel puts binaries it has built under _bazel-bin/_.  Note that you can
always look at the `build` command's output to find output file paths.

Writing Your Own Build Rules
----------------------------

Now you can start adding your own build rules. This example assumes that
_my-project/_ is a Java project.  See the
[build encyclopedia](https://github.com/google/bazel/blob/master/docs/historical/build-encyclopedia.html)
for advice on writing rules for other languages.

Note that when we ran "bazel build" above, the third argument started with a
filesystem path ("examples/java"), followed by a colon. When you run
`bazel build examples/java:hello-world`, Bazel will look for a
special file named BUILD in the _examples/java/_ subdirectory.  This
BUILD file defines rules about how Bazel should build things in this
subdirectory.

Thus, to add build rules to my-project, add a BUILD file in the
_my-project/_ directory.  Add the following lines to this BUILD file:

```python
# ~/gitroot/base_workspace/my-project/BUILD
java_binary(
    name = "my-runner",
    srcs = glob(["**/*.java"]),
    main_class = "com.example.ProjectRunner",
)
```

BUILD files are Python-like scripts. BUILD files cannot contain arbitrary
Python, but each build rule looks like a Python function call and you can use
"#" to start a single-line comment.

`java_binary` is the type of thing this rule will build.
`name` is how you'll refer to the rule when you run "bazel build"
(in the "examples/java:hello-world" build above the `name` was
"hello-world"). `srcs` lists the Java source files Bazel should
compile into a Java binary.  `glob(["**/*.java"])` is a handy
shorthand for "recursively include every file that ends with .java" (see the
[user manual](https://github.com/google/bazel/blob/master/docs/historical/bazel-user-manual.html)
for more information about globbing). Replace `com.example.ProjectRunner` with
the class that contains the main method.

If you have no actual Java project you're using, you can use the following
commands to make a fake project for this example:

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

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

public class Greeting {
    public static void sayHi() {
        System.out.println("Hi!");
    }
}
EOF
```

Now build your project:

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

Congratulations, you've written your first Bazel rule!

Adding Dependencies
-------------------

Creating one rule to build your entire project may be sufficient for small
projects, but as projects get larger it's important to break up the build into
self-contained libraries that can be assembled into a final product.  This way
the entire world doesn't need to be rebuilt on small changes and Bazel can
parallelize more of the build steps.

To break up a project, create separate rules for each subcomponent and then
make them depend on each other. For the example above, add the following rules
to the _my-project/BUILD_ file:

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

java_library(
    name = "greeter",
    srcs = ["java/com/example/Greeting.java"],
)
```

Now you can build and run `my-project:my-other-runner`:

```bash
$ bazel run my-project:my-other-runner
INFO: Found 1 target...
Target //my-project:my-other-runner up-to-date:
  bazel-bin/my-project/my-other-runner.jar
  bazel-bin/my-project/my-other-runner
INFO: Elapsed time: 2.454s, Critical Path: 1.58s

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

If you edit _ProjectRunner.java_ and rebuild `my-other-runner`, only
_ProjectRunner.java_ needs to be rebuilt (<code>greeter</code> is unchanged).

Using Multiple Packages
-----------------------

For larger projects, you will often be dealing with several directories. You
can refer to targets defined in other BUILD files using the syntax
`//package-name:target-name`.  For example, suppose
_my-project/java/com/example/_ has a _cmdline/_ subdirectory with the following
file:

```bash
$ mkdir my-project/java/com/example/cmdline
$ cat > my-project/java/com/example/cmdline/Runner.java &lt;&lt;EOF
package com.example.cmdline;

import com.example.Greeting;

public class Runner {
    public static void main(String args[]) {
        Greeting.sayHi();
    }
}
EOF
```

We could add a BUILD file at _my-project/java/com/example/cmdline/BUILD_
that contained the following rule:

```python
# ~/gitroot/base_workspace/my-project/java/com/example/cmdline/BUILD
java_binary(
    name = "runner",
    srcs = ["Runner.java"],
    main_class = "com.example.cmdline.Runner",
    deps = ["//my-project:greeter"]
)
```

However, by default, build rules are _private_. This means that they can only be
referred to by rules in the same BUILD file. This prevents libraries that are
implementation details from leaking into public APIs, but it also means that you
must explicitly allow `runner` to depend on `my-project:greeter`. As is, if we
build `runner` we'll get a permissions error:

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

You can make a rule visibile to rules in other BUILD files by adding a
`visibility = level` attribute.  Change the `greeter` rule in
_my-project/BUILD_ to be visible to our new rule:

```python
java_library(
    name = "greeter",
    srcs = ["java/com/example/Greeting.java"],
    visibility = ["//my-project/java/com/example/cmdline:__pkg__"],
)
```

This makes `//my-project:greeter` visible to any rule in the
`//my-project/java/com/example/cmdline` package. Now we can build and
run the binary:

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

INFO: Running command line: bazel-bin/my-project/java/com/example/cmdline/runner
Hi!
```

See the [build encyclopedia](https://github.com/google/bazel/blob/master/docs/historical/build-encyclopedia.html) for more visibility options.

Deploying
---------

If you look at the contents of
_bazel-bin/my-project/java/com/example/cmdline/runner.jar_, you can see that it
only contains `Runner.class`, not its dependencies (`Greeting.class`):

```bash
$ jar tf bazel-bin/my-project/java/com/example/cmdline/runner.jar
META-INF/
META-INF/MANIFEST.MF
com/
com/example/
com/example/cmdline/
com/example/cmdline/Runner.class
```

To deploy a `runner` binary, we need a self-contained jar. To build this, build
runner_deploy.jar (or, more generally, _&lt;target-name&gt;_deploy.jar_):

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

`runner_deploy.jar` will contain all of its dependencies.

Next Steps
----------

You can now create your own targets and compose them.  See the [build
encyclopedia](https://github.com/google/bazel/blob/master/docs/historical/build-encyclopedia.html)
and Bazel
[user manual](https://github.com/google/bazel/blob/master/docs/historical/bazel-user-manual.html)
for more information.
[Let us know](https://groups.google.com/forum/#!forum/bazel-discuss)
if you have any questions!