すずけんメモ

技術メモです

sbtについて調べた

scalaを書くにあたってsbtを使う必要があったのでまとめておく。公式ドキュメントは以下にある。

Contents sbt Documentation http://www.scala-sbt.org/release/docs/index.html

公式ドキュメントをみつつ、sbtのセットアップ方法をまとめておく。環境は以下のとおり。

% uname -a
Darwin HOST 12.4.0 Darwin Kernel Version 12.4.0: Wed May  1 17:57:12 PDT 2013; root:xnu-2050.24.15~1/RELEASE_X86_64 x86_64

% system_profiler SPSoftwareDataType | grep "System Version"
      System Version: OS X 10.8.4 (12E55)

% brew --version
0.9.4

% scala -version
Scala code runner version 2.9.2 -- Copyright 2002-2011, LAMP/EPFL

セットアップ方法

まずインストール

% brew install sbt

とりあえず作業ディレクトリを/tmp/sbt_testとした。バージョンをみるにはsbt about

% sbt about
[info] Set current project to default-cf6087 (in build file:/private/tmp/sbt_test/)
[info] This is sbt 0.11.3
[info] The current project is {file:/private/tmp/sbt_test/}default-cf6087
[info] The current project is built against Scala 2.9.1
[info] sbt, sbt plugins, and build definitions are using Scala 2.9.1

こんな感じのファイルをhw.scalaとして配置しておく。

object Hi {
      def main(args: Array[String]) = println("Hi!")
}

sbtでコンソールを開き、runするとビルドできる。Hi!と出力されているのが確認できる。

% pwd
/tmp/sbt_test
% ls
hw.scala
% sbt
[info] Set current project to default-cf6087 (in build file:/private/tmp/sbt_test/)
> run
[info] Updating {file:/private/tmp/sbt_test/}default-cf6087...
[info] Resolving org.scala-lang#scala-library;2.9.1 ...
[info] Done updating.
[info] Compiling 1 Scala source to /private/tmp/sbt_test/target/scala-2.9.1/classes...
[info] Running Hi
Hi!
[success] Total time: 4 s, completed 2013/08/01 10:18:49
>

設定

設定情報はbuild.sbtに書く。設定の書き方は以下に載っている。

.sbt Build Definition — sbt Documentation http://www.scala-sbt.org/release/docs/Getting-Started/Basic-Def.html

試しに以下のようにbuild.sbtを書いた

name := "hello"

version := "1.0"

scalaVersion := "2.9.1"

これを/tmp/sbt_test/build.sbtに配置して、sbtする。

% sbt
[info] Set current project to hello (in build file:/private/tmp/sbt_test/)
> run
[info] Updating {file:/private/tmp/sbt_test/}default-cf6087...
[info] Resolving org.scala-lang#scala-library;2.9.1 ...
[info] Done updating.
[info] Running Hi
Hi!
[success] Total time: 1 s, completed 2013/08/01 10:32:04
% ls
build.sbt hw.scala  project   target

するとprojectディレクトリが作成される。sbt関連のランチャーっぽいものが生成されているようだ。

% tree project
project
└── target
    └── config-classes
        ├── $81beed32fd363d86c9c3$$anonfun$$sbtdef$1.class
        ├── $81beed32fd363d86c9c3$.class
        ├── $81beed32fd363d86c9c3.class
        ├── $f0b4b64e830dcd216535$$anonfun$$sbtdef$1.class
        ├── $f0b4b64e830dcd216535$.class
        ├── $f0b4b64e830dcd216535.class
        ├── $fc2285516a79659283ee$$anonfun$$sbtdef$1.class
        ├── $fc2285516a79659283ee$.class
        └── $fc2285516a79659283ee.class

2 directories, 9 files
% javap project.target.config-classes.\$81beed32fd363d86c9c3
Warning: Binary file project.target.config-classes.$81beed32fd363d86c9c3 contains $81beed32fd363d86c9c3
Compiled from "/private/tmp/sbt_test/build.sbt"
public final class $81beed32fd363d86c9c3 {
  public static final sbt.Init<sbt.Scope>.SettingsDefinition $sbtdef();
}

実際のディレクトリ構造

Directory structure — sbt Documentation http://www.scala-sbt.org/release/docs/Getting-Started/Directories.html

実際にはMavenなどと同様のディレクトリ構造にする。

sbtのインタラクティブモードについて

sbtでインタラクティブモードを起動できる。

