This rule is used for building Scala projects with Bazel. There are
currently four rules, scala_library
, scala_macro_library
, scala_binary
and scala_test
.
In order to use scala_library
, scala_macro_library
, and scala_binary
,
you must have bazel 0.5.3 or later and add the following to your WORKSPACE file:
rules_scala_version="5cdae2f034581a05e23c3473613b409de5978833" # update this as needed
http_archive(
name = "io_bazel_rules_scala",
url = "https://github.com/bazelbuild/rules_scala/archive/%s.zip"%rules_scala_version,
type = "zip",
strip_prefix= "rules_scala-%s" % rules_scala_version
)
load("@io_bazel_rules_scala//scala:scala.bzl", "scala_repositories")
scala_repositories()
To use a particular tag, use the tagged number in tag =
and omit the commit
attribute.
Note that these plugins are still evolving quickly, as is bazel, so you may need to select
the version most appropriate for you.
In addition, you must register scala_toolchain
- To register default empty toolcahin simply add those lines to WORKSPACE
file:
load("@io_bazel_rules_scala//scala:toolchains.bzl", "scala_register_toolchains")
scala_register_toolchains()
Then in your BUILD file just add the following so the rules will be available:
load("@io_bazel_rules_scala//scala:scala.bzl", "scala_library", "scala_binary", "scala_test")
You may wish to have these rules loaded by default using bazel's prelude. You can add the above to the file tools/build_rules/prelude_bazel
in your repo (don't forget to have a, possibly empty, BUILD file there) and then it will be automatically prepended to every BUILD file in the workspace.
To run with a persistent worker (much faster), you need to add
build --strategy=Scalac=worker
test --strategy=Scalac=worker
to your command line, or to enable by default for building/testing add it to your .bazelrc.
scala_library(name, srcs, deps, runtime_deps, exports, data, main_class, resources, resource_strip_prefix, scalacopts, jvm_flags, scalac_jvm_flags, javac_jvm_flags)
scala_macro_library(name, srcs, deps, runtime_deps, exports, data, main_class, resources, resource_strip_prefix, scalacopts, jvm_flags, scalac_jvm_flags, javac_jvm_flags)
scala_library
generates a .jar
file from .scala
source files. This rule
also creates an interface jar to avoid recompiling downstream targets unless
their interface changes.
scala_macro_library
generates a .jar
file from .scala
source files when
they contain macros. For macros, there are no interface jars because the macro
code is executed at compile time. For best performance, you want very granular
targets until such time as the zinc incremental compiler can be supported.
In order to make a java rule use this jar file, use the java_import
rule.
Attributes | |
---|---|
name |
A unique name for this target |
srcs |
List of Scala |
deps |
List of other libraries to linked to this library target |
runtime_deps |
List of other libraries to put on the classpath only at runtime. This is rarely needed in Scala. |
exports |
List of targets to add to the dependencies of those that depend on this target. Similar to the `java_library` parameter of the same name. Use this sparingly as it weakens the precision of the build graph. |
data |
List of files needed by this rule at runtime. |
main_class |
Name of class with main() method to use as an entry point
The value of this attribute is a class name, not a source file. The
class must be available at runtime: it may be compiled by this rule
(from |
resources |
A list of data files to be included in the JAR. |
resource_strip_prefix |
The path prefix to strip from Java resources. If specified, this path prefix is stripped from every file in the `resources` attribute. It is an error for a resource file not to be under this directory. |
scalacopts |
Extra compiler options for this library to be passed to scalac. Subject to Make variable substitution and Bourne shell tokenization. |
jvm_flags |
Deprecated, superseded by scalac_jvm_flags and javac_jvm_flags. Is not used and is kept as backwards compatibility for the near future. Effectively jvm_flags is now an executable target attribute only. |
scalac_jvm_flags |
List of JVM flags to be passed to scalac after the
|
javac_jvm_flags |
List of JVM flags to be passed to javac after the
|
scala_binary(name, srcs, deps, runtime_deps, data, main_class, resources, resource_strip_prefix, scalacopts, jvm_flags, scalac_jvm_flags, javac_jvm_flags)
scala_binary
generates a Scala executable. It may depend on scala_library
, scala_macro_library
and java_library
rules.
A scala_binary
requires a main_class
attribute.
Attributes | |
---|---|
name |
A unique name for this target |
srcs |
List of Scala |
deps |
List of other libraries to linked to this binary target |
runtime_deps |
List of other libraries to put on the classpath only at runtime. This is rarely needed in Scala. |
data |
List of files needed by this rule at runtime. |
main_class |
Name of class with main() method to use as an entry point
The value of this attribute is a class name, not a source file. The
class must be available at runtime: it may be compiled by this rule
(from |
resources |
A list of data files to be included in the JAR. |
resource_strip_prefix |
The path prefix to strip from Java resources. If specified, this path prefix is stripped from every file in the `resources` attribute. It is an error for a resource file not to be under this directory. |
scalacopts |
Extra compiler options for this binary to be passed to scalac. Subject to Make variable substitution and Bourne shell tokenization. |
jvm_flags |
List of JVM flags to be passed to the executing JVM. Subject to Make variable substitution and Bourne shell tokenization. |
scalac_jvm_flags |
List of JVM flags to be passed to scalac after the
|
javac_jvm_flags |
List of JVM flags to be passed to javac after the
|
scala_test(name, srcs, suites, deps, data, main_class, resources, resource_strip_prefix, scalacopts, jvm_flags, scalac_jvm_flags, javac_jvm_flags)
scala_test
generates a Scala executable which runs unit test suites written
using the scalatest
library. It may depend on scala_library
,
scala_macro_library
and java_library
rules.
A scala_test
by default runs all tests in a given target.
For backwards compatibility it accepts a suites
attribute which
is ignored due to the ease with which that field is not correctly
populated and tests are not run.
scala_repl(name, deps, scalacopts, jvm_flags, scalac_jvm_flags, javac_jvm_flags)
A scala repl allows you to add library dependencies (not currently scala_binary
targets)
to generate a script to run which starts a REPL.
Since bazel run
closes stdin, it cannot be used to start the REPL. Instead,
you use bazel build
to build the script, then run that script as normal to start a REPL
session. An example in this repo:
bazel build test:HelloLibRepl
bazel-bin/test/HelloLibRepl
The scala library suite allows you to define a glob or series of targets to generate sub scala libraries for. The outer target will export all of the inner targets. This allows splitting up of a series of independent files in a larger target into smaller ones. This lets us cache outputs better and also build the individual targets in parallel. Downstream targets should not be aware of its presence.
The scala test suite allows you to define a glob or series of targets to generate sub scala tests for. The outer target defines a native test suite to run all the inner tests. This allows splitting up of a series of independent tests from one target into several. This lets us cache outputs better and also build and test the individual targets in parallel.
load("@io_bazel_rules_scala//thrift:thrift.bzl", "thrift_library")
thrift_library(name, srcs, deps, absolute_prefix, absolute_prefixes)
thrift_library
generates a thrift source zip file. It should be consumed by a thrift compiler like scrooge_scala_library
.
Attributes | |
---|---|
name |
A unique name for this target |
srcs |
List of Thrift |
deps |
List of other thrift dependencies that this thrift depends on. |
absolute_prefix |
This string acts as a wildcard expression of the form *`string_value` that is removed from the start of the path. Example: thrift is at `a/b/c/d/e/A.thrift` , prefix of `b/c/d`. Will mean other thrift targets can refer to this thrift at `e/A.thrift`. |
absolute_prefixes |
Each of these strings acts as a wildcard expression of the form |
You first need to add the following to your WORKSPACE file:
load("@io_bazel_rules_scala//scala_proto:scala_proto.bzl", "scala_proto_repositories")
scala_proto_repositories()
Then you can import scalapb_proto_library
in any BUILD file like this:
load("@io_bazel_rules_scala//scala_proto:scala_proto.bzl", "scalapb_proto_library")
scalapb_proto_library(name, deps, with_grpc, with_java, with_flat_package, with_single_line_to_string)
scalapb_proto_library
generates a scala library of scala proto bindings
generated by the ScalaPB compiler.
Attributes | |
---|---|
name |
A unique name for this target |
deps |
List of dependencies for this target. Must either be of type |
with_grpc |
Enables generation of grpc service bindings for services defined in |
with_java |
Enables generation of converters to and from java protobuf bindings. If you set this to |
with_flat_package |
When true, ScalaPB will not append the protofile base name to the package name |
with_single_line_to_string |
Enables generation of |
Scala toolchain allows you to define global configuration to all scala targets.
Currently the only option that can be set is scalacopts
but the plan is to expand it to other options as well.
some scala_toolchain must be registered!
In your workspace file add the following lines:
# WORKSPACE
# register default scala toolchain
load("@io_bazel_rules_scala//scala:toolchains.bzl", "scala_register_toolchains")
scala_register_toolchains()
- Add your own definition to scala_toolchain to a
BUILD
file:
# //toolchains/BUILD
load("//scala:scala_toolchain.bzl", "scala_toolchain")
scala_toolchain(
name = "my_toolchain_impl",
scalacopts = ["-Ywarn-unused"],
visibility = ["//visibility:public"]
)
toolchain(
name = "my_scala_toolchain",
toolchain_type = "@io_bazel_rules_scala//scala:toolchain_type",
toolchain = "my_toolchain_impl",
visibility = ["//visibility:public"]
)
- register your custom toolchain from
WORKSPACE
:
# WORKSPACE
# ...
register_toolchains("//toolchains:my_scala_toolchain")
Bazel pushes towards explicit and minimal dependencies to keep BUILD file hygiene and allow for targets to refactor their dependencies without fear of downstream breaking.
Currently rules_scala does this at the cost of having cryptic scalac
errors when one mistakenly depends on a transitive dependency or, as more often the case for some, a transitive dependency is needed to please scalac itself.
To learn more about the motivation of strict-deps itself you can visit this Bazel blog post on the subject.
To use it just add --strict_java_deps=WARN|ERROR
to your bazel
invocation.
In both cases of WARN
or ERROR
you will get the following text in the event of a violation:
...
Target '//some_package:transitive_dependency' is used but isn't explicitly declared, please add it to the deps.
You can use the following buildozer command:
buildozer 'add deps //some_package:transitive_dependency' //some_other_package:transitive_dependency_user
Note that if you have buildozer
installed you can just run the last line and have it automatically apply the fix for you.
Caveats:
- Extra builds- when strict-deps is on the transitive dependencies are inputs to the compilation action which means you can potentially have more build triggers for changes the cross the ijar boundary
- Label propagation- since label of targets are needed for the clear message and since it's not currently supported by JavaInfo from bazel we manually propagate it. This means that the error messages have a significantly lower grade if you don't use one of the scala rules or scala_import (since they don't propagate these labels)
- javac outputs incorrect targets due to a problem we're tracing down. Practically we've noticed it's pretty trivial to understand the correct target (i.e. it's almost a formatting problem)
Note: Currently strict-deps is protected by a feature toggle but we're strongly considering making it the default behavior as java_*
rules do.
Test & Build:
bash test_all.sh
This doesn't currently pass on OS X (see #136 for details) and so you can also use:
bazel test //test/...
Note bazel test //...
will not work since we have a sub-folder on the root folder which is meant to be used in a failure scenario in the integration tests.
Similarly to only build you should use bazel build //src/...
due to that folder.