ハードウェアの気になるあれこれ

技術的に興味のあることを調べて書いてくブログ。主にハードウェアがネタ。

sbtの変数&タスク定義について

スポンサーリンク

2021年になって、早半年(´゚д゚`)

なんか知らぬ間に時間が経っていきますね。。。。 謎に落ちていたモチベーションも戻ってきつつあるので、またゴニョゴニョ活動してる内容をブログにしていこうと思います。 という事で、Chiselで使っているsbtについて、気になったことを試してみた内容を。

sbtの設定ファイルbuild.sbt

Chiselを使うに当たって、普段はchisel-templatebuild.sbtを修正して使うこと多く、理解が曖昧だった。そのため、chisel-templatebuild.sbtを例に、少し中身を見ておく。

今のchisel-tamplateはこんな感じ。

// See README.md for license details.

ThisBuild / scalaVersion     := "2.12.13"
ThisBuild / version          := "0.1.0"
ThisBuild / organization     := "%ORGANIZATION%"

lazy val root = (project in file("."))
  .settings(
    name := "%NAME%",
    libraryDependencies ++= Seq(
      "edu.berkeley.cs" %% "chisel3" % "3.4.3",
      "edu.berkeley.cs" %% "chiseltest" % "0.3.3" % "test"
    ),
    scalacOptions ++= Seq(
      "-Xsource:2.11",
      "-language:reflectiveCalls",
      "-deprecation",
      "-feature",
      "-Xcheckinit",
      // Enables autoclonetype2 in 3.4.x (on by default in 3.5)
      "-P:chiselplugin:useBundlePlugin"
    ),
    addCompilerPlugin("edu.berkeley.cs" % "chisel3-plugin" % "3.4.3" cross CrossVersion.full),
    addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full)
  )

最初に使ったchisel-templateの内容からすると、ずいぶんスッキリしたな。 でも、やってる事は何となくわかっても、細かい部分は理解できてないことが多い。例えばThisBuildの意味するところとは?とか。

ThisBuild

sbtのマニュアルに、ThisBuildは"「プロジェクト全体」を表す値に設定することができ"という記述がある。またこれを使った例として、次のような例が記載されていた。

説明としては「サブプロジェクト間に共通なセッティングを一度に定義するため」となっている。

簡単に試してみたのが、次の例だ。

ThisBuild / version          := "0.1.0"

lazy val root = (project in file("."))
  .settings(
    name := "sbt-study",
    version := "1.0.0"
  )

lazy val sub = (project in file("./sub"))
  .settings(
    name := "sbt-study-sub",
  )

上記例でrootの方はversionを明示的に1.0.0に変更している。これをsbt上で確認すると次のようになった。

sbt:sbt-study> root/version
[info] 1.0.0
sbt:sbt-study> sub/version
[info] 0.1.0

ThisBuildに固有の設定を追加する

先の例であったvesionなどは、デフォルトで定義済みの値になる。プロジェクト固有の共通設定を増やしたい場合にはsettingKeyを使って、値を定義しておけばOKなようだ。

// See README.md for license details.

lazy val mySetting = settingKey[String]("hoge")

ThisBuild / mySetting := "hoge"

lazy val root = (project in file("."))
  .settings(
    name := "sbt-study",
  )

lazy val sub = (project in file("./sub"))
  .settings(
    name := "sbt-study-sub",
  )

rootmySettingThisBuildの設定と一致していることが確認できた。

sbt:sbt-study> ThisBuild/mySetting
[info] hoge
sbt:sbt-study> root/mySetting
[info] hoge
sbt:sbt-study> sub/mySetting
[info] fuga

タスクの定義

で、こっちが元々気になった事。ビルドシステムで必要になる、タスクの定義とその依存関係をどうやって定義すればいいのか?という事を確認した。

まずはタスクの定義だが、先ほど使ったsettingKeyと似たtaskKeyを使って、タスク用の変数を作成し、それに実装を与えればOKだ。

この辺はマニュアルの以下に記載されている。

// 自前タスク用の変数定義
lazy val hello = taskKey[Unit]("say hello")

// タスクの実装
hello := {
  println("Hello!")
}

実行する場合は、sbtのコンソールでタスク用の変数名をそのまま実行すればOK

sbt:sbt-study> hello
Hello!
[success] Total time: 0 s, completed 2021/07/04 22:39:24

タスクの依存関係の定義

タスクの実行に当たって、タスク間で実行する順番を定義したい場合がある。 このような場合には、次のようにして依存するタスクを登録しておけばOK。

ここでは、testコマンドの実行前に、自分で定義したhelloタスクを実行している。

lazy val hello = taskKey[Unit]("say hello")

hello := println("Hello!")
test := hello.value

実行すると次のようになる。

sbt:sbt_study> test
Hello!
[success] Total time: 0 s, completed 2021/07/04 22:47:37

複数の定義に依存する場合は、次のようにブロック式内に依存するタスクを並べればOK。

lazy val hello = taskKey[Unit]("say hello")
lazy val helloB = taskKey[Unit]("say hello")

hello := println("Hello!")
helloB := println("Hello!!")
test := {
  hello.value
  helloB.value
}

これでsbtを使って少し凝ったビルドの処理が出来そう。