summaryrefslogblamecommitdiff
path: root/docs/cross.md
blob: 25ae4a8a84b646e24ad2f581f8101bc039f5876e (plain) (tree)












































































































































                                                                                

                                                                              



                                                                
                                                           



                                                                

                                                           







                                                                             
Mill handles cross-building of all sorts via the `Cross[T]` module.


## Defining Cross Modules

You can use this as follows:

```scala
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

```bash
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
```

The modules each also have a `basePath` of

```text
foo/2.10
foo/2.11
foo/2.12
```

And the `suffix` targets will have the corresponding output paths for their
metadata and files:

```text
foo/2.10/suffix
foo/2.10/bigSuffix
foo/2.11/suffix
foo/2.11/bigSuffix
foo/2.12/suffix
foo/2.12/bigSuffix
```

You can also have a cross-build with multiple inputs:

```scala
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:

```bash
mill --show foo[210,jvm].suffix
mill --show foo[211,jvm].suffix
mill --show foo[212,jvm].suffix
mill --show foo[210,js].suffix
mill --show foo[211,js].suffix
mill --show foo[212,js].suffix
mill --show foo[212,native].suffix
```

## Using Cross Modules from Outside

You can refer to targets defined in cross-modules as follows:

```scala
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{ "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:

```scala
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{ "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 that external
targets:

```scala
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:

```bash
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
```


## Cross Resolvers

You can define an implicit `mill.define.Cross.Resolve` 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:

```scala
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.