What is sbt?


A build tool for Scala (and Java)

  • whenMark HarrahWhen the SBT was created, it was called “Simple Build Tool”
  • But when it was first announced publicly, the namesbtIt doesn’t stand for anything, it’s just “SBT”, that’s how it should be written[1]

Other options of Scala build tool

  • Java build tools, like ant, maven, gradle
  • Mill
  • Fury
  • seed
  • CBT
  • .

Why sbt?


The most used scala build tool

  • Scala Official Recommendation
  • 93.6% Scala Developer’s Choices [2]
  • Use Scala as the DSL definition build file
  • Almost every Scala guide on the market is based onsbt
  • You can build a mix of Java and Scala projects
  • Incremental compilation (Good incremental compilation design)
  • Support for continuous compilation and testing through trigger Execution
  • Supports parallel task execution
  • Support for a large number of plug-ins
  • You can reuse Maven or Ivy’s Repository for dependency management

The sbt project structure

├─ Build.sbt ------ Build Definition File ├─ Project ------ Build Support Files │ ├─ build.properties │ ├─ Plugins. SBT │ └ ─ ─ project ├ ─ ─ the SRC │ ├ ─ ─ the main │ │ ├ ─ ─ resources │ │ └ ─ ─ scala │ └ ─ ─ the test │ ├ ─ ─ resources │ └ ─ ─ scala └ ─ ─ target ------ build products

Build Definition


Settings Expression


Introduction

{key} := {body}
Copy the code

The configuration expression consists of the following three parts:

  • The left-hand side of the operator is calledkey
  • Operators use: =said
  • The right-hand side of the operator is calledbody

Keys

  • SBT preset keys are defined in sbT. keys. All preset keys will be imported into SBT. keys 3

  • You can customize keys in the following ways

    lazy val customKey = settingKey[String] ("The custom key")
    Copy the code

Adding project description

name := "scala-demo-project"
organization := "com.shuailli.demo"
version := "0.1.0 from - the SNAPSHOT"
scalaVersion := "2.13.5"
Copy the code

Adding library dependencies

// define libs version
val http4sVersion = "0.21.29"
val specs2Version = "4.11.0"
Copy the code
libraryDependencies ++= Seq(
  "org.http4s"% %"http4s-dsl" % http4sVersion,
  "org.http4s"% %"http4s-blaze-client" % http4sVersion,
  "org.http4s"% %"http4s-circe" % http4sVersion,
  "org.specs2"% %"specs2-core" % specs2Version % "test".)Copy the code

Tips

  • Scala’s primary and secondary versions have very different features, so many liBs are compiled to multiple Scala version visible examples

  • Get the appropriate Scala version of lib using the %% method to make sure that lib is binary compatible for your project

    GroupID % artifactID % Revision If you use groupID %% artifactID % Revision instead of groupID % artifactID % Revision, SBT adds the Scala version number of the project to the lib name. It’s just a quick fix. You can write instead of %%:

libraryDependencies += "org.scala-tools" % "Scala - stm_2. 11" % "0.3"
Copy the code

Given that the scalaVersion of this build is 2.11.1, the following approach is equivalent (note the %% after “org.scala-tools”) :

libraryDependencies += "org.scala-tools"% %"scala-stm" % "0.3"
Copy the code

Compiler Options

scalacOptions ++= Seq(
  "-encoding"."utf8".// Option and arguments on same line
  "-Xfatal-warnings".// New lines for each options
  "-deprecation"."-unchecked"."-language:implicitConversions"."-language:higherKinds"."-language:existentials"."-language:postfixOps"
)
Copy the code
  • The official full Compiler Options are visible: link

  • A copy of the recommended Compiler Options configuration is visible: links


Command Alias

addCommandAlias("checkAndTest"."; clean; scalafmtCheck; coverage; test; coverageReport; coverageOff")
Copy the code

Adding plugins

// define lib version
val kindProjectorVersion = "0.13.0"

addCompilerPlugin("org.typelevel"% %"kind-projector" % kindProjectorVersion cross CrossVersion.full)
Copy the code

Build Support Files

Any files under the project directory can be used during the build process.


Specifying the sbt version

  • useproject/build.propertiesThe file specifiedsbtversion
sbt.version = 1.4.7
Copy the code
  • If the specifiedsbtVersion does not exist locally,sbt launcherIt will be downloaded automatically for you before the build starts.
  • This feature ensures that different versions are preinstalled locallysbtThe developer produces a consistent build artifact for a build of the same project, because it will end up using the specified version of SBT

Organize plugins

  • useproject/plugins.sbtFile managementsbtThe plug-in
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.8.0 comes with")
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.6.1." ")
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.2")
Copy the code

How to run sbt?


Installation

  • Install JDK (JDK8 or JDK11 is recommended)

  • Install the SBT

// In MacOS 
$ brew install sbt
Copy the code
  • Now you can start Scala project development

  • Tips:

    • Scala differs from other languages in that major and minor versions of Scala have very different features. As a result, a specific version of Scala (build.sbt) is usually installed for each project rather than globally. _sbt_ can be used to manage a specific version of Scala for each Scala project.

    • After SBT is installed, by default, SBT builds projects using Scala corresponding to its own version


