Migrating from Maven to Bazel

When migrating from any build tool to Bazel, it’s best to have both build
tools running in parallel until you have fully migrated your development team,
CI system, and any other relevant systems. You can run Maven and Bazel in the
same repository.

Migrate from Maven to Bazel

Examples below come from a migration of the
Guava project from Maven to Bazel. The Guava
project used is release 22.0. The examples using Guava do not walk through
each step in the migration, but they do show the files and contents that are
generated or added manually for the migration.

1. Create the WORKSPACE file

Create a file named WORKSPACE at the root of your project. If your project
has no external dependencies, the workspace file can be empty.

If your project depends on files or packages that are not in one of the
project’s directories, specify these external dependencies in the workspace
file. To automate the listing of external dependencies for the workspace file,
use the tool generate_workspace. For instructions about using this tool, see
Generate a WORKSPACE file for a Java project.

Guava project example: external dependencies

Below are the results of using the tool generate_workspace to list the
Guava project’s external dependencies.

2. Create one BUILD file

Now that you have your workspace defined and external dependencies (if
applicable) listed, you need to create BUILD files to describe how your project
should be built. Unlike Maven with its one pom.xml file, Bazel can use many
BUILD files to build a project. These files specify multiple build targets,
which allow Bazel to produce incremental builds.

Add BUILD files in stages. Start with adding one BUILD file
at the root of your project and using it to do an initial build using Bazel.
Then, you refine your build by adding more BUILD files with more granular
targets.

In the same directory as your WORKSPACE file, create a text file and
name it BUILD.

In this BUILD file, use the appropriate rule to create one target to
build your project. Here are some tips:

Use the appropriate rule:

To build projects with a single Maven module, use the
java_library rule as follows:

name: Give the target a meaningful name. In the examples above
we call the target “everything.”

srcs: Use globbing to list all .java files in your project.

resources: Use globbing to list all resources in your project.

deps: You need to determine which external dependencies your
project needs. For example, if you generated a list of external
dependencies using the tool generate_workspace, the dependencies
for java_library are the libraries listed in the
generated_java_libraries macro.

Now that you have a BUILD file at the root of your project, build
your project to ensure that it works. On the command line, from your
workspace directory, use bazel build //:everything to build your
project with Bazel.

The project has now been successfully built with Bazel. You will need
to add more BUILD files to allow incremental builds of the project.

Guava project example: start with one BUILD file

When migrating the Guava project to Bazel, initially one BUILD file is used
to build the entire project. Here are the contents of this initial BUILD
file in the workspace directory:

3. Create more BUILD files (Optional)

Bazel does work with just one BUILD file, as you saw after completing your first
build. You should still consider breaking the build into smaller chunks by
adding more BUILD files with granular targets.

control over visibility of targets between packages, which can prevent
issues such as libraries containing implementation details leaking into
public APIs.

Tips for adding more BUILD files:

You can start by adding a BUILD file to each Java package. Start with
Java packages that have the fewest dependencies and work you way up
to packages with the most dependencies.

As you add BUILD files and specify targets, add these new targets to the
deps sections of targets that depend on them. Note that the glob()
function does not cross package boundaries, so as the number
of packages grows the files matched by glob() will shrink.

Any time you add a BUILD file to a main directory, ensure that you add
a BUILD file to the corresponding test directory.

Take care to limit visibility properly between packages.

To simplify troubleshooting errors in your setup of BUILD files, ensure
that the project continues to build with Bazel as you add each build
file. Run bazel build //... to ensure all of your targets still build.

4. Build using Bazel

You’ve been building using Bazel as you add BUILD files to validate the setup
of the build.

When you have BUILD files at the desired granularity, you can use Bazel
to produce all of your builds.