Producing no artifact for root project with package under multi-project build in SBT
Asked Answered
B

5

8

I have a multi-project build configuration in SBT that consists of two distinct modules that do not depend on each other. They just (happen to) belong to the same product.

The project layout is as follows:

myLib
  + build.sbt
  + myProject_1
  |    + build.sbt
  |    + src
  |        + ...
  + myProject_2
  |    + build.sbt
  |    + src
  |        + ...
  + project
       + Build.scala

project/Build.scala contains common settings and looks like this:

import sbt._
import Keys._

object ApplicationBuild extends Build {

  val appVersion = "1.0-SNAPSHOT"

  val defaultScalacOptions = Seq(
    "-unchecked", "-deprecation", "-feature", "-language:reflectiveCalls",
    "-language:implicitConversions", "-language:postfixOps",
    "-language:dynamics", "-language:higherKinds", "-language:existentials",
    "-language:experimental.macros", "-Xmax-classfile-name", "140")

  val defaultResolvers = Seq(
    "Typesafe repository" at "http://repo.typesafe.com/typesafe/releases/"
  )

  val defaultLibraryDependencies = Seq(
    "org.specs2" %% "specs2" % "1.14" % "test",
    "org.slf4j" % "slf4j-nop" % "1.7.5" % "test"
  )

  val defaultSettings = Defaults.defaultSettings ++ Seq(
    scalacOptions ++= defaultScalacOptions,
    resolvers ++= defaultResolvers,
    libraryDependencies ++= defaultLibraryDependencies
  )
}

