参考ieda官方指导 、官方sbt参考手册(翻译烂)、JamesRoper,现在idea做的狠好,可以有一些功能代替sbt,只是为了开源或共享项目推荐以sbt构建定义脚本文件为主做设置,比如sbt版本在build.properties中指定就是这个考量(Note that newer sbt versions(1.0 +) will create the build.properties file automatically if it doesn't exist.),相对mvn算是进步吧。按照idea的说法,在build.sbt搞就行,idea也会以它为准。纯sbt项目以build.sbt脚本描述构建过程、用idea创建的纯scala项目(不用sbt)基本的都与之类似比如sbt子项目即idea模块,要转为sbt项目只需创建build.sbt,然后describe your whole project inside build.sbt and then re-import the project.
环境是sbt1.2.1+scala2.11(2.12可能降低性能?)、win10 WSL Ubuntu 和 Idea2018社区版,较老版本的idea2017和sbt1的兼容不太友好(其scala插件也比较老)
The Command Line Interface (CLI)
作为工具sbt有两种使用模式:一次性的批量执行模式和CLI持续交互模式sbt shell,通过类似REPL的sbt shell可以获取settings的值、 运行tasks、执行commands命令、增量编译:
1、batch mode批量模式:在项目目录下打开命令行、以sbt开头来执行命令:sbt compile
2、CLI交互模式:执行同样的编译命令还可以在idea中ctrl+shift+s打开sbt shell,输入compile.
idea中的sbt shell一键打开很便利了、查看setting执行show Key、查看Task执行inspect Key,可以执行的命令包括compile、test、clean、update(命令可以依赖于tasks and settings),执行Task:subProjectID/compile执行subProjectID项目范围上定义的的compile任务。打开一个sbt shell就是一次会话,在这一次会话中普通setting在打开时只eval一次、Task则是每次引用时执行一次,由于.sbt是脚本,有一些执行顺序问题,比如普通setting不可以依赖task,对于依赖其他setting的setting或者依赖其他task的task可以声明为lazy.
sbt项目Anatomy
目前的sbt最佳实践是以项目根路径下的build.sbt脚本为核心构建,.scala构建定义文件仅仅为它服务。build.sbt脚本中典型的setting包括organization、name、version以及scalaVersion(如果不声明则默认为sbt使用的版本),如果你准备将你的项目打包成一个 jar 包,则至少要给 name 和 version 赋值。在project子目录下写scala文件也可以表达构建,在多模块项目构建中,为了避免多个.sbt的存在引入过多的繁琐,才会只用.scala形式的build定义。.sbt和.scala二者之间的settings可互相访问, .scala中的内容可以被import到.sbt中,而.sbt中的settings会被默认添加到.scala的settings当中。默认情况下,.sbt中的settings必须设置到Project级别的Scope,除非明确指定Scope; .scala中则可以将settings纳入Build级别的Scope,也可以纳入Project级别的Scope。.sbt脚本基本相当如下.scala
import sbt._ //默认导入
import Keys._
object MyBuild extends
Build
{
val helloSbt = project.in(file("."))
.settings(Seq(
organization := "org.example", //都是sbt.Keys内置settings key
name := "hello-sbt",
version := "1.0.0-SNAPSHOT",
scalaVersion := "2.10.3",
scalacOptions += "-deprecation",
libraryDependencies ++= Seq(...
))
}
0.13之前的.scala是唯一支持multi-project构建定义的方式、之后增加了multi-project .sbt build definition。
project子目录下的build.properties指定sbt版本、在plugins.sbt中使用addSbtPlugin方法添加插件。
.sbt里面可以写statements语句和expressions表达式,statement语句不返回值:val foo = "bar"
表达式会返回值如:5 + 4,总之和scala类似,赋值语句和纯函数调用就是statements语句、其他大部分都是会返回值的表达式。
依赖图
sbt依赖管理即:在.sbt中定义scalaVersion以及libraryDependencies列表ModuleID,sbt的依赖管理系统自动会下载所有直接依赖以及传递依赖JAR.
As the number of the nodes increases, the time it takes to resolve dependencies grows significantly (This is caused by sbt dependency resolver resolving version conflicts, evaluating exclusion rules and override rules transitively). The slow resolution is exacerbated for builds with many subprojects as the resolution process is repeated for each subprojects.
从2014年的0.13.7版本开始加入了LinkedIn的类似增量编译的cached resolution增量解析技术(incrementally resolve the dependency graph.)可以辅助提速:cached resolution feature creates minigraphs for each direct dependency. These minigraphs are resolved using the stock dependency resolver based on Ivy, and the result is stored locally under ~/.sbt/0.13/dependency/and shared across all builds. 参考:the documentation on cached resolution
在build.sbt设置 updateOptions 可以打开cached resolution:
updateOptions := updateOptions.value.withCachedResolution(true)
排斥警告Eviction warnings
依赖图越来越大,一个常见问题是版本冲突问题
这种情况下会采用较新版本,这种处理方式叫Eviction,1.6.6被1.7.5排斥了。冲突的版本如果是二进制兼容的,排斥就没什么问题,但是,对于二进制不兼容库依赖的排斥就会有问题,比如你的代码使用了v1.1版本API的某个方法,但这个方法在v2.0删除了。从sbt 0.13.6开始,sbt会对这种二进制不兼容的排斥情况发出警告:
[warn] There may be incompatibilities among your library dependencies.
[warn] Here are some of the libraries that were evicted:
[warn] * com.typesafe.akka:akka-actor_2.10:2.1.4 -> 2.3.7
[warn] Run 'evicted' to see detailed eviction warnings
我们可以手动再现这种情况:同时依赖banana-rdf 0.4 和 Akka Actor 2.3.7. 这是由于Akka 2.1.x 和 2.3.x 二进制不兼容,我们只能做如下work around:
1、升级到较新版本:使用show update、找出冲突版本的调用者,查看有没有库的较新版本可以免除冲突;
2、降级到较老版本:使用dependencyOverrides to override the dependency graph transitively.
3、发布本地分支:Consult software license for requirements.
无法解析依赖Unresolved dependencies error
传递依赖找不到:
::::::::::::::::::::::::::::::::::::::::::::::
[warn] :: UNRESOLVED DEPENDENCIES ::
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn] :: foundrylogic.vpp#vpp;2.2.1: not found
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn] Note: Unresolved dependencies path:
[warn] foundrylogic.vpp:vpp:2.2.1
[warn] +- org.apache.cayenne:cayenne-tools:3.0.2
[warn] +- org.apache.cayenne.plugins:maven-cayenne-plugin:3.0.2 (/foo/build.sbt#L25)
有问题的依赖是maven-cayenne-plugin 3.0.2,位于build.sbt的第25行。可以添加合适的解析器resolver来解决,或者排除传递依赖,参考:Library Management.
顺便发现了WSL有意思的一个特性,在win10上用msi win installer方式安装的工具软件比如scala、sbt,在WSL里竟然顺便也配好了,sbt装好以后path也有了什么launch启动脚本都带了,win10安装的scala在WSL查看whereis scala显示:
scala: /mnt/c/Java/scala/bin/scala /mnt/c/Java/scala/bin/scala.bat
说明WSL会包含进来可用的win10 的系统path,win10下安装的java8、Git是exe安装,在WSL下查看whereis java竟然也有但是没用。java8还是得装:sudo apt-get install openjdk-8-jre(apt install openjdk-8-jre-headless),win10下安装的java8一样得自己手动配置path. 目前idea的scala插件带lightbend的TechHub/project starter有很多简单示例可供学习,老版本idea里的则还有可能是旧的activator,不要用了。
sbt最大特点是可以用scala代码去定义项目构建过程,也就是说你的项目的构建这件事本身也可以作为一个项目来“开发”,只能说当前项目构建的复杂度已经是配置文件搞不定的了。sbt构建定义力求是portable也就是可分发的、无论是涉及上千人的开源还是十几个人的本地项目这都很有价值。其次是支持子项目模块化(build.sbt可以定义子项目),这里的sbt子项目就是idea模块,与idea中的module模块一一对应,module模块又基本对应idea中的构件artifact(is an assembly of your project assets that you put together to test, deploy or distribute your software solution or its part. Examples are a collection of compiled Java classes or a jar, a Web application as a directory structure or a war, etc.),在项目根目录下执行sbt可以进入交互式sbt shell,执行命令console还可以进一步打开scala repl,它会在启动控制台前先编译你的工程代码,包含你项目所有依赖,你可以用来直接进行简单测试(有种叠屋架床的感觉)和一般的scala REPL一样:quit返回到sbt。项目根目录也叫base directory基础目录. 对win10下的GP项目来说就是这个目录:C:\Users\name\IdeaProjects\incubator-gearpump.
sbt的源码目录结构和mvn一样,小项目里也可以直接将源码*.scala放在项目根目录下,构建定义则写在build.sbt,它比较简单不能支持scala的对象和类只能写一行一行的DSL,所以在基础目录下还会有一个project子目录即元构建,比如GP项目,在基础目录下执行sbt(不带参数)会进入交互式的sbt shell,输出:
Loading project definition from C:\Users\name\IdeaProjects\incubator-gearpump\project
/project包含的*.scala就是构建文件了,按照官方说法:“.sbt builds can be supplemented with project/*.scala files. When the build file gets large enough, the first thing to factor out are resolvers and dependencies”,如果.sbt内容太多太杂了,可以抽取为.scala分类存放
除了交互式shell,还有传统的“批处理”模式用于直接执行多个串联sbt命令,以空格分隔,需要传参的命令及其参数用双引号括起来:
$ sbt clean compile "testOnly TestA TestB"
构建定义
1、构建定义是一系列键值对:
三种Key:
1) SettingKey[T],静态配置;
2) TaskKey[T]任务、命令即clean compile test run package console reload help这些,每次执行都是重新执行;
3) InputKey[T]输入,可以接收命令行参数的任务;
key:=value表达式的单参数运算符“:=”是给一个setting赋一个字符串值或者给一个task赋一个闭包。键key的 := 方法会返回一个Setting.
中文官方指导翻译太烂不可忍,翻译工作涉及信达雅三层,信比如讲到构建定义的二种风格、一种是多项目构建另一种是bare.sbt......直接蒙圈,实际上在英文原版当中出现的Bare .sbt本意是指“原始”的.sbt定义文件,sbt文件叫什么都可以而且可以有多个,只是一般默认是build.sbt. 英语技术文档当中,陈述语句和IT专用用语都是英文,翻译还是得弄清楚哪些词汇需要翻译哪些不用,Bare .sbt中间是有空格的,所以Bare宜翻译过来,极客学院好一点;第二层是达:对于新手来说难的可能算是语序问题,直译过来的英文即使用词用语都对了,它的语序也会让你感觉及其别扭,基本得三五句联合起来理解才行;第三层就是雅:涉及文学作品翻译的,只能吃透了揉碎了,领会了它的意境,再用汉语重新表达出来,相当于重新创作了,在英语语言文学和汉语语言文学两方面都得有深厚积累才行。
这篇文章,Akka项目向导工具Aviator/activator一年前就EOF了,截止到到2017,代之以基于sbt 1.0的Tech Hub
文章大意就是Akka工具开发组重新审视了创建activator的初衷,这种东西是下载的、可能工作在各种环境上的,activator过度复杂了,Activator本质上是对sbt命令的一个包装。大家需要的只是一个好用快速上手的getting started工具,可以快速体验一个helloWorld,更重要的是,sbt变得更好了,它的DSL更好用、安装更方便。用Giter8模板方式给用户提供Tutorials更好。Giter8模板要么提交到你自己公司的Git要么提交到github.
Giter8是Nathan Hamblin创建,它使用GitHub作为仓库提供各种模板,这样只要是github用户都可以创建自己的模板。sbt已经和Giter8集成了,所以只要输入命令:"sbt new"跟上你的仓库名,就能快速创建原型,也就是说用命令行你也可以快速开始一个项目。Tech Hub同样和Giter8集成了,如果你对sbt很熟悉,也可以直接“sbt new”
使用Tech Hub的方法是在idea中新建scala项目、选择lightbend project stater:sbt-based project from a Lightbend Tech Hub template
关于sbt 1.0:随着Scala 2.12发布,sbt从0.13到1变化较大,这俩要配套外加Akka2.5
olderSky一月份的Sbt baby steps:
idea官方建议:We recommend that you switch to Java 8 SDK since the Scala version 2.12, and sbt versions 1.1 and later are not compatible with older Java SDK versions.
sbt国内更新源问题,总之就是oschina不能用了,至少阿里还能用。关于代理仓库sbt Reference Manual — Proxy Repositories,Resolvers是在代码中解析仓库的实例,有两种一种是预定义的一堆可以看一下sbt官方resolvers,另一种是自定义的最常用的是:resolvers+="Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots"。代理仓库的作用:
阿里就是一个代理仓库,sbt要用起来代理仓库需要配置最常用的就是~/.sbt/repositories了,sbt.override.build.repos配置用于指定优先采用repositories、其次才是sbt项目当中代码添加的resolvers. 相同项前者会覆盖后者,这样有了这么一个配置文件就能保证优先采用的代理仓库:-Dsbt.override.build.repos=true,默认是false要打开必须指定。
我的sbt repo文件:
[repositories]
local
aliyun-nexus: http://maven.aliyun.com/nexus/content/groups/public/
Central-repository: http://central.maven.org/maven2/
ibiblio-maven: http://maven.ibiblio.org/maven2/ #这个似乎有用
typesafe: http://repo.typesafe.com/typesafe/ivy-releases/, [organization]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)[revision]/[type]s/[artifact](-[classifier]).[ext], bootOnly
#这一个连接到http://dl.bintray.com/typesafe/ivy-releases/,sbt0.13.7位于:org.scala-sbt/sbt/
uk-repository: http://uk.maven.org/maven2/
jboss-repository: http://repository.jboss.org/nexus/content/groups/public/
repo1: http://repo1.maven.org/maven2/
repo2: http://repo2.maven.org/maven2/
sonatype-oss-releases
maven-central
sonatype-oss-snapshots
https://www.cnblogs.com/superjt/archive/2013/07/16/3192945.html