blob: 6b6ff5bc4f88c923bbc5e74e3605a63f1ef7b557 [file] [log] [blame] [view]
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001Getting Started with Bazel
2==========================
3
4Setup
5-----
6
7Every Bazel project is contained in a directory called a _build root_,
8which holds the inputs, outputs, and build rules for the project. To create a
9Bazel project, first clone the [Github repo](https://github.com/google/bazel)
10and build Bazel (follow the instructions in the
Han-Wen Nienhuys0be7e442015-03-13 19:29:16 +000011[README](install.md) to install prerequisites):
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010012
13```bash
14$ git clone https://github.com/google/bazel.git
15$ cd bazel
16$ ./compile.sh
17```
18
19`./compile.sh` populates the _base_workspace_ subdirectory
20with the tools Bazel needs to do builds.
21
22Suppose that you have an existing project in a directory, say,
23_~/gitroot/my-project/_. Recursively copy _base_workspace/_ and
24all of its contents to wherever you'd like your build root and then move
25_my-project/_ to be a subdirectory of _base_workspace/_:
26
27```bash
28$ cp -R ~/gitroot/bazel/base_workspace ~/gitroot
29$ mv ~/gitroot/my-project ~/gitroot/base_workspace
30```
31
32At this point, you should have the following directory structure:
33
34```
35base_workspace/
36 examples/
37 my-project/
38 tools/
39 WORKSPACE
40```
41
42You can rename _base_workspace/_ to something more descriptive, if you prefer.
43
44Sanity Check: Building an Example
45---------------------------------
46
47To make sure everything is set up correctly in your build root, build one of the
48examples from the _examples/_ directory.
49
50```bash
51$ cd ~/gitroot/base_workspace
52$ bazel build examples/java:hello-world
Kristina Chodorow3e6bd722015-03-19 14:30:24 +000053Extracting Bazel installation...
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010054...........
55INFO: Found 1 target...
56Target //examples/java:hello-world up-to-date:
57 bazel-bin/examples/java/hello-world.jar
58 bazel-bin/examples/java/hello-world
59INFO: Elapsed time: 3.040s, Critical Path: 1.14s
60$ bazel-bin/examples/java/hello-world
61Hello world
62```
63
64Bazel puts binaries it has built under _bazel-bin/_. Note that you can
65always look at the `build` command's output to find output file paths.
66
Googler3a21f002015-03-18 21:52:07 +000067Creating Your Own Build File
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010068----------------------------
69
Googler3a21f002015-03-18 21:52:07 +000070Now you can create your own BUILD file and start adding build rules. This example assumes that
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010071_my-project/_ is a Java project. See the
Han-Wen Nienhuys361af112015-03-17 13:00:09 +000072[build encyclopedia](build-encyclopedia.html)
Googler3a21f002015-03-18 21:52:07 +000073for advice on adding build rules for other languages.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010074
75Note that when we ran "bazel build" above, the third argument started with a
76filesystem path ("examples/java"), followed by a colon. When you run
77`bazel build examples/java:hello-world`, Bazel will look for a
78special file named BUILD in the _examples/java/_ subdirectory. This
79BUILD file defines rules about how Bazel should build things in this
80subdirectory.
81
Googler3a21f002015-03-18 21:52:07 +000082Thus, to add build rules to my-project, create a file named `BUILD` in the
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010083_my-project/_ directory. Add the following lines to this BUILD file:
84
85```python
86# ~/gitroot/base_workspace/my-project/BUILD
87java_binary(
88 name = "my-runner",
89 srcs = glob(["**/*.java"]),
90 main_class = "com.example.ProjectRunner",
91)
92```
93
94BUILD files are Python-like scripts. BUILD files cannot contain arbitrary
95Python, but each build rule looks like a Python function call and you can use
96"#" to start a single-line comment.
97
98`java_binary` is the type of thing this rule will build.
99`name` is how you'll refer to the rule when you run "bazel build"
100(in the "examples/java:hello-world" build above the `name` was
101"hello-world"). `srcs` lists the Java source files Bazel should
102compile into a Java binary. `glob(["**/*.java"])` is a handy
103shorthand for "recursively include every file that ends with .java" (see the
Han-Wen Nienhuys361af112015-03-17 13:00:09 +0000104[user manual](bazel-user-manual.html)
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100105for more information about globbing). Replace `com.example.ProjectRunner` with
106the class that contains the main method.
107
108If you have no actual Java project you're using, you can use the following
109commands to make a fake project for this example:
110
111```bash
112$ # If you're not already there, move to your build root directory.
113$ cd ~/gitroot/base_workspace
114$ mkdir -p my-project/java/com/example
Ross Lighte7dd23c2015-03-19 16:37:19 +0000115$ cat > my-project/java/com/example/ProjectRunner.java <<EOF
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100116package com.example;
117
118public class ProjectRunner {
119 public static void main(String args[]) {
120 Greeting.sayHi();
121 }
122}
123EOF
Ross Lighte7dd23c2015-03-19 16:37:19 +0000124$ cat > my-project/java/com/example/Greeting.java <<EOF
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100125package com.example;
126
127public class Greeting {
128 public static void sayHi() {
129 System.out.println("Hi!");
130 }
131}
132EOF
133```
134
135Now build your project:
136
137```bash
138$ bazel build my-project:my-runner
139INFO: Found 1 target...
140Target //my-project:my-runner up-to-date:
141 bazel-bin/my-project/my-runner.jar
142 bazel-bin/my-project/my-runner
143INFO: Elapsed time: 1.021s, Critical Path: 0.83s
144$ bazel-bin/my-project/my-runner
145Hi!
146```
147
Googler3a21f002015-03-18 21:52:07 +0000148Congratulations, you've created your first Bazel BUILD file!
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100149
150Adding Dependencies
151-------------------
152
153Creating one rule to build your entire project may be sufficient for small
154projects, but as projects get larger it's important to break up the build into
155self-contained libraries that can be assembled into a final product. This way
156the entire world doesn't need to be rebuilt on small changes and Bazel can
157parallelize more of the build steps.
158
159To break up a project, create separate rules for each subcomponent and then
160make them depend on each other. For the example above, add the following rules
161to the _my-project/BUILD_ file:
162
163```python
164java_binary(
165 name = "my-other-runner",
166 srcs = ["java/com/example/ProjectRunner.java"],
167 main_class = "com.example.ProjectRunner",
168 deps = [":greeter"],
169)
170
171java_library(
172 name = "greeter",
173 srcs = ["java/com/example/Greeting.java"],
174)
175```
176
177Now you can build and run `my-project:my-other-runner`:
178
179```bash
180$ bazel run my-project:my-other-runner
181INFO: Found 1 target...
182Target //my-project:my-other-runner up-to-date:
183 bazel-bin/my-project/my-other-runner.jar
184 bazel-bin/my-project/my-other-runner
185INFO: Elapsed time: 2.454s, Critical Path: 1.58s
186
187INFO: Running command line: bazel-bin/my-project/my-other-runner
188Hi!
Googler3a21f002015-03-18 21:52:07 +0000189```
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100190
191If you edit _ProjectRunner.java_ and rebuild `my-other-runner`, only
192_ProjectRunner.java_ needs to be rebuilt (<code>greeter</code> is unchanged).
193
194Using Multiple Packages
195-----------------------
196
197For larger projects, you will often be dealing with several directories. You
198can refer to targets defined in other BUILD files using the syntax
199`//package-name:target-name`. For example, suppose
200_my-project/java/com/example/_ has a _cmdline/_ subdirectory with the following
201file:
202
203```bash
204$ mkdir my-project/java/com/example/cmdline
Ross Lighte7dd23c2015-03-19 16:37:19 +0000205$ cat > my-project/java/com/example/cmdline/Runner.java <<EOF
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100206package com.example.cmdline;
207
208import com.example.Greeting;
209
210public class Runner {
211 public static void main(String args[]) {
212 Greeting.sayHi();
213 }
214}
215EOF
216```
217
218We could add a BUILD file at _my-project/java/com/example/cmdline/BUILD_
219that contained the following rule:
220
221```python
222# ~/gitroot/base_workspace/my-project/java/com/example/cmdline/BUILD
223java_binary(
224 name = "runner",
225 srcs = ["Runner.java"],
226 main_class = "com.example.cmdline.Runner",
227 deps = ["//my-project:greeter"]
228)
229```
230
231However, by default, build rules are _private_. This means that they can only be
232referred to by rules in the same BUILD file. This prevents libraries that are
233implementation details from leaking into public APIs, but it also means that you
234must explicitly allow `runner` to depend on `my-project:greeter`. As is, if we
235build `runner` we'll get a permissions error:
236
237```bash
238$ bazel build my-project/java/com/example/cmdline:runner
239ERROR: /usr/local/google/home/kchodorow/gitroot/base_workspace/my-project/java/com/example/cmdline/BUILD:2:1:
240 Target '//my-project:greeter' is not visible from target '//my-project/java/com/example/cmdline:runner'.
241 Check the visibility declaration of the former target if you think the dependency is legitimate.
242ERROR: Analysis of target '//my-project/java/com/example/cmdline:runner' failed; build aborted.
243INFO: Elapsed time: 0.091s
244```
245
246You can make a rule visibile to rules in other BUILD files by adding a
247`visibility = level` attribute. Change the `greeter` rule in
248_my-project/BUILD_ to be visible to our new rule:
249
250```python
251java_library(
252 name = "greeter",
253 srcs = ["java/com/example/Greeting.java"],
254 visibility = ["//my-project/java/com/example/cmdline:__pkg__"],
255)
256```
257
258This makes `//my-project:greeter` visible to any rule in the
259`//my-project/java/com/example/cmdline` package. Now we can build and
260run the binary:
261
262```bash
263$ bazel run my-project/java/com/example/cmdline:runner
264INFO: Found 1 target...
265Target //my-project/java/com/example/cmdline:runner up-to-date:
266 bazel-bin/my-project/java/com/example/cmdline/runner.jar
267 bazel-bin/my-project/java/com/example/cmdline/runner
268INFO: Elapsed time: 1.576s, Critical Path: 0.81s
269
270INFO: Running command line: bazel-bin/my-project/java/com/example/cmdline/runner
271Hi!
272```
273
Han-Wen Nienhuys361af112015-03-17 13:00:09 +0000274See the [build encyclopedia](build-encyclopedia.html) for more visibility options.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100275
276Deploying
277---------
278
279If you look at the contents of
280_bazel-bin/my-project/java/com/example/cmdline/runner.jar_, you can see that it
281only contains `Runner.class`, not its dependencies (`Greeting.class`):
282
283```bash
284$ jar tf bazel-bin/my-project/java/com/example/cmdline/runner.jar
285META-INF/
286META-INF/MANIFEST.MF
287com/
288com/example/
289com/example/cmdline/
290com/example/cmdline/Runner.class
291```
292
293To deploy a `runner` binary, we need a self-contained jar. To build this, build
294runner_deploy.jar (or, more generally, _&lt;target-name&gt;_deploy.jar_):
295
296```bash
297$ bazel build my-project/java/com/example/cmdline:runner_deploy.jar
298INFO: Found 1 target...
299Target //my-project/java/com/example/cmdline:runner_deploy.jar up-to-date:
300 bazel-bin/my-project/java/com/example/cmdline/runner_deploy.jar
301INFO: Elapsed time: 1.700s, Critical Path: 0.23s
302```
303
304`runner_deploy.jar` will contain all of its dependencies.
305
306Next Steps
307----------
308
309You can now create your own targets and compose them. See the [build
Han-Wen Nienhuys361af112015-03-17 13:00:09 +0000310encyclopedia](build-encyclopedia.html)
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100311and Bazel
Han-Wen Nienhuys361af112015-03-17 13:00:09 +0000312[user manual](bazel-user-manual.html)
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100313for more information.
314[Let us know](https://groups.google.com/forum/#!forum/bazel-discuss)
315if you have any questions!