Let's connect
Let's connect

How to build a simple Scala application with Bazel

Picture of Rikito Taniguchi, Software Developer

Rikito Taniguchi

Software Developer

14 minutes read

console

|-- WORKSPACE
`-- src
    `-- main
        `-- scala
            |-- cmd
            |   |-- BUILD.bazel
            |   `-- Runner.scala
            `-- lib
                |-- BUILD.bazel
                `-- Greeting.scala

console

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") #Import a rule from the Bazel's "standard library"
 ...
http_archive( #This rule can download and import an archived repo
    name = "io_bazel_rules_scala", #The name that will be used to reference the repo
    sha256 = "77a3b9308a8780fff3f10cdbbe36d55164b85a48123033f5e970fdae262e8eb2",
    strip_prefix = "rules_scala-20220201", #Only files from this directory will be unpacked and imported
    type = "zip",
    url = "https://github.com/bazelbuild/rules_scala/releases/download/20220201/rules_scala-20220201.zip",
)

java

// src/main/scala/lib/Greeting.scala
package lib
object Greeting {
  def sayHi = println("Hi!")
}

java

// src/main/scala/cmd/Runner.scala
package cmd
import lib.Greeting
object Runner {
  def main(args: Array[String]) = {
    Greeting.sayHi
  }

console

# src/main/scala/lib/BUILD.bazel
load("@io_bazel_rules_scala//scala:scala.bzl", "scala_library")
scala_library(
    # unique identifier of this target
    name = "greeting",
    # list of Scala files to build
    srcs = ["Greeting.scala"],
)

bash

$ bazel build //src/main/scala/lib:greeting
...
INFO: Found 1 target...
Target //src/main/scala/lib:greeting up-to-date:
  bazel-bin/src/main/scala/lib/greeting.jar
INFO: Elapsed time: 0.152s, Critical Path: 0.00s
INFO: 1 process: 1 internal.
INFO: Build completed successfully, 1 total action

console

# src/main/scala/cmd/BUILD.bazel
load("@io_bazel_rules_scala//scala:scala.bzl", "scala_binary")
scala_binary(
    name = "runner",
    main_class = "cmd.Runner",
    srcs = ["Runner.scala"],
    deps = ["//src/main/scala/lib:greeting"],
)

java

$ bazel build //src/main/scala/cmd:runner

ERROR: .../01_scala_tutorial/src/main/scala/cmd/BUILD.bazel:3:13:
in scala_binary rule //src/main/scala/cmd:runner:
target '//src/main/scala/lib:greeting' is not visible from
target '//src/main/scala/cmd:runner'.

console

 scala_library(
     name = "greeting",
     srcs = ["Greeting.scala"],
+    visibility = ["//src/main/scala/cmd:__pkg__"],
 )

bash

$ bazel build //src/main/scala/cmd:runner
...
INFO: Found 1 target...
Target //src/main/scala/cmd:runner up-to-date:
  bazel-bin/src/main/scala/cmd/runner.jar
  bazel-bin/src/main/scala/cmd/runner
INFO: Elapsed time: 0.146s, Critical Path: 0.01s
INFO: 1 process: 1 internal.
INFO: Build completed successfully, 1 total action

bash

$ ./bazel-bin/src/main/scala/cmd/runner
Hi!

$ bazel run //src/main/scala/cmd:runner
Hi!

java

// src/main/scala/example/App.scala
package example
import scala.meta._
object App {
  def main(args: Array[String]) = {
    pprint.pprintln(parse(args.head))
  }
  private def parse(arg: String) = {
    arg.parse[Source].get
  }
}

bash

http_archive(
    name = "rules_jvm_external",
    strip_prefix = "rules_jvm_external-4.5",
    sha256 = "b17d7388feb9bfa7f2fa09031b32707df529f26c91ab9e5d909eb1676badd9a6",
    url = "https://github.com/bazelbuild/rules_jvm_external/archive/refs/tags/4.5.zip",
)
...

console

Then list all the dependencies in the maven_install statement, which is also in the WORKSPACE file.

console

# src/main/scala/example/BUILD.bazel
scala_binary(
    name = "app",
    main_class = "example.App",
    srcs = ["App.scala"],
    deps = [
        "@maven//:com_lihaoyi_pprint_2_13",
        "@maven//:org_scalameta_scalameta_2_13",
    ],
)

console

$ bazel build //src/main/scala/example:app
...
INFO: Found 1 target...
Target //src/main/scala/example:app up-to-date:
  bazel-bin/src/main/scala/example/app.jar
  bazel-bin/src/main/scala/example/app
INFO: Elapsed time: 0.165s, Critical Path: 0.00s
INFO: 1 process: 1 internal.
INFO: Build completed successfully, 1 total action
...

$ bazel-bin/src/main/scala/example/app "object main { println(1) }"
Source(
  stats = List(
    Defn.Object(
      ...
    )
  )
)

Liked the article?

Share it with others!

explore more on

Take the first step to a sustained competitive edge for your business

Get your free consultation

VirtusLab's work has met the mark several times over, and their latest project is no exception. The team is efficient, hard-working, and trustworthy. Customers can expect a proactive team that drives results.

Stephen Rooke
Stephen RookeDirector of Software Development @ Extreme Reach

VirtusLab's engineers are truly Strapi extensions experts. Their knowledge and expertise in the area of Strapi plugins gave us the opportunity to lift our multi-brand CMS implementation to a different level.

facile logo
Leonardo PoddaEngineering Manager @ Facile.it

VirtusLab has been an incredible partner since the early development of Scala 3, essential to a mature and stable Scala 3 ecosystem.

Martin_Odersky
Martin OderskyHead of Programming Research Group @ EPFL

The VirtusLab team's in-depth knowledge, understanding, and experience of technology have been invaluable to us in developing our product. The team is professional and delivers on time – we greatly appreciated this efficiency when working with them.

Michael_Grant
Michael GrantDirector of Development @ Cyber Sec Company