sbt Shell and common commands

  • Enter thesbtInteractive mode
$ sbt
Copy the code
  • Common commands:
> new
> clean
> compile
> test
> testOnly
> package
> console
> run
Copy the code

Batch mode

You can also run SBT in batch mode, specifying arguments with Spaces as delimiters. For SBT commands that accept arguments, the command and argument are passed to the SBT in quotes. Such as:

$ sbt clean compile "testOnly TestA TestB"
Copy the code

In this example, testOnly takes two parameters, TestA and TestB. This command is executed in order (clean, compile, then testOnly).

In batch mode, builds will run very slowly.


Continuous Build and Test

To speed up the edit-compile-test cycle, you can have SBT automatically recompile or run tests when you save your source files. Prefixed with ~, the command is automatically run whenever one or more source files change.

  • Try it in interactive mode
> ~ compile
Copy the code
> ~ run
Copy the code
> ~ testQuick
Copy the code

In interactive mode, press Enter to stop monitoring changes. Of course, the ~ prefix can be used in either interactive or batch mode.

  • Try this operation in batch mode
$ sbt '~ run'
Copy the code

In order to classify the ~ prefix (representing the current user root directory in Unix and SBT), you need to wrap the SBT command with ‘in batch mode


Common plugins


Formatter

  • inproject/plugins.sbtFile add-on plug-in
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.2")
Copy the code
  • Add the configuration file in the project root directory.scalafmt.conf
  • An example of the simplest configuration, see the official configuration description: link
Version = 2.7.5 maxColumn = 180 align = more danglingParentheses = false continuationIndent. DefnSite = 2Copy the code
  • Specify the following command to execute formatter
$ sbt scalafmt
// or
$ sbt scalafmtCheck
Copy the code

Package & Release

  • inproject/plugins.sbtFile add package plug-in (produce fat JAR package – a JAR file containing all the class files in the code and library)
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "1.0.0")
Copy the code
  • Run the following command to generate the JAR package
$ sbt package
Copy the code
  • inproject/plugins.sbtFile add package plug-in (output deployment image)
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.7.5")
Copy the code
  • Run the following command to build deployment images for different systems
$ sbt debian:packageBin   # deb package
$ sbt windows:packageBin  # msi package
$ sbt docker:publishLocal # docker image
Copy the code

Test & Coverage

  • inproject/plugins.sbtFile add-on plug-in
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.6.1." ")
Copy the code
  • inbuild.sbtFile to add test coverage configuration
coverageEnabled in Test: =true
coverageMinimum := 90
coverageFailOnMinimum := true
coverageExcludedPackages := coverageExcludedClasses.mkString(";")
Copy the code
  • To invoke coverage check, run the following commands
$ sbt coverage
// or 
$ sbt test
// or
$ sbt coverageReport
Copy the code

Scopes

I mentioned keys earlier, but you can actually assign different values to the same key in different contexts, each of which is called scope

For example, if you have multiple projects in your build definition, version can be a different value in each project.


There are three scope axes

The Scope axis is a type where each instance of the type can define its own Scope (that is, each instance’s key can have its own specific value).

  • Projects
  • Configurations
  • Tasks

Scoping by Project axis

If you have multiple projects in the same build, each project needs to have its own Settings. That is, keys can be confined to different contexts depending on the project.

When a project does not define project-level Settings, the build-level Settings are usually used as the default Settings.

  • In the following example, the build hierarchy is set using the Project axissettings
ThisBuild / scalaVersion     := "2.13.5"
ThisBuild / version          := "0.1.0 from - the SNAPSHOT"
ThisBuild / organization     := "com.shuailli.demo"
Copy the code

ThisBuild represents the build hierarchy


Scoping by Configuration axis

A Configuration defines a particular build, which may contain its own classpath, source files, generated packages, and so on.

You can see these configurations in the SBT:

  • CompileDefine the main build (SRC /main/ Scala).
  • TestDefine how tests are built (SRC /test/ Scala).
  • Runtimerun taskdefineclasspath.
  • Providecompiling tasktest taskdefineclasspath.

By default, all keys related to compilation, packaging, and running are limited to one configuration, so different configurations may have different effects. The most obvious examples are task keys: compile, package, and run; However, all other keys that can affect these keys (such as sourceDirectories, scalacOptions, and fullClasspath) are also limited to this configuration.


Scoping by Task axis

Settings can influence how a task works.

To support this feature, one Task key (such as packageSrc) can act as a scope for another key (such as packageOptions).

Some packaging-related tasks (packageSrc, packageBin, packageDoc) can share packaging-related keys, such as artifactName and packageOptions. These keys can have unique values for each packaged task.

packageSrc / packageOptions := ???
Copy the code
packageBin / packageOptions := ???
Copy the code
packageDoc / packageOptions := ???
Copy the code

Referrences

  • [1] SBT Faq, www.scala-sbt.org/release/doc…
  • [2] 2019 Scala Developer Survey, scalacenter lot. IO/Scala – devel…
  • [3] SBT Keys, www.scala-sbt.org/1.x/api/sbt…