mill

Using Mill to publish JVM/JS library with platform-specific code


I want to publish (at least locally) a JVM/JS cross-platform library using Mill. I have that much working with build file shown below.

The part that has me stumped is that I'd like to include a modest amount of platform-specific code. The most obvious approach to me is to put that code in two separate directories, xpJVM and xpJS and make xpShared.jvm and xpShared.js depend on them. But that generates a type conflict with the PublishModule:

[build.mill-61] [error]  found   : package_.this.xpJS.type
[build.mill-61] [error]  required: mill.scalalib.PublishModule
[build.mill-61] [error]     def moduleDeps = Seq(xpJS)
[build.mill-61] [error]                          ^
[build.mill-61] [error] /Users/bwbecker/temp/xp/build.mill:21:26: type mismatch;

Here's the important part of the file layout:

.
├── build.mill
├── xpJS
│   └── src
│       └── Platform.scala
├── xpJVM
│   └── src
│       └── Platform.scala
└── xpShared
    ├── src
    │   └── XP.scala
    └── test
        └── src
            └── XPTests.scala

Here's the build.mill file:


package build
import mill._, scalalib._, scalajslib._, publish._

trait AppScalaModule extends ScalaModule {
  def scalaVersion = "3.3.5"
}

trait AppScalaJSModule extends AppScalaModule with ScalaJSModule {
  def scalaJSVersion = "1.16.0"
}

// JVM-specific stuff
object xpJVM extends AppScalaModule
// JS-specific stuff
object xpJS extends AppScalaJSModule 

object xpShared extends AppScalaModule {
  trait SharedModule extends AppScalaModule with PlatformScalaModule 
  
  object jvm extends SharedModule with XP_Publish {
    // The following line causes a compile error
    def moduleDeps = Seq(xpJVM)
    object test extends ScalaTests {
      def ivyDeps = Agg(ivy"com.lihaoyi::utest::0.8.5")
      def testFramework = "utest.runner.Framework"
    }
  }

  object js extends SharedModule with AppScalaJSModule with XP_Publish {
    // The following line causes a compile error
    def moduleDeps = Seq(xpJS)
    object test extends ScalaTests with ScalaJSTests {
      def ivyDeps = Agg(ivy"com.lihaoyi::utest::0.8.5")
      def testFramework = "utest.runner.Framework"
    }
  }
}

trait XP_Publish extends PublishModule {
  override def publishVersion          = "0.1.0"
  override def artifactName = "xp"

  override def pomSettings = PomSettings(
    description = "A cross-platform library.",
    organization = "ca.uwaterloo",
    url = "",
    licenses = Seq(),
    versionControl = VersionControl(),
    developers = Seq()
  )
}

Any suggestions on how to proceed? I have two:

  1. Attempt to use the CrossScalaModule shown in the Mill documentation. I'm skeptical of this approach because it involves a lot of overhead for something I don't need (multiple Scala versions) and there's nothing in that example that addresses my specific problem (platform-specific code).
  2. Override the sources for xpShared.js and xpShared.jvm to include the sources in xpJS and xpJVM. I'm more optimistic that will work, but the approach outlined above seems so much more direct. I'd prefer that approach, if possible.

Thanks for any suggestions you may have!


Solution

  • OK, after hours of work, the solution comes 15 minutes after posting and starting to pursue the second option, above.

    mill show __.sources shows

     "xpShared.js.sources": [
        "ref:v0:b7894f75:/Users/bwbecker/temp/xp/xpShared/src",
        "ref:v0:7a661082:/Users/bwbecker/temp/xp/xpShared/src-js"
      ],
    

    and similarly for xpShared.jvm.sources.

    Simply put the platform-specific code in xpShared/src-js and xpShared/src-jvm.

    Easy -- once you know. In fairness, a search of the documentation (both with the built-in search and google) for src-jvm turns up nothing.