The root build file build.sbt is just needed to put all together [I also tried to remove it.. but then the sub-projects don't get compiled anymore]:

lazy val myProject_1 = project.in(file("myProject_1"))

lazy val myProject_2 = project.in(file("myProject_2"))

And finally here is myProject_1/build.sbt [I have just omitted myProject_2/build.sbt because it is very similar and does not provide any added value for the topic]:

name := "myProject_1"

version := ApplicationBuild.appVersion

ApplicationBuild.defaultSettings

libraryDependencies ++= Seq(
  "commons-codec" % "commons-codec" % "1.8"
)

The project compiles successfully... but when I issue the command sbt package, then an empty jar is generated in the root target directory:

j3d@gonzo:~/myLib/$ ll target/scala-2.10
drwxrwxr-x 2 j3d j3d 4096 Dez 23 17:13 ./
drwxrwxr-x 5 j3d j3d 4096 Dez 23 17:13 ../
-rw-rw-r-- 1 j3d j3d  273 Dez 23 17:13 brix_2.10-0.1-SNAPSHOT.jar

Am I missing something? How can I prevent SBT from generating this empty and useless jar?

Bushelman answered 23/12, 2013 at 16:23 Comment(0)
F
6

I propose a workaround with the following (re)definition of package in build.sbt:

Keys.`package` := {
    (Keys.`package` in (a, Compile)).value
    (Keys.`package` in (b, Compile)).value
}

where a and b are (sub)modules.

lazy val a = project

lazy val b = project

Since package is a keyword in Scala it needs quotes to be resolvable.

It also needs to be fully-qualified since package is imported by Keys._ and sbt._ imports that are by default in .sbt build files.

/Users/jacek/sandbox/so/multi-packageBin/build.sbt:5: error: reference to package is ambiguous;
it is imported twice in the same scope by
import Keys._
and import sbt._
`package` := {
^
[error] Type error in expression

Please also note that I'm using SBT 0.13.2-SNAPSHOT (built from the sources) so use with caution (yet I doubt it will make a difference in any version of SBT 0.13+).

[multi-packagebin]> */*:sbtVersion
[info] 0.13.2-SNAPSHOT
[multi-packagebin]> projects
[info] In file:/Users/jacek/sandbox/so/multi-packageBin/
[info]     a
[info]     b
[info]   * multi-packagebin
[multi-packagebin]> package
[info] Updating {file:/Users/jacek/sandbox/so/multi-packageBin/}a...
[info] Updating {file:/Users/jacek/sandbox/so/multi-packageBin/}b...
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[info] Done updating.
[info] Resolving org.scala-lang#scala-reflect;2.10.3 ...
[info] Packaging /Users/jacek/sandbox/so/multi-packageBin/b/target/scala-2.10/b_2.10-0.1-SNAPSHOT.jar ...
[info] Done packaging.
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[info] Done updating.
[info] Packaging /Users/jacek/sandbox/so/multi-packageBin/a/target/scala-2.10/a_2.10-0.1-SNAPSHOT.jar ...
[info] Done packaging.
[success] Total time: 1 s, completed Feb 23, 2014 10:12:41 AM
Fridlund answered 23/2, 2014 at 9:22 Comment(5)
Yessss... just tried with SBT 0.13.1 and it works ;-) Thank you very much.Bushelman
why I got following warning when I followed your suggestion? warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses (Keys.package in (data, Compile)).valueCly
What's the entire build.sbt file? I'd suggest raise another question on SO so the question and potential answers won't get buried in comments.Fridlund
Didn't actually read the whole question/answer, but this was the only place I could find that solved my "reference to package is ambiguous" problem. Thanks!Cottrill
+1. This worked for my Scala.js cross project configuration as well. I simply don't understand why publishArtifacts := false doesn't work...Jesu
H
10

This is ridiculously difficult to achieve. The following set of options appears to achieve the goal. Subsets of these options have a tendency to burn you by suppressing the root jar via some execution paths but not others, so if you want to find the minimum cover make sure neither 'sbt package' and 'sbt publishLocal' creates the jar. It took me plenty long to find this set and I am disinclined to iterate further.

      Keys.`package` :=  file(""),
packageBin in Global :=  file(""),
   packagedArtifacts :=  Map(),

sbt: making simple things borderline impossible since 2008.

Heterozygous answered 3/9, 2014 at 21:14 Comment(0)
F
6

I propose a workaround with the following (re)definition of package in build.sbt:

Keys.`package` := {
    (Keys.`package` in (a, Compile)).value
    (Keys.`package` in (b, Compile)).value
}

where a and b are (sub)modules.

lazy val a = project

lazy val b = project

Since package is a keyword in Scala it needs quotes to be resolvable.

It also needs to be fully-qualified since package is imported by Keys._ and sbt._ imports that are by default in .sbt build files.

/Users/jacek/sandbox/so/multi-packageBin/build.sbt:5: error: reference to package is ambiguous;
it is imported twice in the same scope by
import Keys._
and import sbt._
`package` := {
^
[error] Type error in expression

Please also note that I'm using SBT 0.13.2-SNAPSHOT (built from the sources) so use with caution (yet I doubt it will make a difference in any version of SBT 0.13+).

[multi-packagebin]> */*:sbtVersion
[info] 0.13.2-SNAPSHOT
[multi-packagebin]> projects
[info] In file:/Users/jacek/sandbox/so/multi-packageBin/
[info]     a
[info]     b
[info]   * multi-packagebin
[multi-packagebin]> package
[info] Updating {file:/Users/jacek/sandbox/so/multi-packageBin/}a...
[info] Updating {file:/Users/jacek/sandbox/so/multi-packageBin/}b...
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[info] Done updating.
[info] Resolving org.scala-lang#scala-reflect;2.10.3 ...
[info] Packaging /Users/jacek/sandbox/so/multi-packageBin/b/target/scala-2.10/b_2.10-0.1-SNAPSHOT.jar ...
[info] Done packaging.
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[info] Done updating.
[info] Packaging /Users/jacek/sandbox/so/multi-packageBin/a/target/scala-2.10/a_2.10-0.1-SNAPSHOT.jar ...
[info] Done packaging.
[success] Total time: 1 s, completed Feb 23, 2014 10:12:41 AM
Fridlund answered 23/2, 2014 at 9:22 Comment(5)
Yessss... just tried with SBT 0.13.1 and it works ;-) Thank you very much.Bushelman
why I got following warning when I followed your suggestion? warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses (Keys.package in (data, Compile)).valueCly
What's the entire build.sbt file? I'd suggest raise another question on SO so the question and potential answers won't get buried in comments.Fridlund
Didn't actually read the whole question/answer, but this was the only place I could find that solved my "reference to package is ambiguous" problem. Thanks!Cottrill
+1. This worked for my Scala.js cross project configuration as well. I simply don't understand why publishArtifacts := false doesn't work...Jesu
B
1

I use the following

lazy val root: Project = Project(
  id        = "root",
  base      = file("."),
  aggregate = Seq(proj1, proj2),
  settings  = Project.defaultSettings ++ Seq(
    publishArtifact in (Compile, packageBin) := false, // there are no binaries
    publishArtifact in (Compile, packageDoc) := false, // there are no javadocs
    publishArtifact in (Compile, packageSrc) := false  // there are no sources
  )
)

That still generates the empty packaged jar, but it will not export it when publishing.

Bluebill answered 23/12, 2013 at 22:26 Comment(2)
... but in that case wouldn't "publishArtifacts := false" be enough?Bushelman
I'd be happy to know the answer to @j3d's question tooGuitar
S
1

I'm not entirely sure on all the implications of this as I am new to SBT but the following seems to do the job:

compile := sbt.inc.Analysis.Empty

Overriding the packaging tasks didn't seem right to me. So I used inspect (plus the source as I didn't know what to look for at first) to find where exactly these mappings were coming from and found these dependencies:

compile:package -> compile:packageBin -> compile:packageBin::packageConfiguration -> compile:packageBin::mappings -> compile:packageBin::products (provided by compile:products) -> compile:compile

I don't know why it has to be this difficult. Most of my problems are coming from trying to have a multi project build.

Saeger answered 5/10, 2015 at 0:48 Comment(2)
I just realised inspect tree compile:package would have been far easier than following the dependencies manually.Saeger
This actually doesn't work. If packageBin isn't redefined then it will still call Defaults.packageTask which in turn calls Package.apply. It does some cache and up to date checks but may call Package.makeJar which is when you see: > [info] Packaging C:\target\my.jar ... > [info] Done packaging. It looks like the only proper way is the workaround from @JacekSaeger
L
0

I add the following settings to the project root:

Compile / packageBin := { file("") }
Compile / packageSrc := { file("") }
Compile / packageDoc := { file("") }

By changing tasks at Compile scope, the default package task is also suppressed.

Labonte answered 18/12, 2016 at 0:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.