blob: 120c9b93992df6cb325acd375d6fa50b9ccb98a2 [file] [log] [blame] [view]
Yun Peng1f63afa2016-06-24 18:01:03 +00001---
dzc22b85a22017-05-31 20:37:50 +02002layout: documentation
Googler8af9dc52017-06-07 13:49:48 -04003title: Build Tutorial - Java
daroberts223aebd2021-02-18 17:53:30 -08004category: getting-started
Yun Peng1f63afa2016-06-24 18:01:03 +00005---
dzc22b85a22017-05-31 20:37:50 +02006
Googler22230e42020-12-02 15:18:28 -08007# Bazel Tutorial: Build a Java Project
dzc22b85a22017-05-31 20:37:50 +02008
Googler22230e42020-12-02 15:18:28 -08009This tutorial covers the basics of building Java applications with
Googler8af9dc52017-06-07 13:49:48 -040010Bazel. You will set up your workspace and build a simple Java project that
11illustrates key Bazel concepts, such as targets and `BUILD` files.
dzc22b85a22017-05-31 20:37:50 +020012
Googler8af9dc52017-06-07 13:49:48 -040013Estimated completion time: 30 minutes.
dzc22b85a22017-05-31 20:37:50 +020014
Googler8af9dc52017-06-07 13:49:48 -040015## What you'll learn
dzc22b85a22017-05-31 20:37:50 +020016
Googler22230e42020-12-02 15:18:28 -080017In this tutorial you learn how to:
dzc22b85a22017-05-31 20:37:50 +020018
Googler8af9dc52017-06-07 13:49:48 -040019* 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
dzc22b85a22017-05-31 20:37:50 +020025
26## Before you begin
27
Googler1c6a9822017-08-04 19:31:14 +020028### Install Bazel
29
dzc205125b2017-06-26 11:01:47 +020030To prepare for the tutorial, first [Install Bazel](../install.md) if
Googler1c6a9822017-08-04 19:31:14 +020031you don't have it installed already.
32
Laszlo Csomor75748652018-07-26 07:38:14 -070033### Install the JDK
34
Ivo List2fb9f3c2020-12-17 10:19:09 -0800351. Install Java JDK (preferred version is 11, however versions between 8 and 15 are supported).
Laszlo Csomor75748652018-07-26 07:38:14 -070036
372. 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 Egg5f17a762018-10-11 07:21:51 -070047 6. Navigate to the JDK directory (for example `C:\Program Files\Java\jdk1.8.0_152`).
Laszlo Csomor75748652018-07-26 07:38:14 -070048 7. Click "OK" on all dialog windows.
49
Googler1c6a9822017-08-04 19:31:14 +020050### Get the sample project
51
52Retrieve the sample project from Bazel's GitHub repository:
dzc22b85a22017-05-31 20:37:50 +020053
dzc51dcd282017-06-14 22:52:27 +020054```sh
Ruben Das32fc4372019-10-28 10:35:02 -070055git clone https://github.com/bazelbuild/examples
Googler8af9dc52017-06-07 13:49:48 -040056```
dzc22b85a22017-05-31 20:37:50 +020057
Googler8af9dc52017-06-07 13:49:48 -040058The sample project for this tutorial is in the `examples/java-tutorial`
59directory and is structured as follows:
dzc22b85a22017-05-31 20:37:50 +020060
Googler8af9dc52017-06-07 13:49:48 -040061```
62java-tutorial
Googler8af9dc52017-06-07 13:49:48 -040063├── 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```
dzc22b85a22017-05-31 20:37:50 +020076
77## Build with Bazel
78
79### Set up the workspace
80
Googler8af9dc52017-06-07 13:49:48 -040081Before you can build a project, you need to set up its workspace. A workspace is
82a directory that holds your project's source files and Bazel's build outputs. It
83also contains files that Bazel recognizes as special:
dzc22b85a22017-05-31 20:37:50 +020084
Googler8af9dc52017-06-07 13:49:48 -040085* 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,
dzc22b85a22017-05-31 20:37:50 +020087
Googler8af9dc52017-06-07 13:49:48 -040088* 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.)
dzc22b85a22017-05-31 20:37:50 +020091
Googler8af9dc52017-06-07 13:49:48 -040092To designate a directory as a Bazel workspace, create an empty file named
93`WORKSPACE` in that directory.
dzc22b85a22017-05-31 20:37:50 +020094
Googler8af9dc52017-06-07 13:49:48 -040095When Bazel builds the project, all inputs and dependencies must be in the same
96workspace. Files residing in different workspaces are independent of one
97another unless linked, which is beyond the scope of this tutorial.
dzc22b85a22017-05-31 20:37:50 +020098
Googler8af9dc52017-06-07 13:49:48 -040099### Understand the BUILD file
dzc22b85a22017-05-31 20:37:50 +0200100
Googler8af9dc52017-06-07 13:49:48 -0400101A `BUILD` file contains several different types of instructions for Bazel.
102The most important type is the *build rule*, which tells Bazel how to build the
103desired outputs, such as executable binaries or libraries. Each instance
104of a build rule in the `BUILD` file is called a *target* and points to a
105specific set of source files and dependencies. A target can also point to other
106targets.
dzc22b85a22017-05-31 20:37:50 +0200107
Googler8af9dc52017-06-07 13:49:48 -0400108Take a look at the `java-tutorial/BUILD` file:
dzc22b85a22017-05-31 20:37:50 +0200109
vladmos4e9208a2020-03-11 12:16:42 -0700110```python
Googler8af9dc52017-06-07 13:49:48 -0400111java_binary(
Googler006659e2017-07-20 19:48:05 +0200112 name = "ProjectRunner",
Googler8af9dc52017-06-07 13:49:48 -0400113 srcs = glob(["src/main/java/com/example/*.java"]),
114)
115```
dzc22b85a22017-05-31 20:37:50 +0200116
Googler8af9dc52017-06-07 13:49:48 -0400117In our example, the `ProjectRunner` target instantiates Bazel's built-in
dzc205125b2017-06-26 11:01:47 +0200118[`java_binary` rule](../be/java.html#java_binary). The rule tells Bazel to
Googler8af9dc52017-06-07 13:49:48 -0400119build a `.jar` file and a wrapper shell script (both named after the target).
dzc22b85a22017-05-31 20:37:50 +0200120
Googler8af9dc52017-06-07 13:49:48 -0400121The attributes in the target explicitly state its dependencies and options.
122While 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
124the source files that Bazel uses to build the target, and `main_class` specifies
125the class that contains the main method. (You may have noticed that our example
dzc205125b2017-06-26 11:01:47 +0200126uses [glob](../be/functions.html#glob) to pass a set of source files to Bazel
Googler8af9dc52017-06-07 13:49:48 -0400127instead of listing them one by one.)
dzc22b85a22017-05-31 20:37:50 +0200128
Googler8af9dc52017-06-07 13:49:48 -0400129### Build the project
dzc22b85a22017-05-31 20:37:50 +0200130
Googler8af9dc52017-06-07 13:49:48 -0400131Let's build your sample project. Change into the `java-tutorial` directory
132and run the following command:
dzc22b85a22017-05-31 20:37:50 +0200133
Googler8af9dc52017-06-07 13:49:48 -0400134```
Googler006659e2017-07-20 19:48:05 +0200135bazel build //:ProjectRunner
Googler8af9dc52017-06-07 13:49:48 -0400136```
137Notice the target label - the `//` part is the location of our `BUILD` file
138relative to the root of the workspace (in this case, the root itself), and
139`ProjectRunner` is what we named that target in the `BUILD` file. (You will
140learn about target labels in more detail at the end of this tutorial.)
dzc22b85a22017-05-31 20:37:50 +0200141
Googler8af9dc52017-06-07 13:49:48 -0400142Bazel produces output similar to the following:
dzc22b85a22017-05-31 20:37:50 +0200143
Googler8af9dc52017-06-07 13:49:48 -0400144```bash
Googler006659e2017-07-20 19:48:05 +0200145 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
Googler8af9dc52017-06-07 13:49:48 -0400150```
dzc22b85a22017-05-31 20:37:50 +0200151
Googler8af9dc52017-06-07 13:49:48 -0400152Congratulations, you just built your first Bazel target! Bazel places build
153outputs in the `bazel-bin` directory at the root of the workspace. Browse
154through its contents to get an idea for Bazel's output structure.
dzc22b85a22017-05-31 20:37:50 +0200155
Googler8af9dc52017-06-07 13:49:48 -0400156Now test your freshly built binary:
dzc22b85a22017-05-31 20:37:50 +0200157
dzc51dcd282017-06-14 22:52:27 +0200158```sh
Googler8af9dc52017-06-07 13:49:48 -0400159bazel-bin/ProjectRunner
160```
dzc22b85a22017-05-31 20:37:50 +0200161
162### Review the dependency graph
163
Googler8af9dc52017-06-07 13:49:48 -0400164Bazel requires build dependencies to be explicitly declared in BUILD files.
165Bazel uses those statements to create the project's dependency graph, which
166enables accurate incremental builds.
dzc22b85a22017-05-31 20:37:50 +0200167
Googler8af9dc52017-06-07 13:49:48 -0400168Let's visualize our sample project's dependencies. First, generate a text
169representation of the dependency graph (run the command at the workspace root):
dzc22b85a22017-05-31 20:37:50 +0200170
Googler8af9dc52017-06-07 13:49:48 -0400171```
wtroberts5a0cf9b2019-09-06 07:55:15 -0700172bazel query --notool_deps --noimplicit_deps "deps(//:ProjectRunner)" --output graph
Googler8af9dc52017-06-07 13:49:48 -0400173```
dzc22b85a22017-05-31 20:37:50 +0200174
Googler8af9dc52017-06-07 13:49:48 -0400175The above command tells Bazel to look for all dependencies for the target
176`//:ProjectRunner` (excluding host and implicit dependencies) and format the
177output as a graph.
dzc22b85a22017-05-31 20:37:50 +0200178
Googler8af9dc52017-06-07 13:49:48 -0400179Then, paste the text into [GraphViz](http://www.webgraphviz.com/).
dzc22b85a22017-05-31 20:37:50 +0200180
dzc22b85a22017-05-31 20:37:50 +0200181
Googler8af9dc52017-06-07 13:49:48 -0400182As you can see, the project has a single target that build two source files with
183no additional dependencies:
dzc22b85a22017-05-31 20:37:50 +0200184
Googler8af9dc52017-06-07 13:49:48 -0400185![Dependency graph of the target 'ProjectRunner'](/assets/tutorial_java_01.svg)
dzc22b85a22017-05-31 20:37:50 +0200186
Googler8af9dc52017-06-07 13:49:48 -0400187Now that you have set up your workspace, built your project, and examined its
188dependencies, let's add some complexity.
dzc22b85a22017-05-31 20:37:50 +0200189
190## Refine your Bazel build
191
Googler8af9dc52017-06-07 13:49:48 -0400192While a single target is sufficient for small projects, you may want to split
193larger projects into multiple targets and packages to allow for fast incremental
194builds (that is, only rebuild what's changed) and to speed up your builds by
195building multiple parts of a project at once.
dzc22b85a22017-05-31 20:37:50 +0200196
Googler8af9dc52017-06-07 13:49:48 -0400197### Specify multiple build targets
dzc22b85a22017-05-31 20:37:50 +0200198
Googler8af9dc52017-06-07 13:49:48 -0400199Let's split our sample project build into two targets. Replace the contents of
200the `java-tutorial/BUILD` file with the following:
dzc22b85a22017-05-31 20:37:50 +0200201
vladmos4e9208a2020-03-11 12:16:42 -0700202```python
Googler8af9dc52017-06-07 13:49:48 -0400203java_binary(
204 name = "ProjectRunner",
205 srcs = ["src/main/java/com/example/ProjectRunner.java"],
206 main_class = "com.example.ProjectRunner",
207 deps = [":greeter"],
208)
dzc22b85a22017-05-31 20:37:50 +0200209
Googler8af9dc52017-06-07 13:49:48 -0400210java_library(
211 name = "greeter",
212 srcs = ["src/main/java/com/example/Greeting.java"],
213)
214```
dzc22b85a22017-05-31 20:37:50 +0200215
Googler8af9dc52017-06-07 13:49:48 -0400216With this configuration, Bazel first builds the `greeter` library, then the
Passw473a9162017-12-22 14:13:12 -0800217`ProjectRunner` binary. The `deps` attribute in `java_binary` tells Bazel that
Googler8af9dc52017-06-07 13:49:48 -0400218the `greeter` library is required to build the `ProjectRunner` binary.
dzc22b85a22017-05-31 20:37:50 +0200219
Googler8af9dc52017-06-07 13:49:48 -0400220Let's build this new version of our project. Run the following command:
dzc22b85a22017-05-31 20:37:50 +0200221
Googler8af9dc52017-06-07 13:49:48 -0400222```
223bazel build //:ProjectRunner
224```
dzc22b85a22017-05-31 20:37:50 +0200225
Googler8af9dc52017-06-07 13:49:48 -0400226Bazel produces output similar to the following:
dzc22b85a22017-05-31 20:37:50 +0200227
Googler8af9dc52017-06-07 13:49:48 -0400228```
229INFO: Found 1 target...
230Target //:ProjectRunner up-to-date:
231 bazel-bin/ProjectRunner.jar
232 bazel-bin/ProjectRunner
233INFO: Elapsed time: 2.454s, Critical Path: 1.58s
234```
dzc22b85a22017-05-31 20:37:50 +0200235
Googler8af9dc52017-06-07 13:49:48 -0400236Now test your freshly built binary:
dzc22b85a22017-05-31 20:37:50 +0200237
Googler8af9dc52017-06-07 13:49:48 -0400238```
239bazel-bin/ProjectRunner
240```
dzc22b85a22017-05-31 20:37:50 +0200241
Googler8af9dc52017-06-07 13:49:48 -0400242If you now modify `ProjectRunner.java` and rebuild the project, Bazel only
243recompiles that file.
dzc22b85a22017-05-31 20:37:50 +0200244
Googler8af9dc52017-06-07 13:49:48 -0400245Looking at the dependency graph, you can see that `ProjectRunner` depends on the
246same inputs as it did before, but the structure of the build is different:
dzc22b85a22017-05-31 20:37:50 +0200247
laurentlb79b94312018-11-07 05:18:59 -0800248![Dependency graph of the target 'ProjectRunner' after adding a dependency](
249/assets/tutorial_java_02.svg)
dzc22b85a22017-05-31 20:37:50 +0200250
Googler8af9dc52017-06-07 13:49:48 -0400251You've now built the project with two targets. The `ProjectRunner` target builds
252two source files and depends on one other target (`:greeter`), which builds
253one additional source file.
dzc22b85a22017-05-31 20:37:50 +0200254
255### Use multiple packages
256
Googler8af9dc52017-06-07 13:49:48 -0400257Let’s now split the project into multiple packages. If you take a look at the
258`src/main/java/com/example/cmdline` directory, you can see that it also contains
259a `BUILD` file, plus some source files. Therefore, to Bazel, the workspace now
260contains two packages, `//src/main/java/com/example/cmdline` and `//` (since
261there is a `BUILD` file at the root of the workspace).
dzc22b85a22017-05-31 20:37:50 +0200262
Googler8af9dc52017-06-07 13:49:48 -0400263Take a look at the `src/main/java/com/example/cmdline/BUILD` file:
dzc22b85a22017-05-31 20:37:50 +0200264
vladmos4e9208a2020-03-11 12:16:42 -0700265```python
Googler8af9dc52017-06-07 13:49:48 -0400266java_binary(
267 name = "runner",
268 srcs = ["Runner.java"],
269 main_class = "com.example.cmdline.Runner",
vladmos4e9208a2020-03-11 12:16:42 -0700270 deps = ["//:greeter"],
Googler8af9dc52017-06-07 13:49:48 -0400271)
272```
dzc22b85a22017-05-31 20:37:50 +0200273
Googler8af9dc52017-06-07 13:49:48 -0400274The `runner` target depends on the `greeter` target in the `//` package (hence
275the target label `//:greeter`) - Bazel knows this through the `deps` attribute.
276Take a look at the dependency graph:
dzc22b85a22017-05-31 20:37:50 +0200277
Googler8af9dc52017-06-07 13:49:48 -0400278![Dependency graph of the target 'runner'](/assets/tutorial_java_03.svg)
dzc22b85a22017-05-31 20:37:50 +0200279
Peter Laird4b16e022017-10-12 16:44:19 +0200280However, for the build to succeed, you must explicitly give the `runner` target in
281`//src/main/java/com/example/cmdline/BUILD` visibility to targets in
Googler8af9dc52017-06-07 13:49:48 -0400282`//BUILD` using the `visibility` attribute. This is because by default targets
283are only visible to other targets in the same `BUILD` file. (Bazel uses target
284visibility to prevent issues such as libraries containing implementation details
285leaking into public APIs.)
dzc22b85a22017-05-31 20:37:50 +0200286
Googler8af9dc52017-06-07 13:49:48 -0400287To do this, add the `visibility` attribute to the `greeter` target in
288`java-tutorial/BUILD` as shown below:
dzc22b85a22017-05-31 20:37:50 +0200289
vladmos4e9208a2020-03-11 12:16:42 -0700290```python
Googler8af9dc52017-06-07 13:49:48 -0400291java_library(
292 name = "greeter",
293 srcs = ["src/main/java/com/example/Greeting.java"],
294 visibility = ["//src/main/java/com/example/cmdline:__pkg__"],
vladmos4e9208a2020-03-11 12:16:42 -0700295)
Googler8af9dc52017-06-07 13:49:48 -0400296```
dzc22b85a22017-05-31 20:37:50 +0200297
Googler8af9dc52017-06-07 13:49:48 -0400298Let's now build the new package. Run the following command at the root of the
299workspace:
dzc22b85a22017-05-31 20:37:50 +0200300
Googler8af9dc52017-06-07 13:49:48 -0400301```
302bazel build //src/main/java/com/example/cmdline:runner
303```
dzc22b85a22017-05-31 20:37:50 +0200304
Googler8af9dc52017-06-07 13:49:48 -0400305Bazel produces output similar to the following:
dzc22b85a22017-05-31 20:37:50 +0200306
Googler8af9dc52017-06-07 13:49:48 -0400307```
308INFO: Found 1 target...
309Target //src/main/java/com/example/cmdline:runner up-to-date:
310 bazel-bin/src/main/java/com/example/cmdline/runner.jar
311 bazel-bin/src/main/java/com/example/cmdline/runner
312 INFO: Elapsed time: 1.576s, Critical Path: 0.81s
313```
dzc22b85a22017-05-31 20:37:50 +0200314
Googler8af9dc52017-06-07 13:49:48 -0400315Now test your freshly built binary:
dzc22b85a22017-05-31 20:37:50 +0200316
Googler8af9dc52017-06-07 13:49:48 -0400317```
318./bazel-bin/src/main/java/com/example/cmdline/runner
Googler8af9dc52017-06-07 13:49:48 -0400319```
dzc22b85a22017-05-31 20:37:50 +0200320
Googler8af9dc52017-06-07 13:49:48 -0400321You've now modified the project to build as two packages, each containing one
322target, and understand the dependencies between them.
dzc22b85a22017-05-31 20:37:50 +0200323
dzc22b85a22017-05-31 20:37:50 +0200324
325## Use labels to reference targets
326
Googler8af9dc52017-06-07 13:49:48 -0400327In `BUILD` files and at the command line, Bazel uses target labels to reference
328targets - for example, `//:ProjectRunner` or
329`//src/main/java/com/example/cmdline:runner`. Their syntax is as follows:
dzc22b85a22017-05-31 20:37:50 +0200330
331```
Googler8af9dc52017-06-07 13:49:48 -0400332//path/to/package:target-name
dzc22b85a22017-05-31 20:37:50 +0200333```
334
Googler8af9dc52017-06-07 13:49:48 -0400335If the target is a rule target, then `path/to/package` is the path to the
336directory containing the `BUILD` file, and `target-name` is what you named the
337target in the `BUILD` file (the `name` attribute). If the target is a file
338target, then `path/to/package` is the path to the root of the package, and
339`target-name` is the name of the target file, including its full path.
dzc22b85a22017-05-31 20:37:50 +0200340
laurentlbd22331d2019-09-09 06:52:56 -0700341When referencing targets at the repository root, the package path is empty,
342just use `//:target-name`. When referencing targets within the same `BUILD`
Googler8af9dc52017-06-07 13:49:48 -0400343file, you can even skip the `//` workspace root identifier and just use
344`:target-name`.
dzc22b85a22017-05-31 20:37:50 +0200345
Googler8af9dc52017-06-07 13:49:48 -0400346For example, for targets in the `java-tutorial/BUILD` file, you did not have to
347specify a package path, since the workspace root is itself a package (`//`), and
348your two target labels were simply `//:ProjectRunner` and `//:greeter`.
dzc22b85a22017-05-31 20:37:50 +0200349
Googler8af9dc52017-06-07 13:49:48 -0400350However, for targets in the `//src/main/java/com/example/cmdline/BUILD` file you
351had to specify the full package path of `//src/main/java/com/example/cmdline`
352and your target label was `//src/main/java/com/example/cmdline:runner`.
dzc22b85a22017-05-31 20:37:50 +0200353
354## Package a Java target for deployment
355
Googler8af9dc52017-06-07 13:49:48 -0400356Let’s now package a Java target for deployment by building the binary with all
357of its runtime dependencies. This lets you run the binary outside of your
358development environment.
dzc22b85a22017-05-31 20:37:50 +0200359
dzc205125b2017-06-26 11:01:47 +0200360As you remember, the [java_binary](../be/java.html#java_binary) build rule
Googler8af9dc52017-06-07 13:49:48 -0400361produces a `.jar` and a wrapper shell script. Take a look at the contents of
362`runner.jar` using this command:
dzc22b85a22017-05-31 20:37:50 +0200363
Googler8af9dc52017-06-07 13:49:48 -0400364```
365jar tf bazel-bin/src/main/java/com/example/cmdline/runner.jar
366```
dzc22b85a22017-05-31 20:37:50 +0200367
Googler8af9dc52017-06-07 13:49:48 -0400368The contents are:
dzc22b85a22017-05-31 20:37:50 +0200369
Googler8af9dc52017-06-07 13:49:48 -0400370```
371META-INF/
372META-INF/MANIFEST.MF
373com/
374com/example/
375com/example/cmdline/
376com/example/cmdline/Runner.class
377```
378As you can see, `runner.jar` contains `Runner.class`, but not its dependency,
379`Greeting.class`. The `runner` script that Bazel generates adds `greeter.jar`
380to the classpath, so if you leave it like this, it will run locally, but it
381won't run standalone on another machine. Fortunately, the `java_binary` rule
wyv007cba02020-05-12 04:17:23 -0700382allows you to build a self-contained, deployable binary. To build it, append
383`_deploy.jar` to the target name:
dzc22b85a22017-05-31 20:37:50 +0200384
Googler8af9dc52017-06-07 13:49:48 -0400385```
386bazel build //src/main/java/com/example/cmdline:runner_deploy.jar
387```
dzc22b85a22017-05-31 20:37:50 +0200388
Googler8af9dc52017-06-07 13:49:48 -0400389Bazel produces output similar to the following:
dzc22b85a22017-05-31 20:37:50 +0200390
Googler8af9dc52017-06-07 13:49:48 -0400391```
392INFO: Found 1 target...
393Target //src/main/java/com/example/cmdline:runner_deploy.jar up-to-date:
394 bazel-bin/src/main/java/com/example/cmdline/runner_deploy.jar
395INFO: Elapsed time: 1.700s, Critical Path: 0.23s
396```
397You have just built `runner_deploy.jar`, which you can run standalone away from
398your development environment since it contains the required runtime
399dependencies.
dzc22b85a22017-05-31 20:37:50 +0200400
Googler8af9dc52017-06-07 13:49:48 -0400401## Further reading
dzc22b85a22017-05-31 20:37:50 +0200402
Googler22230e42020-12-02 15:18:28 -0800403For more details, see:
404
jingwenc541dd12019-09-16 22:12:21 -0700405* [rules_jvm_external](https://github.com/bazelbuild/rules_jvm_external) for
406 rules to manage transitive Maven dependencies.
407
dzc205125b2017-06-26 11:01:47 +0200408* [External Dependencies](../external.html) to learn more about working with
409 local and remote repositories.
dzc22b85a22017-05-31 20:37:50 +0200410
laurentlb374d1652019-09-13 13:11:22 -0700411* The [other rules](../rules.html) to learn more about Bazel.
dzc22b85a22017-05-31 20:37:50 +0200412
dzc205125b2017-06-26 11:01:47 +0200413* The [C++ build tutorial](../tutorial/cpp.md) to get started with building
Googler8af9dc52017-06-07 13:49:48 -0400414 C++ projects with Bazel.
dzc22b85a22017-05-31 20:37:50 +0200415
Laszlo Csomor5d357942018-06-12 01:56:45 -0700416* The [Android application tutorial](../tutorial/android-app.md) and
417 [iOS application tutorial](../tutorial/ios-app.md) to get started with
Googler8af9dc52017-06-07 13:49:48 -0400418 building mobile applications for Android and iOS with Bazel.
dzc22b85a22017-05-31 20:37:50 +0200419
Googler8af9dc52017-06-07 13:49:48 -0400420Happy building!
dzc22b85a22017-05-31 20:37:50 +0200421