I'm trying to define a multi-project build with a consequent number of subprojects:
.
├── build.sbt
├── project/
│ ├── dependencies.scala
│ ├── tasks.scala
│ └── settings.scala
├── lib_1/
│ └── src/
├── ...
└── lib_n/
└── src/
Those subprojects are currently defined in build.sbt:
val outputJarFolder = "/some/path/"
lazy val comonSettings = /* ... */
lazy val lib_1 = (project in file ("lib1")).settings(
name:="LibOne",
commonSettings,
libraryDependencies ++= Seq(scalaTest, jsonLib, scalaXML, commonsIo),
Compile/packageBin/artifactPath := file(outputJarFolder + "lib1.jar")
)
// ... more libs ...
lazy val lib_n = (project in file ("libn")).settings(
name:="LibLast",
commonSettings,
Compile/packageBin/artifactPath := file(outputJarFolder + "libn.jar")
)
.depensOn(lib_2, lib_12)
How can I define those subprojects in another file than build.sbt in order to "unclog" that file? I want to still be able to define them in their lexicographic order (so lazy is a must). I'm working with sbt version 1.2.8 and scala 2.10.
I've tried:
Putting the declaration of those lib_k variables in a scala file and importing it --> sbt says: "classes cannot be lazy".
Putting those declaration in an object (or in a class and instantiate it in build.sbt) --> sbt projects doesn't list any subproject.
sbt documentation mentions it, but doesn't emphasize too much (perhaps to avoid encouragement for too much variation in how builds are defined in the absence of a common convention):
The build definition is described in build.sbt (actually any files named *.sbt) in the project’s base directory.
So you can split your build.sbt file into several separate .sbt files in the root of the project with different names.
I also recommend reading documentation on Organizing the build.
Related
Im trying to implement the simple server-client application using scalaPB's official example. The scala code is found on their gitHub
However, when I try to run it, I keep getting the error object helloworld is not a member of package io.grpc.examples.helloworld when I try to import anything using import io.grpc.examples.helloworld.helloworld.{foo}.
My build.sbt file:
name := "Distributed sorting"
version := "0.1"
scalaVersion := "2.13.7"
libraryDependencies ++= Seq(
"io.grpc" % "grpc-netty" % scalapb.compiler.Version.grpcJavaVersion,
"com.thesamet.scalapb" %% "scalapb-runtime-grpc" % scalapb.compiler.Version.scalapbVersion
)
Compile / PB.targets := Seq(
scalapb.gen() -> (Compile / sourceManaged).value / "scalapb"
)
My files look like this:
├── build.sbt
├── project
│ ├── build.properties
│ ├── scalapb.sbt
│ └── target
├── ...
└── src/main
├── protobuf
├── hello.proto
└── scala/io/grpc/examples/helloworld
├── HelloWorldClient.scala
└── HelloWorldServer.scala
Firstly, I recommend using Akka gRPC rather than using ScalaPB directly. The documentation is pretty clear and there is a giter8 config that can be used to create a sample project using sbt new.
Secondly, the code in that gitHub does not look like official sample code. It says it has been "translated from grpc java" which is probably not what you want.
Finally, on the specific issue you are seeing, the stubs generated by scalaPB are in a package whose name is given in the proto file. The example file has
package com.example.protos
So the stubs will be in com.example.protos.Greeter.
I have package structure similar to below;
myapplication/
├── my-library/
│ └── src
│ └──main
│ └── scala
│
├── my-other-library/
│ └── src/
│ └──main/
│ └── scala/
│── my-executable-project/
│ │── src/
│ │ └──main/
│ │ └── scala/
│ └── resources/
│ └── somefile.txt
└── build.sbt
When I run the tests via sbt or intellij;
relative files (e.g. new File("build.sbt")) being relative to myapplication.
When I run the project with reStart via sbt-revolver or from the binary;
my-executable-project is being the working directory. So to access same build.sbt file I should be using new File("../build.sbt")
This project structure make sense to me because there may be other executable projects later. I prefer keeping every project under the parent one.
Only my-executable-project is being packaged and run in the production. And when it runs there again my-executable-project is being the working directory.
The only inconvenience right now is when I want to reference to a relative file it is different in tests and regular runs.
I overcome resource loading with the usage of classpath and classloader but couldn't find a way for relative file references. When app runs tests fail, when tests run app fails.
Edit: This is how my one and only build.sbt looks like;
lazy val root = project
.in(file("."))
.disablePlugins(RevolverPlugin)
.aggregate(library1, library2, service, common)
.settings(
settings,
name := "parent",
version := "0.1"
)
lazy val common = project
.in(file("common"))
.disablePlugins(RevolverPlugin)
.settings(
settings,
name := "common",
libraryDependencies ++= ... some deps ...
)
lazy val library1 = project
.in(file("library1"))
.disablePlugins(RevolverPlugin)
.dependsOn(common)
.settings(
settings,
name := "library1",
libraryDependencies ++= ... some deps ...
)
lazy val library2 = project
.in(file("library2"))
.disablePlugins(RevolverPlugin)
.dependsOn(common)
.settings(
settings,
name := "library2",
libraryDependencies ++= ... some deps ...
)
lazy val service = project
.in(file("service1"))
.dependsOn(library1, library2)
.enablePlugins(JavaServerAppPackaging)
.settings(
settings,
name := "service1",
mappings in Universal ++= directory("service1/src/main/resources"),
mainClass in Compile := Some("my.main.class.service.Main"),
Revolver.enableDebugging(port = 5005, suspend = false),
libraryDependencies ++= ... some deps ...
)
I solved these issues putting all sbt stuff in the parent project.
See here the docu: https://www.scala-sbt.org/1.x/docs/Multi-Project.html
The main structure of build.sbt looks then:
lazy val root = (project in file("."))
.aggregate(util, core)
lazy val util = (project in file("util"))
lazy val core = (project in file("core"))
Every project can then be configured like:
lazy val core = (project in file("core"))
.enablePlugins(PlayScala, BuildInfoPlugin)
.settings(generalConf.noPublishSettings)
.settings(generalConf.buildInfoSettings)
.settings(coreConf.settings)
Here you see that we use general configs generalConf and special project config (coreConf). These files are then in the /project folder.
I am learning Scala with this coursera course task here that provides SBT file. I download its objsets.zip here. Then I unzip it end and enter into it and type sbt and then console. I try to load the file src/main/scala/objsets/TweetSet.scala on commandline but I am getting a lot of errors.
scala> :load src/main/scala/objsets/TweetSet.scala
Loading src/main/scala/objsets/TweetSet.scala...
<console>:1: error: illegal start of definition
package objsets
^
<console>:10: error: not found: value TweetReader
import TweetReader._
^
import common._
defined class Tweet
<console>:2: error: illegal start of statement (no modifiers allowed here)
override def toString: String =
^
the course uses Eclipse Scala IDE but I would like to learn to use Vim for Scala development, my favorite editor. I find Eclipse hard to use. So
How can I load the scala files in the scala interpreter on the commandline under SBT? Does there exist some favourable tools for developing the scala project on a text editor such as Vim without having to leave the editor or commandline themselves?
SBT files and the directory looks like this
$ tree src/
src/
├── main
│ └── scala
│ ├── common
│ │ └── package.scala
│ └── objsets
│ ├── TweetData.scala
│ ├── TweetReader.scala
│ ├── TweetSet.scala
│ └── testing.sc
└── test
└── scala
└── objsets
└── TweetSetSuite.scala
7 directories, 6 files
$ cat build.sbt assignment.sbt
name := course.value + "-" + assignment.value
scalaVersion := "2.11.7"
scalacOptions ++= Seq("-deprecation")
// grading libraries
libraryDependencies += "junit" % "junit" % "4.10" % Test
// for funsets
libraryDependencies += "org.scala-lang.modules" %% "scala-parser-combinators" % "1.0.4"
// include the common dir
commonSourcePackages += "common"
courseId := "bRPXgjY9EeW6RApRXdjJPw"
course := "progfun1"
assignment := "objsets"
assignmentInfo := AssignmentInfo(
key = "6PTXvD99EeWAiCIAC7Pj9w",
itemId = "d1FGp",
premiumItemId = Some("Ogg05"),
partId = "7hlkb",
styleSheet = Some((_: File) / "scalastyle" / "scalastyle_config.xml")
)
:load copies the contents of a file into the REPL line by line. That means that you end up trying to define a package (which is not allowed in the REPL), and then you try to import things that aren't visible, etc. If you use :load on a file that has a format useable by the REPL, it will work. In most cases, this means replacing the package line(s) with imports.
There's no need to use :load anyway. sbt console will place you in a REPL that has the project on its classpath. sbt consoleQuick will place you in a REPL that only has the dependencies on the classpath.
For your second question, you are meant to use sbt as a background process. In your terminal emulator, you'll have one tab running vim on your files, and in the other tab, you'll have sbt. In the tab with sbt, you can run ~compile, which recompiles your code every time you save a file in Vim. This replicates how IDEs show compiler errors/warnings as you type.
How can I accumulate all the discoveredMainClasses of a project, along with its dependent sub projects in SBT?
For example, I have a project that looks like
├── bar
│ └── src
│ └── main
│ └── scala
│ └── BarMain.scala
├── build.sbt
├── foo
│ └── src
│ └── main
│ └── scala
│ └── FooMain.scala
├── project
│ └── build.properties
└── root
With one root project that aggregate(foo, bar), I get the following for discoveredMainClasses:
[info] foo/compile:discoveredMainClasses
[info] List(MainFoo)
[info] bar/compile:discoveredMainClasses
[info] List(MainBar)
[info] root/compile:discoveredMainClasses
[info] List()
With one root that only dependsOn(foo, bar) I get
> show discoveredMainClasses
[info] *
How can I have show root/discoveredMainClasses contain both MainFoo and MainBar?
For context, I have other tasks that depend on the output from discoveredMainClasses namely the makeBashScripts in native-packager
The core idea is to create a module that depends on all all the sub modules you want to include and configure all settings on this module.
This results in a build.sbt like this
lazy val root = project.in(file("."))
// package the root module, but not the sub modules
.enablePlugins(JavaAppPackaging)
.settings(
name := "application",
// add the discoveredMainClasses to this project
discoveredMainClasses in Compile ++= (discoveredMainClasses in (client, Compile)).value,
discoveredMainClasses in Compile ++= (discoveredMainClasses in (server, Compile)).value
)
// include these modules in the resulting package
.dependsOn(client, server)
lazy val client = project.in(file("client"))
.settings(
name := "client"
)
lazy val server = project.in(file("server"))
.settings(
name := "server"
)
The (discoveredMainClasses in (client, Compile)).value accesses the discoveredMainClasses from the client project in the Compile scope.
You can build and run your applications with
$ sbt universal:stage
$ ./target/universal/stage/bin/client-app
$ ./target/universal/stage/bin/server-app
A running example can be found here.
cheers,
Muki
An alternative way to #Muki's answer would be to define a ScopeFilter that includes everything but root and accumulate main classes that way. This has the advantage of not having to repeat client, server everywhere.
The resulting build.sbt:
lazy val allCompileButRootFilter =
ScopeFilter(inAggregates(ThisProject, includeRoot = false), inConfigurations(Compile))
lazy val root = project.in(file("."))
.aggregate(client, server)
.enablePlugins(JavaAppPackaging)
.settings(
discoveredMainClasses in Compile ++=
discoveredMainClasses.all(allCompileButRootFilter).value.flatten,
...
)
I have created a project foo_proj with Intellij (using SBT template) and added a module test_mod to it. The abbreviated directory looks like this
foo_proj
├── src
│ └── main
│ └── scala-2.11
│ └── proj_obj.scala
└── test_mod
└── src
└── tmod.scala
The contents of proj_obj.scala are:
package com.base.proj
object proj_obj {
}
If would like to be able to import this object (proj_obj) into the module file tmod.scala, but when I try import com.base.proj, it can't find it.
I am new to Scala, so if I want to use stuff from the project src directory in other project modules, how else should I be structuring things? Or is this an Intellij IDEA configuration that I need to set?
Edit
The contents of the generated build.sbt are
name := "test_proj"
version := "1.0"
scalaVersion := "2.11.6"
to enable "submodules" (aka multiproject), all you need to do is add the following to your build.sbt file (or use a scala file under project dir):
lazy val root = project in file(".")
lazy val testModule = project in file("test_mod") dependsOn(root)
also, you should change test_mod dir structure.
either drop the src dir and put all your sources under the test_mod dir,
or use the sbt convention: src/main/scala or src/test/scala.