--- layout: documentation title: Introduction to Bazel --- Introduction to Bazel: Build Java ========== This tutorial is an introduction for anyone getting started with Bazel. It focuses on the concepts, setup, and use of Bazel using a Java sample project. Estimated time: 30 min ## What you will learn In this tutorial you'll learn how to: * Build a target from source files * Produce a visual representation of the dependency graph * Break a monolithic binary into smaller libraries * Use multiple Bazel packages * Control the visibility of a target between packages * Use labels to reference a target * Deploy your target ## Before you begin * [Install Bazel](/docs/install.md) ## Create the sample Java project The first step in this tutorial is to create a small Java project. Even though the project is in Java, this tutorial will focus on concepts that are helpful for using Bazel in any language. 1. Create the directory `~/my-project/` 2. Move to this directory: ``` cd ~/my-project ``` 3. Create the following directories under `my-project`: ``` mkdir -p src/main/java/com/example ``` Note that path uses conventions specific to Java programs. Programs written in other languages may have a different workspace path and directory structure. 4. In the directory you created, add a file called `Greeting.java` with the following contents: ```java package com.example; public class Greeting { public static void sayHi() { System.out.println("Hi!"); } } ``` 5. Add a second file `ProjectRunner.java` with the following contents: ```java package com.example; public class ProjectRunner { public static void main(String args[]) { Greeting.sayHi(); } } ``` You’ve now created a small Java project. It contains one file that will be compiled into a library, and another which will be an executable that uses the library. The rest of this tutorial focuses on setting up and using Bazel to build these source files. ## Build with Bazel ### Set up the workspace Workspaces are directories that contain the source files for one or more software projects, as well as a WORKSPACE file and BUILD files that contain the instructions that Bazel uses to build the software. The workspace may also contain symbolic links to output directories. To define the workspace, create an empty text file at the root of the project and name it `WORKSPACE`. You now have: `~/my-project/WORKSPACE`. This directory and its subdirectories are now part of the same workspace. When Bazel builds an output, all inputs and dependencies must be in the same workspace. Anything in different workspaces are independent of each other, though there are ways to link workspaces that are beyond the scope of this introduction tutorial. If you also do the [C++ tutorial](/docs/tutorial/cpp.md), you’ll notice it uses the same workspace. Bazel can understand multiple targets in multiple languages in a single workspace. ### Create a BUILD file Bazel looks for files named `BUILD` which describe how to build the project. 1. In the `~/my-project` directory, create a file and name it BUILD. This BUILD file is a sibling of the WORKSPACE file. In the BUILD file, you use a declarative language similar to Python to create instances of Bazel rules. These instances are called *rule targets*. In Bazel, *targets* are either files or rule targets and they are the elements in a workspace that you can ask Bazel to build. For this project, you’ll use the built-in rule `java_binary`. Bazel's built-in rules are all documented in the [Build Encyclopedia](/docs/be/overview.html). You can also create your own rules using the [Bazel rule extension framework](/docs/skylark/concepts.md). 2. Add this text to the BUILD file: ``` java_binary( name = "my-runner", srcs = glob(["src/main/java/com/example/*.java"]), main_class = "com.example.ProjectRunner", ) ``` As you can see, the text in the BUILD file doesn’t describe what Bazel does when it executes this rule target. The rule’s implementation handles the complexity of how it works (such as the compiler used). You can treat the rule as a black box, focusing on what inputs it needs, and the outputs it produces. This rule builds a Java archive ("jar file") as well as a wrapper shell script with the same name as the rule target. When you’re writing your own BUILD file, go to the [Build Encyclopedia](/docs/be/overview.html) for a description of what a rule does and for its list of possible attributes you can define. For example, here’s the entry for the [java_binary](/docs/be/java.html#java_binary) rule in the Build Encyclopedia. The Build Encyclopedia has information about all of the rules that are compiled into Bazel. Let’s take a look at the rule target that you added to the BUILD file. Each rule instantiation in the BUILD file creates one rule target. Here, you’ve instantiated the rule `java_binary`, creating the target `my-runner`. Different rules will require different attributes, though all must include a “name” attribute. You use these attributes to explicitly list all of the target’s dependencies and options. In the target above: * `my-runner` is the name of the rule target created * `glob(["src/main/java/com/example/*.java"])` includes every file in that directory that ends with .java (see the Build Encyclopedia for more information about [globbing](/docs/be/functions.html#glob)) * `"com.example.ProjectRunner"` specifies the class that contains the main method. ### Build with Bazel Now you’re ready to build the Java binary. To do so, you’ll use the command `bazel build` with the target label `//:my-runner`. You reference targets by using their label. Label syntax is described later in this tutorial. 1. Build my-runner by using this command: ``` bazel build //:my-runner ``` You’ll see output similar to: ``` 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 ``` 2. Now execute the file by using this command: ``` bazel-bin/my-runner ``` Congratulations, you've built your first Bazel target! Let’s take a look at what you built. In `~/my-project`, Bazel created the directory `bazel-bin` as well as other directories to store information about the build. Open this directory to look at the files created during the build process. These output directories keep the outputs separate from your source tree. ### Review the dependency graph Bazel requires build dependencies to be explicitly declared in BUILD files. The build will fail if dependencies are missing, so when a build works the declared dependencies are accurate. With this explicit information about dependencies, Bazel creates a build graph and uses it to accurately perform incremental builds. Our small Java project isn’t too exciting, but let’s check out its build graph. The command `bazel query` retrieves information about the graph and the relationships between targets. Let’s use it to produce a visual representation of the build graph. 1. From the root of the workspace (`my-project`), produce a text description of the graph by using the command: ``` bazel query --noimplicit_deps 'deps(//:my-runner)' --output graph ``` 2. Then, paste the output into Graphviz ([http://www.webgraphviz.com/](http://www.webgraphviz.com/)) to see the visual representation. The graph for the target my-runner will look like this: ![Dependency graph of the target 'my-runner'](/assets/tutorial_java_01.svg) You can see that `my-runner` depends on the two source files in your Java project. You have now set up the workspace and BUILD file, and used Bazel to build your project. You have also created a visual representation of the build graph to see the structure of your build. ## Refine your Bazel build ### Add dependencies Creating one rule target to build your entire project may be sufficient for small projects. As projects get larger it's important to break up the build into self-contained libraries that can be assembled into a final product. Self-contained libraries mean that everything doesn't need to be rebuilt after small changes and that Bazel can parallelize more of the build steps. These self-contained libraries also encourages good code hygiene. To break up a project, create a separate rule target for the each subcomponent and then add the subcomponents as dependencies. For the project in this tutorial, create a rule target to compile the library, and make the executable depend on it. 1. Replace the text in the BUILD file with the text below: ``` java_binary( name = "my-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"], ) ``` The new `deps` attribute in `java_binary` tells Bazel that the `greeter` library will be needed to compile the binary. Rules for many languages support the `deps` attribute, though the exact semantics of the attribute will vary based on the language and the type of target. The rule [java_library](/docs/be/java.html#java_library) compiles sources into a .jar file. Remember to go to the [Build Encyclopedia](/docs/be/overview.html) for details about specific rules. This BUILD file builds the same files as before, but in a different way: now Bazel will first build the `greeter` library and then build `my-runner`. 2. Try building //:my-runner using the command: ``` bazel build //:my-runner ``` You’ll see output similar to: ``` INFO: Found 1 target... Target //:my-runner up-to-date: bazel-bin/my-runner.jar bazel-bin/my-runner INFO: Elapsed time: 2.454s, Critical Path: 1.58s ``` 3. Execute the file by using this command:: ``` bazel-bin/my-runner ``` If you now edit `ProjectRunner.java` and rebuild `my-runner`, the source file `Greeting.java` will not be recompiled. When the BUILD file had only the one target, both source files would be recompiled after any change. Looking at the dependency graph, you can see that `my-runner` depends on the same inputs as it did before, but the structure of the build is different. The original dependency graph for `my-runner` looked link this: ![Original dependency graph of the target 'my-runner'](/assets/tutorial_java_01.svg) The dependency graph for `my-runner` after adding a dependency looks like this: ![Dependency graph of the target 'my-runner' after adding a dependency](/assets/tutorial_java_02.svg) ### Use multiple packages For larger projects, you will often be dealing with several directories in your workspace. You can organize your build process by adding a BUILD file to the top directory of source files that you want to organize together. A directory containing a BUILD file is called a package. Note that Bazel and Java both have the concept of a package. These are unrelated to each other, though both are related to the structure of the directories. Let’s build the java project using multiple packages. 1. First, let’s make the Java project a bit more complex. 1. Add the following directory and file: ``` mkdir -p src/main/java/com/example/cmdline ``` 2. In the directory cmdline, add the file Runner.java with the following contents: ```java package com.example.cmdline; import com.example.Greeting; public class Runner { public static void main(String args[]) { Greeting.sayHi(); } } ``` Now you have a slightly larger Java project that you can organize with multiple packages. 2. In the directory `src/main/java/com/example/cmdline`, add an empty text file and name it BUILD. The structure of the Java project is now: ``` ├── BUILD ├── src │ └── main │ └── java │ └── com │ └── example │ ├── cmdline │ │ ├── BUILD │ │ └── Runner.java │ ├── Greeting.java │ └── ProjectRunner.java └── WORKSPACE ``` Each directory in the workspace can be part of only one package. The workspace now has two BUILD files, and so has two packages: 1. The directory `my-project` and its subdirectories (but not including subdirectories with their own BUILD file, such as `cmdline`), and 2. The directory `cmdline` and any subdirectories. 3. In the new BUILD file, add the following text: ``` java_binary( name = "runner", srcs = ["Runner.java"], main_class = "com.example.cmdline.Runner", deps = ["//:greeter"] ) ``` The file `Runner.java` depends on `com.example.Greeting`. In the BUILD file this dependency is shown by listing the rule target `greeter` (with the label `//:greeter`). Below is what the dependency graph for runner will look like. You can see how `//:greeter` gives the dependency on `Greeting.java`. ![Dependency graph of the target 'runner'](/assets/tutorial_java_03.svg) 4. However, if you try to build runner right now you'll get a permissions error. You can see the permission error by trying to build the target using the command: ``` bazel build //src/main/java/com/example/cmdline:runner ``` By default, rule targets are private, which means that they can only be depended on by targets in the same BUILD file. This privacy prevents libraries that are implementation details from leaking into public APIs, but it also means that you must explicitly allow `runner` to depend on `//:greeter`. 5. Make a rule target visible to rule targets in other BUILD files by adding a `visibility` attribute. To make the `greeter` rule target in `~/my-project/BUILD` visible to any rule target in the new package, add the following visibility attribute: ``` java_library( name = "greeter", srcs = ["src/main/java/com/example/Greeting.java"], visibility = ["//src/main/java/com/example/cmdline:__pkg__"], ) ``` The target `//:greeter` is now visible to any target in the `//src/main/java/com/example/cmdline` package. See the Build Encyclopedia for more [visibility options](/docs/be/common-definitions.html#common.visibility). 6. Now you can build the runner binary by using the command: ``` bazel build //src/main/java/com/example/cmdline:runner ``` You’ll see output similar to: ``` 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 ``` 7. Execute the file by using this command: ``` bazel-bin/src/main/java/com/example/cmdline/runner ``` You’ve now refined your build so that it is broken down into smaller self-contained libraries, and so that the explicit dependencies are more granular. You’ve also built the Java project using multiple packages. ## Use labels to reference targets In the BUILD files and in the command line, you have been using target labels to reference targets. The label’s syntax is: `//path/to/package:target-name`, where “`//`” is the workspace’s root, and “`:`” separates the package name and the target name. If the target is a rule target and so defined in a BUILD file, “`path/to/package`” would be the path of the BUILD file itself. “`Target-name`” would be the same as the “`name`” attribute in the target in the BUILD file. The first BUILD file you created in this tutorial is in the same directory as the WORKSPACE file. When referencing rule targets defined in that file, nothing is needed for the path to the package because the workspace root and the package root are the same directory. Here are the labels of the two targets defined in that first BUILD file: ``` //:my-runner //:greeter ``` The second BUILD file has a longer path from the workspace root to the package root. The label for the target in that BUILD file is: ``` //src/main/java/com/example/cmdline:runner ``` Target labels can be shortened in a variety of ways. Within a BUILD file, if you’re referencing a target from the same package, you can write the label starting at “`:`”. For example, the rule target `greeter` can always be written as `//:greeter`, and in the BUILD file where it’s defined, it can also be written as `:greeter`. This shortened label in a BUILD file makes it immediately clear which targets are in the current package. A rule target’s name will always be defined by its name attribute. A target’s name is a bit more complex when it’s in a directory other than the root of the package. In that case, the target’s label is: `//path/to/package:path/to/file/file_name`. ## Package a Java target for deployment To understand what you’ve built and what else can be built with Bazel, you need to understand the capabilities of the rules used in your BUILD files. Always go to the [Build Encyclopedia](/docs/be/overview.html) for this information. Let’s look at packaging a Java target for deployment, which requires you to know the capabilities of the rule `java_binary`. You’re able to run the Java binaries you created in this tutorial, but you can’t simply run it on a server, because it relies on the greeting library jar to actually run. "Packaging an artifact so it can be run reliably outside the development environment involves bundling it with all of its runtime dependencies. Let's see now what’s needed to package the binaries. The rule [java_binary](/docs/be/java.html#java_binary) produces a Java archive (“jar file”) and a wrapper shell script. The file `_deploy.jar` is suitable for deployment, but it’s only built by this rule if explicitly requested. Let’s investigate. 1. Look at the contents of the output `runner.jar` by using this command: ``` jar tf bazel-bin/src/main/java/com/example/cmdline/runner.jar ``` You’ll see output similar to: ``` META-INF/ META-INF/MANIFEST.MF com/ com/example/ com/example/cmdline/ com/example/cmdline/Runner.class ``` You can see that `runner.jar` contains `Runner.class`, but not its dependency `Greeting.class`. The `runner` script that Bazel generates adds the greeter jar to the classpath, so running this program works locally. It will not work if you want to copy `runner.jar` to another machine and use it as a standalone binary. 2. The rule `java_binary` allows you to build a self-contained binary that can be deployed. To create this binary, build `runner_deploy.jar` (or, more generally, `_deploy.jar`) by using this command: ``` bazel build //src/main/java/com/example/cmdline:runner_deploy.jar ``` You’ll see output similar to: ``` 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 ``` The file runner_deploy.jar will contain all of its dependencies, and so can be used as a standalone binary. You’ve now created a Java target that you can distribute and deploy. To do so, you had to be aware of what outputs the Bazel Java rule `java_binary` is able to produce. ## Further topics * Try the tutorial [Build C++](/docs/tutorial/cpp.md). * Try the tutorial [Build Mobile Application](/docs/tutorial/app.md).