Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 1 | Getting Started with Bazel |
| 2 | ========================== |
| 3 | |
| 4 | Setup |
| 5 | ----- |
| 6 | |
| 7 | Every Bazel project is contained in a directory called a _build root_, |
| 8 | which holds the inputs, outputs, and build rules for the project. To create a |
| 9 | Bazel project, first clone the [Github repo](https://github.com/google/bazel) |
| 10 | and build Bazel (follow the instructions in the |
Han-Wen Nienhuys | 0be7e44 | 2015-03-13 19:29:16 +0000 | [diff] [blame] | 11 | [README](install.md) to install prerequisites): |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 12 | |
| 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 |
| 20 | with the tools Bazel needs to do builds. |
| 21 | |
| 22 | Suppose that you have an existing project in a directory, say, |
| 23 | _~/gitroot/my-project/_. Recursively copy _base_workspace/_ and |
| 24 | all 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 | |
| 32 | At this point, you should have the following directory structure: |
| 33 | |
| 34 | ``` |
| 35 | base_workspace/ |
| 36 | examples/ |
| 37 | my-project/ |
| 38 | tools/ |
| 39 | WORKSPACE |
| 40 | ``` |
| 41 | |
| 42 | You can rename _base_workspace/_ to something more descriptive, if you prefer. |
| 43 | |
| 44 | Sanity Check: Building an Example |
| 45 | --------------------------------- |
| 46 | |
| 47 | To make sure everything is set up correctly in your build root, build one of the |
| 48 | examples from the _examples/_ directory. |
| 49 | |
| 50 | ```bash |
| 51 | $ cd ~/gitroot/base_workspace |
| 52 | $ bazel build examples/java:hello-world |
Kristina Chodorow | 3e6bd72 | 2015-03-19 14:30:24 +0000 | [diff] [blame] | 53 | Extracting Bazel installation... |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 54 | ........... |
| 55 | INFO: Found 1 target... |
| 56 | Target //examples/java:hello-world up-to-date: |
| 57 | bazel-bin/examples/java/hello-world.jar |
| 58 | bazel-bin/examples/java/hello-world |
| 59 | INFO: Elapsed time: 3.040s, Critical Path: 1.14s |
| 60 | $ bazel-bin/examples/java/hello-world |
| 61 | Hello world |
| 62 | ``` |
| 63 | |
| 64 | Bazel puts binaries it has built under _bazel-bin/_. Note that you can |
| 65 | always look at the `build` command's output to find output file paths. |
| 66 | |
Googler | 3a21f00 | 2015-03-18 21:52:07 +0000 | [diff] [blame] | 67 | Creating Your Own Build File |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 68 | ---------------------------- |
| 69 | |
Googler | 3a21f00 | 2015-03-18 21:52:07 +0000 | [diff] [blame] | 70 | Now you can create your own BUILD file and start adding build rules. This example assumes that |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 71 | _my-project/_ is a Java project. See the |
Han-Wen Nienhuys | 361af11 | 2015-03-17 13:00:09 +0000 | [diff] [blame] | 72 | [build encyclopedia](build-encyclopedia.html) |
Googler | 3a21f00 | 2015-03-18 21:52:07 +0000 | [diff] [blame] | 73 | for advice on adding build rules for other languages. |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 74 | |
| 75 | Note that when we ran "bazel build" above, the third argument started with a |
| 76 | filesystem path ("examples/java"), followed by a colon. When you run |
| 77 | `bazel build examples/java:hello-world`, Bazel will look for a |
| 78 | special file named BUILD in the _examples/java/_ subdirectory. This |
| 79 | BUILD file defines rules about how Bazel should build things in this |
| 80 | subdirectory. |
| 81 | |
Googler | 3a21f00 | 2015-03-18 21:52:07 +0000 | [diff] [blame] | 82 | Thus, to add build rules to my-project, create a file named `BUILD` in the |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 83 | _my-project/_ directory. Add the following lines to this BUILD file: |
| 84 | |
| 85 | ```python |
| 86 | # ~/gitroot/base_workspace/my-project/BUILD |
| 87 | java_binary( |
| 88 | name = "my-runner", |
| 89 | srcs = glob(["**/*.java"]), |
| 90 | main_class = "com.example.ProjectRunner", |
| 91 | ) |
| 92 | ``` |
| 93 | |
| 94 | BUILD files are Python-like scripts. BUILD files cannot contain arbitrary |
| 95 | Python, 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 |
| 102 | compile into a Java binary. `glob(["**/*.java"])` is a handy |
| 103 | shorthand for "recursively include every file that ends with .java" (see the |
Han-Wen Nienhuys | 361af11 | 2015-03-17 13:00:09 +0000 | [diff] [blame] | 104 | [user manual](bazel-user-manual.html) |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 105 | for more information about globbing). Replace `com.example.ProjectRunner` with |
| 106 | the class that contains the main method. |
| 107 | |
| 108 | If you have no actual Java project you're using, you can use the following |
| 109 | commands 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 Light | e7dd23c | 2015-03-19 16:37:19 +0000 | [diff] [blame] | 115 | $ cat > my-project/java/com/example/ProjectRunner.java <<EOF |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 116 | package com.example; |
| 117 | |
| 118 | public class ProjectRunner { |
| 119 | public static void main(String args[]) { |
| 120 | Greeting.sayHi(); |
| 121 | } |
| 122 | } |
| 123 | EOF |
Ross Light | e7dd23c | 2015-03-19 16:37:19 +0000 | [diff] [blame] | 124 | $ cat > my-project/java/com/example/Greeting.java <<EOF |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 125 | package com.example; |
| 126 | |
| 127 | public class Greeting { |
| 128 | public static void sayHi() { |
| 129 | System.out.println("Hi!"); |
| 130 | } |
| 131 | } |
| 132 | EOF |
| 133 | ``` |
| 134 | |
| 135 | Now build your project: |
| 136 | |
| 137 | ```bash |
| 138 | $ bazel build my-project:my-runner |
| 139 | INFO: Found 1 target... |
| 140 | Target //my-project:my-runner up-to-date: |
| 141 | bazel-bin/my-project/my-runner.jar |
| 142 | bazel-bin/my-project/my-runner |
| 143 | INFO: Elapsed time: 1.021s, Critical Path: 0.83s |
| 144 | $ bazel-bin/my-project/my-runner |
| 145 | Hi! |
| 146 | ``` |
| 147 | |
Googler | 3a21f00 | 2015-03-18 21:52:07 +0000 | [diff] [blame] | 148 | Congratulations, you've created your first Bazel BUILD file! |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 149 | |
| 150 | Adding Dependencies |
| 151 | ------------------- |
| 152 | |
| 153 | Creating one rule to build your entire project may be sufficient for small |
| 154 | projects, but as projects get larger it's important to break up the build into |
| 155 | self-contained libraries that can be assembled into a final product. This way |
| 156 | the entire world doesn't need to be rebuilt on small changes and Bazel can |
| 157 | parallelize more of the build steps. |
| 158 | |
| 159 | To break up a project, create separate rules for each subcomponent and then |
| 160 | make them depend on each other. For the example above, add the following rules |
| 161 | to the _my-project/BUILD_ file: |
| 162 | |
| 163 | ```python |
| 164 | java_binary( |
| 165 | name = "my-other-runner", |
| 166 | srcs = ["java/com/example/ProjectRunner.java"], |
| 167 | main_class = "com.example.ProjectRunner", |
| 168 | deps = [":greeter"], |
| 169 | ) |
| 170 | |
| 171 | java_library( |
| 172 | name = "greeter", |
| 173 | srcs = ["java/com/example/Greeting.java"], |
| 174 | ) |
| 175 | ``` |
| 176 | |
| 177 | Now you can build and run `my-project:my-other-runner`: |
| 178 | |
| 179 | ```bash |
| 180 | $ bazel run my-project:my-other-runner |
| 181 | INFO: Found 1 target... |
| 182 | Target //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 |
| 185 | INFO: Elapsed time: 2.454s, Critical Path: 1.58s |
| 186 | |
| 187 | INFO: Running command line: bazel-bin/my-project/my-other-runner |
| 188 | Hi! |
Googler | 3a21f00 | 2015-03-18 21:52:07 +0000 | [diff] [blame] | 189 | ``` |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 190 | |
| 191 | If you edit _ProjectRunner.java_ and rebuild `my-other-runner`, only |
| 192 | _ProjectRunner.java_ needs to be rebuilt (<code>greeter</code> is unchanged). |
| 193 | |
| 194 | Using Multiple Packages |
| 195 | ----------------------- |
| 196 | |
| 197 | For larger projects, you will often be dealing with several directories. You |
| 198 | can 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 |
| 201 | file: |
| 202 | |
| 203 | ```bash |
| 204 | $ mkdir my-project/java/com/example/cmdline |
Ross Light | e7dd23c | 2015-03-19 16:37:19 +0000 | [diff] [blame] | 205 | $ cat > my-project/java/com/example/cmdline/Runner.java <<EOF |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 206 | package com.example.cmdline; |
| 207 | |
| 208 | import com.example.Greeting; |
| 209 | |
| 210 | public class Runner { |
| 211 | public static void main(String args[]) { |
| 212 | Greeting.sayHi(); |
| 213 | } |
| 214 | } |
| 215 | EOF |
| 216 | ``` |
| 217 | |
| 218 | We could add a BUILD file at _my-project/java/com/example/cmdline/BUILD_ |
| 219 | that contained the following rule: |
| 220 | |
| 221 | ```python |
| 222 | # ~/gitroot/base_workspace/my-project/java/com/example/cmdline/BUILD |
| 223 | java_binary( |
| 224 | name = "runner", |
| 225 | srcs = ["Runner.java"], |
| 226 | main_class = "com.example.cmdline.Runner", |
| 227 | deps = ["//my-project:greeter"] |
| 228 | ) |
| 229 | ``` |
| 230 | |
| 231 | However, by default, build rules are _private_. This means that they can only be |
| 232 | referred to by rules in the same BUILD file. This prevents libraries that are |
| 233 | implementation details from leaking into public APIs, but it also means that you |
| 234 | must explicitly allow `runner` to depend on `my-project:greeter`. As is, if we |
| 235 | build `runner` we'll get a permissions error: |
| 236 | |
| 237 | ```bash |
| 238 | $ bazel build my-project/java/com/example/cmdline:runner |
| 239 | ERROR: /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. |
| 242 | ERROR: Analysis of target '//my-project/java/com/example/cmdline:runner' failed; build aborted. |
| 243 | INFO: Elapsed time: 0.091s |
| 244 | ``` |
| 245 | |
| 246 | You 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 |
| 251 | java_library( |
| 252 | name = "greeter", |
| 253 | srcs = ["java/com/example/Greeting.java"], |
| 254 | visibility = ["//my-project/java/com/example/cmdline:__pkg__"], |
| 255 | ) |
| 256 | ``` |
| 257 | |
| 258 | This makes `//my-project:greeter` visible to any rule in the |
| 259 | `//my-project/java/com/example/cmdline` package. Now we can build and |
| 260 | run the binary: |
| 261 | |
| 262 | ```bash |
| 263 | $ bazel run my-project/java/com/example/cmdline:runner |
| 264 | INFO: Found 1 target... |
| 265 | Target //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 |
| 268 | INFO: Elapsed time: 1.576s, Critical Path: 0.81s |
| 269 | |
| 270 | INFO: Running command line: bazel-bin/my-project/java/com/example/cmdline/runner |
| 271 | Hi! |
| 272 | ``` |
| 273 | |
Han-Wen Nienhuys | 361af11 | 2015-03-17 13:00:09 +0000 | [diff] [blame] | 274 | See the [build encyclopedia](build-encyclopedia.html) for more visibility options. |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 275 | |
| 276 | Deploying |
| 277 | --------- |
| 278 | |
| 279 | If you look at the contents of |
| 280 | _bazel-bin/my-project/java/com/example/cmdline/runner.jar_, you can see that it |
| 281 | only contains `Runner.class`, not its dependencies (`Greeting.class`): |
| 282 | |
| 283 | ```bash |
| 284 | $ jar tf bazel-bin/my-project/java/com/example/cmdline/runner.jar |
| 285 | META-INF/ |
| 286 | META-INF/MANIFEST.MF |
| 287 | com/ |
| 288 | com/example/ |
| 289 | com/example/cmdline/ |
| 290 | com/example/cmdline/Runner.class |
| 291 | ``` |
| 292 | |
| 293 | To deploy a `runner` binary, we need a self-contained jar. To build this, build |
| 294 | runner_deploy.jar (or, more generally, _<target-name>_deploy.jar_): |
| 295 | |
| 296 | ```bash |
| 297 | $ bazel build my-project/java/com/example/cmdline:runner_deploy.jar |
| 298 | INFO: Found 1 target... |
| 299 | Target //my-project/java/com/example/cmdline:runner_deploy.jar up-to-date: |
| 300 | bazel-bin/my-project/java/com/example/cmdline/runner_deploy.jar |
| 301 | INFO: Elapsed time: 1.700s, Critical Path: 0.23s |
| 302 | ``` |
| 303 | |
| 304 | `runner_deploy.jar` will contain all of its dependencies. |
| 305 | |
| 306 | Next Steps |
| 307 | ---------- |
| 308 | |
| 309 | You can now create your own targets and compose them. See the [build |
Han-Wen Nienhuys | 361af11 | 2015-03-17 13:00:09 +0000 | [diff] [blame] | 310 | encyclopedia](build-encyclopedia.html) |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 311 | and Bazel |
Han-Wen Nienhuys | 361af11 | 2015-03-17 13:00:09 +0000 | [diff] [blame] | 312 | [user manual](bazel-user-manual.html) |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 313 | for more information. |
| 314 | [Let us know](https://groups.google.com/forum/#!forum/bazel-discuss) |
| 315 | if you have any questions! |