I have multiple subprojects in my sbt, one being a server (base upon playframework) the other being the clientside (scala.js) and the third one being the communication between the two in form of protobuf (scalapb).
Now, this is my build.sbt
:
lazy val generalSettings = Seq(
organization := "tld.awesomeness",
version := "0.0.1",
scalaVersion := "2.12.1"
)
val CrossDependencies = new
{
val scalaTest = "org.scalatest" %% "scalatest" % "3.0.1" % "test"
val scalactic = "org.scalactic" %% "scalactic" % "3.0.1"
val scalaTags = "com.lihaoyi" %% "scalatags" % "0.6.2"
}
lazy val proto = (project in file("modules/proto"))
.settings(generalSettings: _*)
.settings(
PB.targets in Compile := Seq(
scalapb.gen() -> (sourceManaged in Compile).value
),
// If you need scalapb/scalapb.proto or anything from google/protobuf/*.proto
libraryDependencies ++= Seq(
"com.trueaccord.scalapb" %% "scalapb-runtime" % com.trueaccord.scalapb.compiler.Version.scalapbVersion % "protobuf",
"com.trueaccord.scalapb" %%% "scalapb-runtime" % com.trueaccord.scalapb.compiler.Version.scalapbVersion,
"com.trueaccord.scalapb" %%% "scalapb-runtime" % com.trueaccord.scalapb.compiler.Version.scalapbVersion % "protobuf"
)
)
lazy val play = (project in file("modules/play"))
.enablePlugins(PlayScala)
.settings(generalSettings: _*)
.settings(
name := "play",
libraryDependencies ++= Seq(
CrossDependencies.scalaTest,
CrossDependencies.scalactic,
CrossDependencies.scalaTags,
"com.typesafe.play" %% "play-json" % "2.6.0-M1"),
scalaJSProjects := Seq(client),
pipelineStages in Assets := Seq(scalaJSPipeline),
compile in Compile := ((compile in Compile) dependsOn scalaJSPipeline).value
)
.aggregate(slick)
.dependsOn(slick)
.aggregate(flyway)
.dependsOn(flyway)
.aggregate(proto)
.dependsOn(proto)
lazy val client = (project in file("modules/client"))
.enablePlugins(ScalaJSPlugin, ScalaJSWeb)
.settings(generalSettings: _*)
.settings(
name := "client",
libraryDependencies += CrossDependencies.scalaTags,
persistLauncher := true
)
.aggregate(proto)
.dependsOn(proto)
// Loads the jvm project at sbt startup
onLoad in Global := (Command.process("project play", _: State)) compose (onLoad in Global).value
fork in run := true
and this is the plugins.sbt
:
// Scala.JS
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.14")
addSbtPlugin("com.vmunier" % "sbt-web-scalajs" % "1.0.2")
// Play
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.6.0-SNAPSHOT")
// Proto
addSbtPlugin("com.thesamet" % "sbt-protoc" % "0.99.3" exclude ("com.trueaccord.scalapb", "protoc-bridge_2.10"))
libraryDependencies += "com.trueaccord.scalapb" %% "compilerplugin-shaded" % "0.5.47"
This is one proto
file:
syntax = "proto3";
package tld.awesomeness.proto;
message Test {
int32 id = 1;
string email = 2;
}
After compilation I get Test.class
Now in the client I try to:
private def doSend(ws: WebSocket): Unit =
{
val msg = Test().withId(1337)
val a: ArrayBuffer = new ArrayBuffer(msg.toByteArray.length)
msg.toByteArray
ws.send(a)
}
(The websocket itself worked all just fine when I sent strings through it!)
Now I get this huge stacktrace:
[info] Fast optimizing /home/sorona/awesomeness/modules/client/target/scala-2.12/client-fastopt.js
[error] Referring to non-existent class tld.awesomeness.proto.Test.Test$
[error] called from tld.awesomeness.ScalaJSTest$.doSend(org.scalajs.dom.raw.WebSocket)scala.Unit
[error] called from tld.awesomeness.ScalaJSTest$.tld$awesomeness$ScalaJSTest$$$anonfun$call$1(org.scalajs.dom.raw.Event,org.scalajs.dom.raw.WebSocket)org.scalajs.dom.raw.Event
[error] called from tld.awesomeness.ScalaJSTest$.call()scala.Unit
[error] called from tld.awesomeness.Main$.main()scala.Unit
[error] called from scala.scalajs.js.JSApp.$$js$exported$meth$main()java.lang.Object
[error] called from tld.awesomeness.Main$.$$js$exported$meth$main()java.lang.Object
[error] called from tld.awesomeness.Main$.main
[error] exported to JavaScript with @JSExport
[error] involving instantiated classes:
[error] tld.awesomeness.ScalaJSTest$
[error] tld.awesomeness.Main$
[error] Referring to non-existent class tld.awesomeness.proto.Test.Test
[error] called from tld.awesomeness.ScalaJSTest$.doSend(org.scalajs.dom.raw.WebSocket)scala.Unit
[error] called from tld.awesomeness.ScalaJSTest$.tld$awesomeness$ScalaJSTest$$$anonfun$call$1(org.scalajs.dom.raw.Event,org.scalajs.dom.raw.WebSocket)org.scalajs.dom.raw.Event
[error] called from tld.awesomeness.ScalaJSTest$.call()scala.Unit
[error] called from tld.awesomeness.Main$.main()scala.Unit
[error] called from scala.scalajs.js.JSApp.$$js$exported$meth$main()java.lang.Object
[error] called from tld.awesomeness.Main$.$$js$exported$meth$main()java.lang.Object
[error] called from tld.awesomeness.Main$.main
[error] exported to JavaScript with @JSExport
[error] involving instantiated classes:
[error] tld.awesomeness.ScalaJSTest$
[error] tld.awesomeness.Main$
[error] Referring to non-existent method tld.awesomeness.proto.Test.Test.toByteArray()[scala.Byte
[error] called from tld.awesomeness.ScalaJSTest$.doSend(org.scalajs.dom.raw.WebSocket)scala.Unit
[error] called from tld.awesomeness.ScalaJSTest$.tld$awesomeness$ScalaJSTest$$$anonfun$call$1(org.scalajs.dom.raw.Event,org.scalajs.dom.raw.WebSocket)org.scalajs.dom.raw.Event
[error] called from tld.awesomeness.ScalaJSTest$.call()scala.Unit
[error] called from tld.awesomeness.Main$.main()scala.Unit
[error] called from scala.scalajs.js.JSApp.$$js$exported$meth$main()java.lang.Object
[error] called from tld.awesomeness.Main$.$$js$exported$meth$main()java.lang.Object
[error] called from tld.awesomeness.Main$.main
[error] exported to JavaScript with @JSExport
[error] involving instantiated classes:
[error] tld.awesomeness.ScalaJSTest$
[error] tld.awesomeness.Main$
[error] Referring to non-existent method tld.awesomeness.proto.Test.Test.withId(scala.Int)tld.awesomeness.proto.Test.Test
[error] called from tld.awesomeness.ScalaJSTest$.doSend(org.scalajs.dom.raw.WebSocket)scala.Unit
[error] called from tld.awesomeness.ScalaJSTest$.tld$awesomeness$ScalaJSTest$$$anonfun$call$1(org.scalajs.dom.raw.Event,org.scalajs.dom.raw.WebSocket)org.scalajs.dom.raw.Event
[error] called from tld.awesomeness.ScalaJSTest$.call()scala.Unit
[error] called from tld.awesomeness.Main$.main()scala.Unit
[error] called from scala.scalajs.js.JSApp.$$js$exported$meth$main()java.lang.Object
[error] called from tld.awesomeness.Main$.$$js$exported$meth$main()java.lang.Object
[error] called from tld.awesomeness.Main$.main
[error] exported to JavaScript with @JSExport
[error] involving instantiated classes:
[error] tld.awesomeness.ScalaJSTest$
[error] tld.awesomeness.Main$
[error] Referring to non-existent method tld.awesomeness.proto.Test.Test$.apply$default$2()java.lang.String
[error] called from tld.awesomeness.ScalaJSTest$.doSend(org.scalajs.dom.raw.WebSocket)scala.Unit
[error] called from tld.awesomeness.ScalaJSTest$.tld$awesomeness$ScalaJSTest$$$anonfun$call$1(org.scalajs.dom.raw.Event,org.scalajs.dom.raw.WebSocket)org.scalajs.dom.raw.Event
[error] called from tld.awesomeness.ScalaJSTest$.call()scala.Unit
[error] called from tld.awesomeness.Main$.main()scala.Unit
[error] called from scala.scalajs.js.JSApp.$$js$exported$meth$main()java.lang.Object
[error] called from tld.awesomeness.Main$.$$js$exported$meth$main()java.lang.Object
[error] called from tld.awesomeness.Main$.main
[error] exported to JavaScript with @JSExport
[error] involving instantiated classes:
[error] tld.awesomeness.ScalaJSTest$
[error] tld.awesomeness.Main$
[error] Referring to non-existent method tld.awesomeness.proto.Test.Test$.apply$default$1()scala.Int
[error] called from tld.awesomeness.ScalaJSTest$.doSend(org.scalajs.dom.raw.WebSocket)scala.Unit
[error] called from tld.awesomeness.ScalaJSTest$.tld$awesomeness$ScalaJSTest$$$anonfun$call$1(org.scalajs.dom.raw.Event,org.scalajs.dom.raw.WebSocket)org.scalajs.dom.raw.Event
[error] called from tld.awesomeness.ScalaJSTest$.call()scala.Unit
[error] called from tld.awesomeness.Main$.main()scala.Unit
[error] called from scala.scalajs.js.JSApp.$$js$exported$meth$main()java.lang.Object
[error] called from tld.awesomeness.Main$.$$js$exported$meth$main()java.lang.Object
[error] called from tld.awesomeness.Main$.main
[error] exported to JavaScript with @JSExport
[error] involving instantiated classes:
[error] tld.awesomeness.ScalaJSTest$
[error] tld.awesomeness.Main$
[error] Referring to non-existent method tld.awesomeness.proto.Test.Test.<init>(scala.Int,java.lang.String)
[error] called from tld.awesomeness.ScalaJSTest$.doSend(org.scalajs.dom.raw.WebSocket)scala.Unit
[error] called from tld.awesomeness.ScalaJSTest$.tld$awesomeness$ScalaJSTest$$$anonfun$call$1(org.scalajs.dom.raw.Event,org.scalajs.dom.raw.WebSocket)org.scalajs.dom.raw.Event
[error] called from tld.awesomeness.ScalaJSTest$.call()scala.Unit
[error] called from tld.awesomeness.Main$.main()scala.Unit
[error] called from scala.scalajs.js.JSApp.$$js$exported$meth$main()java.lang.Object
[error] called from tld.awesomeness.Main$.$$js$exported$meth$main()java.lang.Object
[error] called from tld.awesomeness.Main$.main
[error] exported to JavaScript with @JSExport
[error] involving instantiated classes:
[error] tld.awesomeness.ScalaJSTest$
[error] tld.awesomeness.Main$
java.lang.RuntimeException: There were linking errors
at scala.sys.package$.error(package.scala:27)
at org.scalajs.core.tools.linker.frontend.BaseLinker.linkInternal(BaseLinker.scala:133)
at org.scalajs.core.tools.linker.frontend.BaseLinker.linkInternal(BaseLinker.scala:86)
at org.scalajs.core.tools.linker.frontend.LinkerFrontend$$anonfun$4.apply(LinkerFrontend.scala:54)
at org.scalajs.core.tools.linker.frontend.LinkerFrontend$$anonfun$4.apply(LinkerFrontend.scala:54)
at org.scalajs.core.tools.logging.Logger$class.time(Logger.scala:28)
at org.scalajs.sbtplugin.Loggers$SbtLoggerWrapper.time(Loggers.scala:7)
at org.scalajs.core.tools.linker.frontend.LinkerFrontend.link(LinkerFrontend.scala:53)
at org.scalajs.core.tools.linker.Linker$$anonfun$link$1.apply$mcV$sp(Linker.scala:50)
at org.scalajs.core.tools.linker.Linker$$anonfun$link$1.apply(Linker.scala:49)
at org.scalajs.core.tools.linker.Linker$$anonfun$link$1.apply(Linker.scala:49)
at org.scalajs.core.tools.linker.Linker.guard(Linker.scala:67)
at org.scalajs.core.tools.linker.Linker.link(Linker.scala:49)
at org.scalajs.core.tools.linker.ClearableLinker$$anonfun$link$1.apply(ClearableLinker.scala:51)
at org.scalajs.core.tools.linker.ClearableLinker$$anonfun$link$1.apply(ClearableLinker.scala:51)
at org.scalajs.core.tools.linker.ClearableLinker.linkerOp(ClearableLinker.scala:62)
at org.scalajs.core.tools.linker.ClearableLinker.link(ClearableLinker.scala:51)
at org.scalajs.sbtplugin.ScalaJSPluginInternal$$anonfun$org$scalajs$sbtplugin$ScalaJSPluginInternal$$scalaJSStageSettings$4$$anonfun$apply$6$$anonfun$apply$7.apply(ScalaJSPluginInternal.scala:251)
at org.scalajs.sbtplugin.ScalaJSPluginInternal$$anonfun$org$scalajs$sbtplugin$ScalaJSPluginInternal$$scalaJSStageSettings$4$$anonfun$apply$6$$anonfun$apply$7.apply(ScalaJSPluginInternal.scala:239)
at sbt.FileFunction$$anonfun$cached$1.apply(Tracked.scala:253)
at sbt.FileFunction$$anonfun$cached$1.apply(Tracked.scala:253)
at sbt.FileFunction$$anonfun$cached$2$$anonfun$apply$3$$anonfun$apply$4.apply(Tracked.scala:267)
at sbt.FileFunction$$anonfun$cached$2$$anonfun$apply$3$$anonfun$apply$4.apply(Tracked.scala:263)
at sbt.Difference.apply(Tracked.scala:224)
at sbt.Difference.apply(Tracked.scala:206)
at sbt.FileFunction$$anonfun$cached$2$$anonfun$apply$3.apply(Tracked.scala:263)
at sbt.FileFunction$$anonfun$cached$2$$anonfun$apply$3.apply(Tracked.scala:262)
at sbt.Difference.apply(Tracked.scala:224)
at sbt.Difference.apply(Tracked.scala:200)
at sbt.FileFunction$$anonfun$cached$2.apply(Tracked.scala:262)
at sbt.FileFunction$$anonfun$cached$2.apply(Tracked.scala:260)
at org.scalajs.sbtplugin.ScalaJSPluginInternal$$anonfun$org$scalajs$sbtplugin$ScalaJSPluginInternal$$scalaJSStageSettings$4$$anonfun$apply$6.apply(ScalaJSPluginInternal.scala:256)
at org.scalajs.sbtplugin.ScalaJSPluginInternal$$anonfun$org$scalajs$sbtplugin$ScalaJSPluginInternal$$scalaJSStageSettings$4$$anonfun$apply$6.apply(ScalaJSPluginInternal.scala:237)
at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
at sbt.$tilde$greater$$anonfun$$u2219$1.apply(TypeFunctions.scala:40)
at sbt.std.Transform$$anon$4.work(System.scala:63)
at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:228)
at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:228)
at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:17)
at sbt.Execute.work(Execute.scala:237)
at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:228)
at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:228)
at sbt.ConcurrentRestrictions$$anon$4$$anonfun$1.apply(ConcurrentRestrictions.scala:159)
at sbt.CompletionService$$anon$2.call(CompletionService.scala:28)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
[error] (client/compile:fastOptJS) There were linking errors
My ide finds everything but obviously I am doing something wrong. I already had a look at https://github.com/thesamet/scalapbjs-test but to no avail.
Problem appears with that line val msg = Test().withId(1337)
edit: after comment I changed build.sbt
:
lazy val proto = (crossProject in file("modules/proto"))
.settings(generalSettings: _*)
.settings(
PB.targets in Compile := Seq(
scalapb.gen() -> (sourceManaged in Compile).value
)).
jvmSettings(
libraryDependencies += "com.trueaccord.scalapb" %% "scalapb-runtime" % com.trueaccord.scalapb.compiler.Version.scalapbVersion % "protobuf",
PB.targets in Compile := Seq(
scalapb.gen() -> (sourceManaged in Compile).value
)
).
jsSettings(
libraryDependencies ++= Seq(
"com.trueaccord.scalapb" %%% "scalapb-runtime" % com.trueaccord.scalapb.compiler.Version.scalapbVersion,
"com.trueaccord.scalapb" %%% "scalapb-runtime" % com.trueaccord.scalapb.compiler.Version.scalapbVersion % "protobuf"
),
PB.targets in Compile := Seq(
scalapb.gen() -> (sourceManaged in Compile).value
)
)
lazy val protoJs = proto.js
lazy val protoJVM = proto.jvm
lazy val play = (project in file("modules/play"))
.enablePlugins(PlayScala)
.settings(generalSettings: _*)
.settings(
name := "play",
libraryDependencies ++= Seq(
CrossDependencies.scalaTest,
CrossDependencies.scalactic,
CrossDependencies.scalaTags,
"com.typesafe.play" %% "play-json" % "2.6.0-M1"),
scalaJSProjects := Seq(client),
pipelineStages in Assets := Seq(scalaJSPipeline),
compile in Compile := ((compile in Compile) dependsOn scalaJSPipeline).value
)
.aggregate(slick)
.dependsOn(slick)
.aggregate(flyway)
.dependsOn(flyway)
.aggregate(protoJVM)
.dependsOn(protoJVM)
lazy val client = (project in file("modules/client"))
.enablePlugins(ScalaJSPlugin, ScalaJSWeb)
.settings(generalSettings: _*)
.settings(
name := "client",
libraryDependencies += CrossDependencies.scalaTags,
persistLauncher := true
)
.aggregate(protoJs)
.dependsOn(protoJs)
now now neither play
nor client
can resolve the proto-class :(
(Also I am aware of the redundant PB.targets in Compile...
, I just thought that sharing might not work there, so I added it to both distinct settings again)
With pure CrossProject you need to specify the actual path ScalaPB should look for proto files (the value it guesses is wrong). Here is a minimal example:
lazy val proto = (crossProject.crossType(CrossType.Pure) in file("proto"))
.settings(
PB.targets in Compile := Seq(
scalapb.gen() -> (sourceManaged in Compile).value
),
// The trick is in this line:
PB.protoSources in Compile := Seq(file("proto/src/main/protobuf")),
libraryDependencies ++= Seq(
"com.trueaccord.scalapb" %%% "scalapb-runtime" % com.trueaccord.scalapb.compiler.Version.scalapbVersion,
"com.trueaccord.scalapb" %%% "scalapb-runtime" % com.trueaccord.scalapb.compiler.Version.scalapbVersion % "protobuf"
)
)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.