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.
pom.xmlfile(s). Bazel supports multiple build files and multiple targets per BUILD file, allowing for builds that are more incremental than Maven's.
The steps below describe how to migrate your project 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.
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.
Below are the results of using the tool
generate_workspace to list the
Guava project's external dependencies.
WORKSPACE file contains:
load("//:generate_workspace.bzl", "generated_maven_jars") generated_maven_jars()
BUILD file in the directory
third_party enables access
to external libraries. This BUILD file contains:
load("//:generate_workspace.bzl", "generated_java_libraries") generated_java_libraries()
generate_workspace.bzl file contains:
# The following dependencies were calculated from: # # generate_workspace --maven_project=/usr/local/.../guava def generated_maven_jars(): # pom.xml got requested version # com.google.guava:guava-parent:pom:23.0-SNAPSHOT native.maven_jar( name = "com_google_code_findbugs_jsr305", artifact = "com.google.code.findbugs:jsr305:1.3.9", sha1 = "40719ea6961c0cb6afaeb6a921eaa1f6afd4cfdf", ) # pom.xml got requested version # com.google.guava:guava-parent:pom:23.0-SNAPSHOT native.maven_jar( name = "com_google_errorprone_error_prone_annotations", artifact = "com.google.errorprone:error_prone_annotations:2.0.18", sha1 = "5f65affce1684999e2f4024983835efc3504012e", ) # pom.xml got requested version # com.google.guava:guava-parent:pom:23.0-SNAPSHOT native.maven_jar( name = "com_google_j2objc_j2objc_annotations", artifact = "com.google.j2objc:j2objc-annotations:1.1", sha1 = "ed28ded51a8b1c6b112568def5f4b455e6809019", ) def generated_java_libraries(): native.java_library( name = "com_google_code_findbugs_jsr305", visibility = ["//visibility:public"], exports = ["@com_google_code_findbugs_jsr305//jar"], ) native.java_library( name = "com_google_errorprone_error_prone_annotations", visibility = ["//visibility:public"], exports = ["@com_google_errorprone_error_prone_annotations//jar"], ) native.java_library( name = "com_google_j2objc_j2objc_annotations", visibility = ["//visibility:public"], exports = ["@com_google_j2objc_j2objc_annotations//jar"], )
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
In this BUILD file, use the appropriate rule to create one target to build your project. Here are some tips:
Use the appropriate rule:
java_libraryrule as follows:
java_library( name = "everything", srcs = glob(["src/main/java/**/*.java"]), resources = glob(["src/main/resources/**"]), deps = ["//:all-external-targets"], )
java_libraryrule as follows:
java_library( name = "everything", srcs = glob([ "Module1/src/main/java/**/*.java", "Module2/src/main/java/**/*.java", ... ]), resources = glob([ "Module1/src/main/resources/**", "Module2/src/main/resources/**", ... ]), deps = ["//:all-external-targets"], )
java_binary( name = "everything", srcs = glob(["src/main/java/**/*.java"]), resources = glob(["src/main/resources/**"]), deps = ["//:all-external-targets"], main_class = "com.example.Main" )
Specify the attributes:
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_libraryare the libraries listed in the
Take a look at the example below of this top-level BUILD file from the migration of the Guava project.
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.
When migrating the Guava project to Bazel, initially one BUILD file is used
to build the enitre project. Here are the contents of this initial
file in the workspace directory:
java_library( name = "everything", srcs = glob(["guava/src/**/*.java"]), deps = [ "//third_party:com_google_code_findbugs_jsr305", "//third_party:com_google_errorprone_error_prone_annotations", "//third_party:com_google_j2objc_j2objc_annotations" ], )
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.
Multiple BUILD files with multiple targets will give the build increased granularity, allowing:
Tips for adding more BUILD files:
depssections 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
maindirectory, ensure that you add a BUILD file to the corresponding
bazel build //...to ensure all of your targets still build.
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.