Simple scripts and small programs can be compiled and run manually using the REPL tool. However, as the number of files grows, manual compilation becomes more and more confusing. In order to structure and run projects conveniently, Scala developers use the sbt utility. Let's take a quick look at the advantages of using the Scala Build Tool!
sbt new
Production projects often use libraries to implement business logic, test the code, and accelerate development. So, there are two ways to add library dependencies to them:
- Manually, which means that you add .jar files to the project by dropping them into the lib directory;
- Managed, that is, configured in the build.sbt file, and sbt automatically adds .jar files to the project structure.
Obviously, a well-created project must be bootstrapped as efficiently as possible. It must also automatically add libraries with stable versions. So, most programmers use sbt to run a project by creating a shell script. That script includes basic sbt commands such as compile and test. The first command prints the project warnings and errors caught while compiling. The second command runs the tests located in the src/test/scala directory of your project and gives statistics of passed tests. The testing directory of a project can't appear by itself — you should create it. However, sbt has the command new to create a template structure to quickly set up a new project. It also uses the Giter8 tool, which can be called from the sbt's new command. The following command calls one of the Giter8's templates:
sbt new scala/scala3.g8
Then, input the name of the project to configure its skeleton.
A template to demonstrate a minimal Scala 3 application
name [Scala 3 Project Template]: my-pet-store
The last line of the output will show the full path to the new project. Now you can open it in IDEA.
build.sbt
Here is an already created root project in the build.sbt:
lazy val root = project
.in(file("."))
.settings(
name := "my-pet-store",
version := "0.1.0-SNAPSHOT",
scalaVersion := scala3Version,
libraryDependencies += "org.scalameta" %% "munit" % "0.7.29" % Test
)
The next run command uses the contents of the main class in the src/main/scala directory to launch a project implementation. It is also able to set up other project settings parameters such as:
scalaVersionthat indicates which Scala version is used for running the code;version, that is, the version of the project;organizationNameorganization name that creates the project.
The next parameter enablePlugins activates plugins included in the project from plugins.sbt (plugins are disabled by default).
You can find more information about other settings in the official sbt documentation.
Dependencies
The libraryDependencies parameter is also a setting in the build.sbt file. It imports the external library munit to provide us with testing Scala code. To add more libraries to a project, sbt provides two ways.
- Define the setting as a
Seq:
libraryDependencies ++= Seq(
"org.scalameta" %% "munit" % "0.7.29" % Test,
"org.typelevel" %% "cats-core" % "2.9.0",
)
- Or write the keyword for each library:
libraryDependencies += "org.scalameta" %% "munit" % "0.7.29" % Test
libraryDependencies += "org.typelevel" %% "cats-core" % "2.9.0"
On top of that, sbt manages library dependency inside an external library. Suppose some project uses library A, which depends on library B. In that case, sbt will download both libraries (A, B) and include them in the project automatically.
As you probably noticed, the library for testing Scala code and the cats-core library, which provides abstractions for functional programming, have different general forms. The last keyword Test simply means that the dependency will be added to the project for test configuration but will not be added to the compile configuration.
Run
After all configuration settings, your Scala project is ready to run. To run it, enter the following command:
sbt run
Sbt searches the main class in the src/main/scala path and runs it. The program will print:
Hello world!
I was compiled by Scala 3. :)
But what happens when sbt finds out two or more main classes to run? Let's duplicate a generated Main.scala file and replace the content with:
@main def hello2: Unit =
println("Second File")
After the run command, sbt asks which main class is to be executed:
Multiple main classes detected. Select one to run:
[1] hello
[2] hello2
Enter number:
Enter 2 and catch the Second File string in the console. Besides sbt, Intellij IDEA sees main classes and renders a run button near them:
Conclusion
This topic shows how to use sbt to create and run more complicated projects than can be written and executed by REPL. You learned how to configure some basic settings to build a project and run it. You also learned to deal with a Scala project's library dependencies.