Cross Builds
Mill handles cross-building of all sorts via the Cross[T]
module.
Defining Cross Modules
You can use this as follows:
import mill._
object foo extends mill.Cross[FooModule]("2.10", "2.11", "2.12")
class FooModule(crossVersion: String) extends Module {
def suffix = T { crossVersion }
def bigSuffix = T { suffix().toUpperCase() }
}
This defines three copies of FooModule
: "210"
, "211"
and "212"
, each of which has their own suffix
target. You can then run them via
mill show foo[2.10].suffix
mill show foo[2.10].bigSuffix
mill show foo[2.11].suffix
mill show foo[2.11].bigSuffix
mill show foo[2.12].suffix
mill show foo[2.12].bigSuffix
Please be aware that some shells like
|
The suffix
targets will have the corresponding output paths for their
metadata and files:
out/
├── foo/
│ ├── 2.10/
│ │ ├── bigSuffix.json
│ │ └── suffix.json
│ ├── 2.11/
│ │ ├── bigSuffix.json
│ │ └── suffix.json
│ └── 2.12/
│ ├── bigSuffix.json
│ └── suffix.json
If you want to have dedicated millSourcePath
s, you can add the cross parameters to it:
import mill._
object foo extends mill.Cross[FooModule]("2.10", "2.11", "2.12")
class FooModule(crossVersion: String) extends Module {
def millSourcePath = super.millSourcePath / crossVersion
}
Before Mill 0.11.0-M5,
|
You can also have a cross-build with multiple inputs:
import mill._
val crossMatrix = for {
crossVersion <- Seq("210", "211", "212")
platform <- Seq("jvm", "js", "native")
if !(platform == "native" && crossVersion != "212")
} yield (crossVersion, platform)
object foo extends mill.Cross[FooModule](crossMatrix:_*)
class FooModule(crossVersion: String, platform: String) extends Module {
def suffix = T { crossVersion + "_" + platform }
}
Here, we define our cross-values programmatically using a for
-loop that spits out tuples instead of individual values.
Our FooModule
template class then takes two parameters instead of one.
This creates the following modules each with their own suffix
target:
$ mill showNamed foo[_].suffix
[1/1] showNamed
[1/1] showNamed > [7/7] foo[212,native].suffix
{
"foo[210,jvm].suffix": "210_jvm",
"foo[210,js].suffix": "210_js",
"foo[211,jvm].suffix": "211_jvm",
"foo[211,js].suffix": "211_js",
"foo[212,jvm].suffix": "212_jvm",
"foo[212,js].suffix": "212_js",
"foo[212,native].suffix": "212_native"
}
Using Cross Modules from Outside
You can refer to targets defined in cross-modules as follows:
import mill._
object foo extends mill.Cross[FooModule]("2.10", "2.11", "2.12")
class FooModule(crossVersion: String) extends Module {
def suffix = T { crossVersion }
}
def bar = T { s"hello ${foo("2.10").suffix}" }
Here, foo("2.10")
references the "2.10"
instance of FooModule
. You can
refer to whatever versions of the cross-module you want, even using multiple
versions of the cross-module in the same target:
import mill._
object foo extends mill.Cross[FooModule]("2.10", "2.11", "2.12")
class FooModule(crossVersion: String) extends Module {
def suffix = T { crossVersion }
}
def bar = T { s"hello ${foo("2.10").suffix} world ${foo("2.12").suffix}" }
Using Cross Modules from other Cross Modules
Targets in cross-modules can depend on one another the same way than external targets:
import mill._
object foo extends mill.Cross[FooModule]("2.10", "2.11", "2.12")
class FooModule(crossVersion: String) extends Module {
def suffix = T { crossVersion }
}
object bar extends mill.Cross[BarModule]("2.10", "2.11", "2.12")
class BarModule(crossVersion: String) extends Module {
def bigSuffix = T { foo(crossVersion).suffix().toUpperCase() }
}
Here, you can run:
mill show foo[2.10].suffix
mill show foo[2.11].suffix
mill show foo[2.12].suffix
mill show bar[2.10].bigSuffix
mill show bar[2.11].bigSuffix
mill show bar[2.12].bigSuffix
or the more compact version:
$ mill showNamed foo[__].suffix
[1/1] showNamed
[1/1] showNamed > [3/3] foo[2.12].suffix
{
"foo[2.10].suffix": "2.10",
"foo[2.11].suffix": "2.11",
"foo[2.12].suffix": "2.12"
}
Cross Resolvers
You can define an implicit mill.define.Cross.Resolver
within your
cross-modules, which would let you use a shorthand foo()
syntax when referring to other cross-modules with an identical set of cross values:
import mill._
trait MyModule extends Module {
def crossVersion: String
implicit object resolver extends mill.define.Cross.Resolver[MyModule] {
def resolve[V <: MyModule](c: Cross[V]): V = c.itemMap(List(crossVersion))
}
}
object foo extends mill.Cross[FooModule]("2.10", "2.11", "2.12")
class FooModule(val crossVersion: String) extends MyModule {
def suffix = T { crossVersion }
}
object bar extends mill.Cross[BarModule]("2.10", "2.11", "2.12")
class BarModule(val crossVersion: String) extends MyModule {
def longSuffix = T { "_" + foo().suffix() }
}
While the example resolver
simply looks up the target Cross
value for the cross-module instance with the same crossVersion
, you can make the resolver arbitrarily complex.
E.g. the resolver
for mill.scalalib.CrossSbtModule
looks for a cross-module instance whose scalaVersion
is binary compatible (e.g. 2.10.5 is compatible with 2.10.3) with the current cross-module.