Yun Peng | 1f63afa | 2016-06-24 18:01:03 +0000 | [diff] [blame] | 1 | --- |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 2 | layout: documentation |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 3 | title: Build Tutorial - Java |
daroberts | 223aebd | 2021-02-18 17:53:30 -0800 | [diff] [blame] | 4 | category: getting-started |
Yun Peng | 1f63afa | 2016-06-24 18:01:03 +0000 | [diff] [blame] | 5 | --- |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 6 | |
Googler | 22230e4 | 2020-12-02 15:18:28 -0800 | [diff] [blame] | 7 | # Bazel Tutorial: Build a Java Project |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 8 | |
Googler | 22230e4 | 2020-12-02 15:18:28 -0800 | [diff] [blame] | 9 | This tutorial covers the basics of building Java applications with |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 10 | Bazel. You will set up your workspace and build a simple Java project that |
| 11 | illustrates key Bazel concepts, such as targets and `BUILD` files. |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 12 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 13 | Estimated completion time: 30 minutes. |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 14 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 15 | ## What you'll learn |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 16 | |
Googler | 22230e4 | 2020-12-02 15:18:28 -0800 | [diff] [blame] | 17 | In this tutorial you learn how to: |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 18 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 19 | * Build a target |
| 20 | * Visualize the project's dependencies |
| 21 | * Split the project into multiple targets and packages |
| 22 | * Control target visibility across packages |
| 23 | * Reference targets through labels |
| 24 | * Deploy a target |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 25 | |
| 26 | ## Before you begin |
| 27 | |
Googler | 1c6a982 | 2017-08-04 19:31:14 +0200 | [diff] [blame] | 28 | ### Install Bazel |
| 29 | |
dzc | 205125b | 2017-06-26 11:01:47 +0200 | [diff] [blame] | 30 | To prepare for the tutorial, first [Install Bazel](../install.md) if |
Googler | 1c6a982 | 2017-08-04 19:31:14 +0200 | [diff] [blame] | 31 | you don't have it installed already. |
| 32 | |
Laszlo Csomor | 7574865 | 2018-07-26 07:38:14 -0700 | [diff] [blame] | 33 | ### Install the JDK |
| 34 | |
Ivo List | 2fb9f3c | 2020-12-17 10:19:09 -0800 | [diff] [blame] | 35 | 1. Install Java JDK (preferred version is 11, however versions between 8 and 15 are supported). |
Laszlo Csomor | 7574865 | 2018-07-26 07:38:14 -0700 | [diff] [blame] | 36 | |
| 37 | 2. Set the JAVA\_HOME environment variable to point to the JDK. |
| 38 | * On Linux/macOS: |
| 39 | |
| 40 | export JAVA_HOME="$(dirname $(dirname $(realpath $(which javac))))" |
| 41 | * On Windows: |
| 42 | 1. Open Control Panel. |
| 43 | 2. Go to "System and Security" > "System" > "Advanced System Settings" > "Advanced" tab > "Environment Variables..." . |
| 44 | 3. Under the "User variables" list (the one on the top), click "New...". |
| 45 | 4. In the "Variable name" field, enter `JAVA_HOME`. |
| 46 | 5. Click "Browse Directory...". |
Salty Egg | 5f17a76 | 2018-10-11 07:21:51 -0700 | [diff] [blame] | 47 | 6. Navigate to the JDK directory (for example `C:\Program Files\Java\jdk1.8.0_152`). |
Laszlo Csomor | 7574865 | 2018-07-26 07:38:14 -0700 | [diff] [blame] | 48 | 7. Click "OK" on all dialog windows. |
| 49 | |
Googler | 1c6a982 | 2017-08-04 19:31:14 +0200 | [diff] [blame] | 50 | ### Get the sample project |
| 51 | |
| 52 | Retrieve the sample project from Bazel's GitHub repository: |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 53 | |
dzc | 51dcd28 | 2017-06-14 22:52:27 +0200 | [diff] [blame] | 54 | ```sh |
Ruben Das | 32fc437 | 2019-10-28 10:35:02 -0700 | [diff] [blame] | 55 | git clone https://github.com/bazelbuild/examples |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 56 | ``` |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 57 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 58 | The sample project for this tutorial is in the `examples/java-tutorial` |
| 59 | directory and is structured as follows: |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 60 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 61 | ``` |
| 62 | java-tutorial |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 63 | ├── BUILD |
| 64 | ├── src |
| 65 | │ └── main |
| 66 | │ └── java |
| 67 | │ └── com |
| 68 | │ └── example |
| 69 | │ ├── cmdline |
| 70 | │ │ ├── BUILD |
| 71 | │ │ └── Runner.java |
| 72 | │ ├── Greeting.java |
| 73 | │ └── ProjectRunner.java |
| 74 | └── WORKSPACE |
| 75 | ``` |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 76 | |
| 77 | ## Build with Bazel |
| 78 | |
| 79 | ### Set up the workspace |
| 80 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 81 | Before you can build a project, you need to set up its workspace. A workspace is |
| 82 | a directory that holds your project's source files and Bazel's build outputs. It |
| 83 | also contains files that Bazel recognizes as special: |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 84 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 85 | * The `WORKSPACE` file, which identifies the directory and its contents as a |
| 86 | Bazel workspace and lives at the root of the project's directory structure, |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 87 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 88 | * One or more `BUILD` files, which tell Bazel how to build different parts of |
| 89 | the project. (A directory within the workspace that contains a `BUILD` file |
| 90 | is a *package*. You will learn about packages later in this tutorial.) |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 91 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 92 | To designate a directory as a Bazel workspace, create an empty file named |
| 93 | `WORKSPACE` in that directory. |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 94 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 95 | When Bazel builds the project, all inputs and dependencies must be in the same |
| 96 | workspace. Files residing in different workspaces are independent of one |
| 97 | another unless linked, which is beyond the scope of this tutorial. |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 98 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 99 | ### Understand the BUILD file |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 100 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 101 | A `BUILD` file contains several different types of instructions for Bazel. |
| 102 | The most important type is the *build rule*, which tells Bazel how to build the |
| 103 | desired outputs, such as executable binaries or libraries. Each instance |
| 104 | of a build rule in the `BUILD` file is called a *target* and points to a |
| 105 | specific set of source files and dependencies. A target can also point to other |
| 106 | targets. |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 107 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 108 | Take a look at the `java-tutorial/BUILD` file: |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 109 | |
vladmos | 4e9208a | 2020-03-11 12:16:42 -0700 | [diff] [blame] | 110 | ```python |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 111 | java_binary( |
Googler | 006659e | 2017-07-20 19:48:05 +0200 | [diff] [blame] | 112 | name = "ProjectRunner", |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 113 | srcs = glob(["src/main/java/com/example/*.java"]), |
| 114 | ) |
| 115 | ``` |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 116 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 117 | In our example, the `ProjectRunner` target instantiates Bazel's built-in |
dzc | 205125b | 2017-06-26 11:01:47 +0200 | [diff] [blame] | 118 | [`java_binary` rule](../be/java.html#java_binary). The rule tells Bazel to |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 119 | build a `.jar` file and a wrapper shell script (both named after the target). |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 120 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 121 | The attributes in the target explicitly state its dependencies and options. |
| 122 | While the `name` attribute is mandatory, many are optional. For example, in the |
| 123 | `ProjectRunner` rule target, `name` is the name of the target, `srcs` specifies |
| 124 | the source files that Bazel uses to build the target, and `main_class` specifies |
| 125 | the class that contains the main method. (You may have noticed that our example |
dzc | 205125b | 2017-06-26 11:01:47 +0200 | [diff] [blame] | 126 | uses [glob](../be/functions.html#glob) to pass a set of source files to Bazel |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 127 | instead of listing them one by one.) |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 128 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 129 | ### Build the project |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 130 | |
Googler | ec7ecd7 | 2021-03-19 16:20:52 -0700 | [diff] [blame^] | 131 | To build your sample project, navigate to the `java-tutorial` directory |
| 132 | and run: |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 133 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 134 | ``` |
Googler | 006659e | 2017-07-20 19:48:05 +0200 | [diff] [blame] | 135 | bazel build //:ProjectRunner |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 136 | ``` |
Googler | ec7ecd7 | 2021-03-19 16:20:52 -0700 | [diff] [blame^] | 137 | In the target label, the `//` part is the location of the `BUILD` file |
| 138 | relative to the root of the workspace (in this case, the root itself), |
| 139 | and `ProjectRunner` is the target name in the `BUILD` file. (You will |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 140 | learn about target labels in more detail at the end of this tutorial.) |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 141 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 142 | Bazel produces output similar to the following: |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 143 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 144 | ```bash |
Googler | 006659e | 2017-07-20 19:48:05 +0200 | [diff] [blame] | 145 | INFO: Found 1 target... |
| 146 | Target //:ProjectRunner up-to-date: |
| 147 | bazel-bin/ProjectRunner.jar |
| 148 | bazel-bin/ProjectRunner |
| 149 | INFO: Elapsed time: 1.021s, Critical Path: 0.83s |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 150 | ``` |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 151 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 152 | Congratulations, you just built your first Bazel target! Bazel places build |
| 153 | outputs in the `bazel-bin` directory at the root of the workspace. Browse |
| 154 | through its contents to get an idea for Bazel's output structure. |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 155 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 156 | Now test your freshly built binary: |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 157 | |
dzc | 51dcd28 | 2017-06-14 22:52:27 +0200 | [diff] [blame] | 158 | ```sh |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 159 | bazel-bin/ProjectRunner |
| 160 | ``` |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 161 | |
| 162 | ### Review the dependency graph |
| 163 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 164 | Bazel requires build dependencies to be explicitly declared in BUILD files. |
| 165 | Bazel uses those statements to create the project's dependency graph, which |
| 166 | enables accurate incremental builds. |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 167 | |
Googler | ec7ecd7 | 2021-03-19 16:20:52 -0700 | [diff] [blame^] | 168 | To visualize the sample project's dependencies, you can generate a text |
| 169 | representation of the dependency graph by running this command at the |
| 170 | workspace root: |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 171 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 172 | ``` |
wtroberts | 5a0cf9b | 2019-09-06 07:55:15 -0700 | [diff] [blame] | 173 | bazel query --notool_deps --noimplicit_deps "deps(//:ProjectRunner)" --output graph |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 174 | ``` |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 175 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 176 | The above command tells Bazel to look for all dependencies for the target |
| 177 | `//:ProjectRunner` (excluding host and implicit dependencies) and format the |
| 178 | output as a graph. |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 179 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 180 | Then, paste the text into [GraphViz](http://www.webgraphviz.com/). |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 181 | |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 182 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 183 | As you can see, the project has a single target that build two source files with |
| 184 | no additional dependencies: |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 185 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 186 |  |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 187 | |
Googler | ec7ecd7 | 2021-03-19 16:20:52 -0700 | [diff] [blame^] | 188 | After you set up your workspace, build your project, and examine its |
| 189 | dependencies, then you can add some complexity. |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 190 | |
| 191 | ## Refine your Bazel build |
| 192 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 193 | While a single target is sufficient for small projects, you may want to split |
| 194 | larger projects into multiple targets and packages to allow for fast incremental |
| 195 | builds (that is, only rebuild what's changed) and to speed up your builds by |
| 196 | building multiple parts of a project at once. |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 197 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 198 | ### Specify multiple build targets |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 199 | |
Googler | ec7ecd7 | 2021-03-19 16:20:52 -0700 | [diff] [blame^] | 200 | You can split the sample project build into two targets. Replace the contents of |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 201 | the `java-tutorial/BUILD` file with the following: |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 202 | |
vladmos | 4e9208a | 2020-03-11 12:16:42 -0700 | [diff] [blame] | 203 | ```python |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 204 | java_binary( |
| 205 | name = "ProjectRunner", |
| 206 | srcs = ["src/main/java/com/example/ProjectRunner.java"], |
| 207 | main_class = "com.example.ProjectRunner", |
| 208 | deps = [":greeter"], |
| 209 | ) |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 210 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 211 | java_library( |
| 212 | name = "greeter", |
| 213 | srcs = ["src/main/java/com/example/Greeting.java"], |
| 214 | ) |
| 215 | ``` |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 216 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 217 | With this configuration, Bazel first builds the `greeter` library, then the |
Passw | 473a916 | 2017-12-22 14:13:12 -0800 | [diff] [blame] | 218 | `ProjectRunner` binary. The `deps` attribute in `java_binary` tells Bazel that |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 219 | the `greeter` library is required to build the `ProjectRunner` binary. |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 220 | |
Googler | ec7ecd7 | 2021-03-19 16:20:52 -0700 | [diff] [blame^] | 221 | To build this new version of the project, run the following command: |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 222 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 223 | ``` |
| 224 | bazel build //:ProjectRunner |
| 225 | ``` |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 226 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 227 | Bazel produces output similar to the following: |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 228 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 229 | ``` |
| 230 | INFO: Found 1 target... |
| 231 | Target //:ProjectRunner up-to-date: |
| 232 | bazel-bin/ProjectRunner.jar |
| 233 | bazel-bin/ProjectRunner |
| 234 | INFO: Elapsed time: 2.454s, Critical Path: 1.58s |
| 235 | ``` |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 236 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 237 | Now test your freshly built binary: |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 238 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 239 | ``` |
| 240 | bazel-bin/ProjectRunner |
| 241 | ``` |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 242 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 243 | If you now modify `ProjectRunner.java` and rebuild the project, Bazel only |
| 244 | recompiles that file. |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 245 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 246 | Looking at the dependency graph, you can see that `ProjectRunner` depends on the |
| 247 | same inputs as it did before, but the structure of the build is different: |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 248 | |
laurentlb | 79b9431 | 2018-11-07 05:18:59 -0800 | [diff] [blame] | 249 |  |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 251 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 252 | You've now built the project with two targets. The `ProjectRunner` target builds |
| 253 | two source files and depends on one other target (`:greeter`), which builds |
| 254 | one additional source file. |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 255 | |
| 256 | ### Use multiple packages |
| 257 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 258 | Let’s now split the project into multiple packages. If you take a look at the |
| 259 | `src/main/java/com/example/cmdline` directory, you can see that it also contains |
| 260 | a `BUILD` file, plus some source files. Therefore, to Bazel, the workspace now |
| 261 | contains two packages, `//src/main/java/com/example/cmdline` and `//` (since |
| 262 | there is a `BUILD` file at the root of the workspace). |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 263 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 264 | Take a look at the `src/main/java/com/example/cmdline/BUILD` file: |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 265 | |
vladmos | 4e9208a | 2020-03-11 12:16:42 -0700 | [diff] [blame] | 266 | ```python |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 267 | java_binary( |
| 268 | name = "runner", |
| 269 | srcs = ["Runner.java"], |
| 270 | main_class = "com.example.cmdline.Runner", |
vladmos | 4e9208a | 2020-03-11 12:16:42 -0700 | [diff] [blame] | 271 | deps = ["//:greeter"], |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 272 | ) |
| 273 | ``` |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 274 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 275 | The `runner` target depends on the `greeter` target in the `//` package (hence |
| 276 | the target label `//:greeter`) - Bazel knows this through the `deps` attribute. |
| 277 | Take a look at the dependency graph: |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 278 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 279 |  |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 280 | |
Googler | ec7ecd7 | 2021-03-19 16:20:52 -0700 | [diff] [blame^] | 281 | However, for the build to succeed, you must explicitly give the `runner` target |
| 282 | in `//src/main/java/com/example/cmdline/BUILD` visibility to targets in |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 283 | `//BUILD` using the `visibility` attribute. This is because by default targets |
| 284 | are only visible to other targets in the same `BUILD` file. (Bazel uses target |
| 285 | visibility to prevent issues such as libraries containing implementation details |
| 286 | leaking into public APIs.) |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 287 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 288 | To do this, add the `visibility` attribute to the `greeter` target in |
| 289 | `java-tutorial/BUILD` as shown below: |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 290 | |
vladmos | 4e9208a | 2020-03-11 12:16:42 -0700 | [diff] [blame] | 291 | ```python |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 292 | java_library( |
| 293 | name = "greeter", |
| 294 | srcs = ["src/main/java/com/example/Greeting.java"], |
| 295 | visibility = ["//src/main/java/com/example/cmdline:__pkg__"], |
vladmos | 4e9208a | 2020-03-11 12:16:42 -0700 | [diff] [blame] | 296 | ) |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 297 | ``` |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 298 | |
Googler | ec7ecd7 | 2021-03-19 16:20:52 -0700 | [diff] [blame^] | 299 | Now you can build the new package by running the following command at the root |
| 300 | of the workspace: |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 301 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 302 | ``` |
| 303 | bazel build //src/main/java/com/example/cmdline:runner |
| 304 | ``` |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 305 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 306 | Bazel produces output similar to the following: |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 307 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 308 | ``` |
| 309 | INFO: Found 1 target... |
| 310 | Target //src/main/java/com/example/cmdline:runner up-to-date: |
| 311 | bazel-bin/src/main/java/com/example/cmdline/runner.jar |
| 312 | bazel-bin/src/main/java/com/example/cmdline/runner |
| 313 | INFO: Elapsed time: 1.576s, Critical Path: 0.81s |
| 314 | ``` |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 315 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 316 | Now test your freshly built binary: |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 317 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 318 | ``` |
| 319 | ./bazel-bin/src/main/java/com/example/cmdline/runner |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 320 | ``` |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 321 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 322 | You've now modified the project to build as two packages, each containing one |
| 323 | target, and understand the dependencies between them. |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 324 | |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 325 | |
| 326 | ## Use labels to reference targets |
| 327 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 328 | In `BUILD` files and at the command line, Bazel uses target labels to reference |
| 329 | targets - for example, `//:ProjectRunner` or |
| 330 | `//src/main/java/com/example/cmdline:runner`. Their syntax is as follows: |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 331 | |
| 332 | ``` |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 333 | //path/to/package:target-name |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 334 | ``` |
| 335 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 336 | If the target is a rule target, then `path/to/package` is the path to the |
| 337 | directory containing the `BUILD` file, and `target-name` is what you named the |
| 338 | target in the `BUILD` file (the `name` attribute). If the target is a file |
| 339 | target, then `path/to/package` is the path to the root of the package, and |
| 340 | `target-name` is the name of the target file, including its full path. |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 341 | |
laurentlb | d22331d | 2019-09-09 06:52:56 -0700 | [diff] [blame] | 342 | When referencing targets at the repository root, the package path is empty, |
| 343 | just use `//:target-name`. When referencing targets within the same `BUILD` |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 344 | file, you can even skip the `//` workspace root identifier and just use |
| 345 | `:target-name`. |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 346 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 347 | For example, for targets in the `java-tutorial/BUILD` file, you did not have to |
| 348 | specify a package path, since the workspace root is itself a package (`//`), and |
| 349 | your two target labels were simply `//:ProjectRunner` and `//:greeter`. |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 350 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 351 | However, for targets in the `//src/main/java/com/example/cmdline/BUILD` file you |
| 352 | had to specify the full package path of `//src/main/java/com/example/cmdline` |
| 353 | and your target label was `//src/main/java/com/example/cmdline:runner`. |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 354 | |
| 355 | ## Package a Java target for deployment |
| 356 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 357 | Let’s now package a Java target for deployment by building the binary with all |
| 358 | of its runtime dependencies. This lets you run the binary outside of your |
| 359 | development environment. |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 360 | |
dzc | 205125b | 2017-06-26 11:01:47 +0200 | [diff] [blame] | 361 | As you remember, the [java_binary](../be/java.html#java_binary) build rule |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 362 | produces a `.jar` and a wrapper shell script. Take a look at the contents of |
| 363 | `runner.jar` using this command: |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 364 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 365 | ``` |
| 366 | jar tf bazel-bin/src/main/java/com/example/cmdline/runner.jar |
| 367 | ``` |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 368 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 369 | The contents are: |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 370 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 371 | ``` |
| 372 | META-INF/ |
| 373 | META-INF/MANIFEST.MF |
| 374 | com/ |
| 375 | com/example/ |
| 376 | com/example/cmdline/ |
| 377 | com/example/cmdline/Runner.class |
| 378 | ``` |
| 379 | As you can see, `runner.jar` contains `Runner.class`, but not its dependency, |
| 380 | `Greeting.class`. The `runner` script that Bazel generates adds `greeter.jar` |
| 381 | to the classpath, so if you leave it like this, it will run locally, but it |
| 382 | won't run standalone on another machine. Fortunately, the `java_binary` rule |
wyv | 007cba0 | 2020-05-12 04:17:23 -0700 | [diff] [blame] | 383 | allows you to build a self-contained, deployable binary. To build it, append |
| 384 | `_deploy.jar` to the target name: |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 385 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 386 | ``` |
| 387 | bazel build //src/main/java/com/example/cmdline:runner_deploy.jar |
| 388 | ``` |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 389 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 390 | Bazel produces output similar to the following: |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 391 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 392 | ``` |
| 393 | INFO: Found 1 target... |
| 394 | Target //src/main/java/com/example/cmdline:runner_deploy.jar up-to-date: |
| 395 | bazel-bin/src/main/java/com/example/cmdline/runner_deploy.jar |
| 396 | INFO: Elapsed time: 1.700s, Critical Path: 0.23s |
| 397 | ``` |
| 398 | You have just built `runner_deploy.jar`, which you can run standalone away from |
| 399 | your development environment since it contains the required runtime |
| 400 | dependencies. |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 401 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 402 | ## Further reading |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 403 | |
Googler | 22230e4 | 2020-12-02 15:18:28 -0800 | [diff] [blame] | 404 | For more details, see: |
| 405 | |
jingwen | c541dd1 | 2019-09-16 22:12:21 -0700 | [diff] [blame] | 406 | * [rules_jvm_external](https://github.com/bazelbuild/rules_jvm_external) for |
| 407 | rules to manage transitive Maven dependencies. |
| 408 | |
dzc | 205125b | 2017-06-26 11:01:47 +0200 | [diff] [blame] | 409 | * [External Dependencies](../external.html) to learn more about working with |
| 410 | local and remote repositories. |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 411 | |
laurentlb | 374d165 | 2019-09-13 13:11:22 -0700 | [diff] [blame] | 412 | * The [other rules](../rules.html) to learn more about Bazel. |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 413 | |
dzc | 205125b | 2017-06-26 11:01:47 +0200 | [diff] [blame] | 414 | * The [C++ build tutorial](../tutorial/cpp.md) to get started with building |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 415 | C++ projects with Bazel. |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 416 | |
Laszlo Csomor | 5d35794 | 2018-06-12 01:56:45 -0700 | [diff] [blame] | 417 | * The [Android application tutorial](../tutorial/android-app.md) and |
| 418 | [iOS application tutorial](../tutorial/ios-app.md) to get started with |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 419 | building mobile applications for Android and iOS with Bazel. |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 420 | |
Googler | 8af9dc5 | 2017-06-07 13:49:48 -0400 | [diff] [blame] | 421 | Happy building! |
dzc | 22b85a2 | 2017-05-31 20:37:50 +0200 | [diff] [blame] | 422 | |