% sbt
[info] Set current project to hello (in build file:/private/tmp/sbt_test/)
> help

  help command*               Displays this help message or prints detailed help on requested commands.
  about                       Displays basic information about sbt and the build.
  reboot [full]               Reboots sbt and then executes the remaining commands.
  < file*                     Reads command lines from the provided files.
  !!                          Execute the last command again
  !:                          Show all previous commands
  !:n                         Show the last n commands
  !n                          Execute the command with index n, as shown by the !: command
  !-n                         Execute the nth command before this one
  !string                     Execute the most recent command starting with 'string'
  !?string                    Execute the most recent command containing 'string'
  ~ <command>                 Executes the specified command whenever source files change.
  exit                        Terminates the build.
  reload                      Loads the project in the current directory
  projects                    Displays the names of available projects.
  project [project]           Displays the current project or changes to the provided `project`.
  - command                   Registers 'command' to run if a command fails.
  iflast command              If there are no more commands after this one, 'command' is run.
  ( ; command )+              Runs the provided semicolon-separated commands.
  shell                       Provides an interactive prompt from which commands can be run.
  set <setting-expression>    Evaluates the given Setting and applies to the current project.
  tasks                       Displays the tasks defined for the current project.
  inspect <key>               Prints the value for 'key', the defining scope, delegates, related definitions, and dependencies.
  eval <expression>           Evaluates the given Scala expression and prints the result and type.
  alias                       Adds, removes, or prints command aliases.
  append command              Appends `command` to list of commands to run.
  last <key>                  Prints the last output associated with 'key'.
  last-grep <pattern> <key>   Shows lines from the last output for 'key' that match 'pattern'.
  session ...                 Manipulates session settings.  For details, run 'help session'..
  show <key>                  Displays the result of evaluating the setting or task associated with 'key'.

便利そうなのが、継続的にビルドする機能。~ compileするだけ。これでソースの変更を見はってくれる。watchrとか使うより手軽でよい。

> ~ compile
[success] Total time: 0 s, completed 2013/08/01 10:45:44
1. Waiting for source changes... (press enter to interrupt)

実行のトリガについてはここにまとめてのってる。テストだけ継続的に実行することもできる。

Triggered Execution — sbt Documentation http://www.scala-sbt.org/release/docs/Detailed-Topics/Triggered-Execution.html

外部ライブラリの読み込み

再び設定の話。せっかくだからMavenではなくてsbtに統一したいところ。.sbt Build Definitionによると、build.sbtに以下のように書けばよい。

libraryDependencies += "org.apache.derby" % "derby" % "10.4.1.3"

ライブラリの依存関係については以下に書かれている。

Library Dependencies — sbt Documentation http://www.scala-sbt.org/release/docs/Getting-Started/Library-Dependencies.html

このlibraryDependenciesの書式は以下の様なルールに基づいている。%をつかうのはApache Ivyの流儀らしい。

libraryDependencies += groupID % artifactID % revision % configuration

まとめて書きたいなら以下のようにもできる。

libraryDependencies ++= Seq(
    groupID % artifactID % revision,
    groupID % otherID % otherRevision
)

scalaのバージョンなどについては%%表記すれば設定値から渡せるらしい。

libraryDependencies += "org.scala-tools" % "scala-stm_2.9.1" % "0.3"

とあるものを、

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

書いておけば、build.sbt内のscalaVersionから設定値を当てはめてくれるようになっている。もし複数のScalaバージョンにまたがるリリースを行いたい場合にはCross-Buildingの設定をするといいらしい。

Cross-building — sbt Documentation http://www.scala-sbt.org/release/docs/Detailed-Topics/Cross-Build.html

また、テスト用にだけ使いたい依存ライブラリについてはtestconfigurationに設定するとよい。

libraryDependencies += "org.apache.derby" % "derby" % "10.4.1.3" % "test"

こうするとTestの時についてのみclasspathに設定されるようになっている。

Mavenを併用したい場合には、外部設定として読みこむようにもできる。

Library Management — sbt Documentation http://www.scala-sbt.org/release/docs/Detailed-Topics/Library-Management.html

以下のようにする。

externalPom()

or

externalPom(baseDirectory(_ / "custom-name.xml"))

これにより依存関係のみMavenで管理することもできる。ただし、sbtはIvyをベースに作られているので、IvyがサポートしていないPOMは利用できないという制限がある。