Skip to content

Commit 9747a8f

Browse files
authored
Fix conflicting dependencies between upstream JavaModules (#2735)
Fixes #2732 We introduce a new `localCompileClasspath`, which differs from `compileClasspath` in that it leaves out the `transitiveCompileClasspath` from upstream modules and `resolvedIvyDeps` from third party dependencies. Also tried to do some cleanup of `JavaModule`, refactoring out a `transitiveModuleCompileModuleDeps` helper to DRY things up, re-arranging things so all the `fooModuleDeps` helpers are all together. Tested via a new unit test `mill.scalalib.HelloWorldTests.multiModuleClasspaths`, which fails on master and passes on this PR. This test case asserts the overall "shape" of the classpaths, which should help rule out an entire class of mis-configuration w.r.t. how the classpaths are wired up
1 parent 69954eb commit 9747a8f

File tree

9 files changed

+349
-80
lines changed

9 files changed

+349
-80
lines changed

build.sc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -935,7 +935,7 @@ object bsp extends MillPublishScalaModule with BuildInfo {
935935
}
936936

937937
object worker extends MillPublishScalaModule {
938-
def compileModuleDeps = Seq(bsp, scalalib, testrunner, runner)
938+
def compileModuleDeps = Seq(bsp, scalalib, testrunner, runner) ++ scalalib.compileModuleDeps
939939
def ivyDeps = Agg(Deps.bsp4j, Deps.sbtTestInterface)
940940
}
941941
}

example/basic/4-builtin-commands/build.sc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,9 @@ Inputs:
129129
130130
> ./mill show foo.compileClasspath
131131
[
132-
".../foo/compile-resources",
133132
".../org/scala-lang/scala-library/2.13.11/scala-library-2.13.11.jar",
134133
...
134+
".../foo/compile-resources"
135135
]
136136
137137
*/
@@ -150,9 +150,9 @@ Inputs:
150150
".../foo/src"
151151
],
152152
"foo.compileClasspath": [
153-
".../foo/compile-resources",
154153
".../org/scala-lang/scala-library/2.13.11/scala-library-2.13.11.jar",
155154
...
155+
".../foo/compile-resources"
156156
]
157157
}
158158
@@ -171,9 +171,9 @@ Inputs:
171171
".../foo/src"
172172
],
173173
"foo.compileClasspath": [
174-
".../foo/compile-resources",
175174
".../org/scala-lang/scala-library/2.13.11/scala-library-2.13.11.jar",
176175
...
176+
".../foo/compile-resources"
177177
]
178178
}
179179

example/cross/10-static-blog/build.sc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// libraries - Commonmark and Scalatags - to deal with Markdown parsing and
44
// HTML generation respectively:
55

6-
import $ivy.`com.lihaoyi::scalatags:0.9.1`, scalatags.Text.all._
6+
import $ivy.`com.lihaoyi::scalatags:0.12.0`, scalatags.Text.all._
77
import $ivy.`com.atlassian.commonmark:commonmark:0.13.1`
88
import org.commonmark.parser.Parser
99
import org.commonmark.renderer.html.HtmlRenderer

example/misc/3-import-file-ivy/build.sc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import mill._, scalalib._
2-
import $ivy.`com.lihaoyi::scalatags:0.8.2`, scalatags.Text.all._
2+
import $ivy.`com.lihaoyi::scalatags:0.12.0`, scalatags.Text.all._
33
import $file.scalaversion, scalaversion.myScalaVersion
44

55
object foo extends RootModule with ScalaModule {

example/misc/4-mill-build-folder/build.sc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,14 @@ compiling 1 Scala source...
5252
5353
> ./mill run
5454
Foo.value: <h1>hello</h1>
55-
scalatagsVersion: 0.8.2
55+
scalatagsVersion: 0.12.0
5656
5757
> ./mill show assembly
5858
".../out/assembly.dest/out.jar"
5959
6060
> ./out/assembly.dest/out.jar # mac/linux
6161
Foo.value: <h1>hello</h1>
62-
scalatagsVersion: 0.8.2
62+
scalatagsVersion: 0.12.0
6363
6464
*/
6565

example/misc/4-mill-build-folder/mill-build/build.sc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import mill._, scalalib._
22

33
object millbuild extends MillBuildRootModule{
4-
val scalatagsVersion = "0.8.2"
4+
val scalatagsVersion = "0.12.0"
55
def ivyDeps = Agg(ivy"com.lihaoyi::scalatags:$scalatagsVersion")
66

77
def generatedSources = T {

example/thirdparty/jimfs/build.sc

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
import mill._, scalalib._, publish._
22

3-
object jimfs extends PublishModule with MavenModule{
3+
def sharedCompileIvyDeps = T{
4+
Agg(
5+
ivy"com.google.auto.service:auto-service:1.0.1",
6+
ivy"com.google.code.findbugs:jsr305:3.0.2",
7+
ivy"org.checkerframework:checker-compat-qual:2.5.5",
8+
ivy"com.ibm.icu:icu4j:73.1",
9+
)
10+
}
11+
12+
13+
object jimfs extends PublishModule with MavenModule {
414
def publishVersion = "1.3.3.7"
515

616
def pomSettings = PomSettings(
@@ -12,21 +22,14 @@ object jimfs extends PublishModule with MavenModule{
1222
developers = Nil
1323
)
1424

15-
def ivyDeps = Agg(
25+
def ivyDeps = sharedCompileIvyDeps() ++ Agg(
1626
ivy"com.google.guava:guava:31.1-android",
1727
)
1828

19-
def compileIvyDeps = Agg(
20-
ivy"com.google.auto.service:auto-service:1.0.1",
21-
ivy"com.google.code.findbugs:jsr305:3.0.2",
22-
ivy"org.checkerframework:checker-compat-qual:2.5.5",
23-
ivy"com.ibm.icu:icu4j:73.1",
24-
)
25-
2629
def javacOptions = Seq("-processor", "com.google.auto.service.processor.AutoServiceProcessor")
2730

28-
object test extends MavenModuleTests{
29-
def ivyDeps = Agg(
31+
object test extends MavenModuleTests {
32+
def ivyDeps = sharedCompileIvyDeps() ++ Agg(
3033
ivy"junit:junit:4.13.2",
3134
ivy"com.google.guava:guava-testlib:31.1-android",
3235
ivy"com.google.truth:truth:1.1.3",

scalalib/src/mill/scalalib/JavaModule.scala

Lines changed: 54 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -128,12 +128,34 @@ trait JavaModule
128128
/** The compile-only direct dependencies of this module. */
129129
def compileModuleDeps: Seq[JavaModule] = Seq.empty
130130

131+
/** The direct and indirect dependencies of this module */
132+
def recursiveModuleDeps: Seq[JavaModule] = {
133+
moduleDeps.flatMap(_.transitiveModuleDeps).distinct
134+
}
135+
136+
/**
137+
* Like `recursiveModuleDeps` but also include the module itself,
138+
* basically the modules whose classpath are needed at runtime
139+
*/
140+
def transitiveModuleDeps: Seq[JavaModule] = Seq(this) ++ recursiveModuleDeps
141+
142+
/**
143+
* All direct and indirect module dependencies of this module, including
144+
* compile-only dependencies: basically the modules whose classpath are needed
145+
* at compile-time.
146+
*
147+
* Note that `compileModuleDeps` are defined to be non-transitive, so we only
148+
* look at the direct `compileModuleDeps` when assembling this list
149+
*/
150+
def transitiveModuleCompileModuleDeps: Seq[JavaModule] = {
151+
(moduleDeps ++ compileModuleDeps).flatMap(_.transitiveModuleDeps).distinct
152+
}
153+
131154
/** The compile-only transitive ivy dependencies of this module and all it's upstream compile-only modules. */
132155
def transitiveCompileIvyDeps: T[Agg[BoundDep]] = T {
133156
// We never include compile-only dependencies transitively, but we must include normal transitive dependencies!
134-
compileIvyDeps().map(bindDependency()) ++ T
135-
.traverse(compileModuleDeps)(_.transitiveIvyDeps)()
136-
.flatten
157+
compileIvyDeps().map(bindDependency()) ++
158+
T.traverse(compileModuleDeps)(_.transitiveIvyDeps)().flatten
137159
}
138160

139161
/**
@@ -158,16 +180,6 @@ trait JavaModule
158180
T.log.outputStream.println(asString)
159181
}
160182

161-
/** The direct and indirect dependencies of this module */
162-
def recursiveModuleDeps: Seq[JavaModule] = {
163-
moduleDeps.flatMap(_.transitiveModuleDeps).distinct
164-
}
165-
166-
/** Like `recursiveModuleDeps` but also include the module itself */
167-
def transitiveModuleDeps: Seq[JavaModule] = {
168-
Seq(this) ++ recursiveModuleDeps
169-
}
170-
171183
/**
172184
* Additional jars, classfiles or resources to add to the classpath directly
173185
* from disk rather than being downloaded from Maven Central or other package
@@ -180,28 +192,22 @@ trait JavaModule
180192
* This is calculated from [[ivyDeps]], [[mandatoryIvyDeps]] and recursively from [[moduleDeps]].
181193
*/
182194
def transitiveIvyDeps: T[Agg[BoundDep]] = T {
183-
(ivyDeps() ++ mandatoryIvyDeps()).map(bindDependency()) ++ T.traverse(moduleDeps)(
184-
_.transitiveIvyDeps
185-
)().flatten
195+
(ivyDeps() ++ mandatoryIvyDeps()).map(bindDependency()) ++
196+
T.traverse(moduleDeps)(_.transitiveIvyDeps)().flatten
186197
}
187198

188199
/**
189200
* The upstream compilation output of all this module's upstream modules
190201
*/
191202
def upstreamCompileOutput: T[Seq[CompilationResult]] = T {
192-
T.traverse((recursiveModuleDeps ++ compileModuleDeps.flatMap(
193-
_.transitiveModuleDeps
194-
)).distinct)(_.compile)
203+
T.traverse(transitiveModuleCompileModuleDeps)(_.compile)
195204
}
196205

197206
/**
198207
* The transitive version of `localClasspath`
199208
*/
200209
def transitiveLocalClasspath: T[Agg[PathRef]] = T {
201-
T.traverse(
202-
(moduleDeps ++ compileModuleDeps).flatMap(_.transitiveModuleDeps).distinct
203-
)(m => m.localClasspath)()
204-
.flatten
210+
T.traverse(transitiveModuleCompileModuleDeps)(_.localClasspath)().flatten
205211
}
206212

207213
/**
@@ -210,20 +216,16 @@ trait JavaModule
210216
// Keep in sync with [[transitiveLocalClasspath]]
211217
@internal
212218
def bspTransitiveLocalClasspath: T[Agg[UnresolvedPath]] = T {
213-
T.traverse(
214-
(moduleDeps ++ compileModuleDeps).flatMap(_.transitiveModuleDeps).distinct
215-
)(m => m.bspLocalClasspath)()
216-
.flatten
219+
T.traverse(transitiveModuleCompileModuleDeps)(_.bspLocalClasspath)().flatten
217220
}
218221

219222
/**
220223
* The transitive version of `compileClasspath`
221224
*/
222225
def transitiveCompileClasspath: T[Agg[PathRef]] = T {
223-
T.traverse(
224-
(moduleDeps ++ compileModuleDeps).flatMap(_.transitiveModuleDeps).distinct
225-
)(m => T.task { m.compileClasspath() ++ Agg(m.compile().classes) })()
226-
.flatten
226+
T.traverse(transitiveModuleCompileModuleDeps)(m =>
227+
T.task { m.localCompileClasspath() ++ Agg(m.compile().classes) }
228+
)().flatten
227229
}
228230

229231
/**
@@ -232,9 +234,7 @@ trait JavaModule
232234
// Keep in sync with [[transitiveCompileClasspath]]
233235
@internal
234236
def bspTransitiveCompileClasspath: T[Agg[UnresolvedPath]] = T {
235-
T.traverse(
236-
(moduleDeps ++ compileModuleDeps).flatMap(_.transitiveModuleDeps).distinct
237-
)(m =>
237+
T.traverse(transitiveModuleCompileModuleDeps)(m =>
238238
T.task {
239239
m.bspCompileClasspath() ++ Agg(m.bspCompileClassesPath())
240240
}
@@ -355,11 +355,11 @@ trait JavaModule
355355
}
356356

357357
/**
358-
* The output classfiles/resources from this module, excluding upstream
359-
* modules and third-party dependencies
358+
* The *output* classfiles/resources from this module, used for execution,
359+
* excluding upstream modules and third-party dependencies
360360
*/
361361
def localClasspath: T[Seq[PathRef]] = T {
362-
compileResources() ++ resources() ++ Agg(compile().classes)
362+
localCompileClasspath().toSeq ++ resources() ++ Agg(compile().classes)
363363
}
364364

365365
/**
@@ -368,9 +368,8 @@ trait JavaModule
368368
*/
369369
@internal
370370
def bspLocalClasspath: T[Agg[UnresolvedPath]] = T {
371-
(compileResources() ++ resources()).map(p => UnresolvedPath.ResolvedPath(p.path)) ++ Agg(
372-
bspCompileClassesPath()
373-
)
371+
(compileResources() ++ resources()).map(p => UnresolvedPath.ResolvedPath(p.path)) ++
372+
Agg(bspCompileClassesPath())
374373
}
375374

376375
/**
@@ -379,53 +378,51 @@ trait JavaModule
379378
*/
380379
// Keep in sync with [[bspCompileClasspath]]
381380
def compileClasspath: T[Agg[PathRef]] = T {
382-
transitiveCompileClasspath() ++
383-
compileResources() ++
384-
unmanagedClasspath() ++
385-
resolvedIvyDeps()
381+
resolvedIvyDeps() ++ transitiveCompileClasspath() ++ localCompileClasspath()
382+
}
383+
384+
/**
385+
* The *input* classfiles/resources from this module, used during compilation,
386+
* excluding upstream modules and third-party dependencies
387+
*/
388+
def localCompileClasspath: T[Agg[PathRef]] = T {
389+
compileResources() ++ unmanagedClasspath()
386390
}
387391

388392
/** Same as [[compileClasspath]], but does not trigger compilation targets, if possible. */
389393
// Keep in sync with [[compileClasspath]]
390394
@internal
391395
def bspCompileClasspath: T[Agg[UnresolvedPath]] = T {
392396
bspTransitiveCompileClasspath() ++
393-
(compileResources() ++ unmanagedClasspath() ++ resolvedIvyDeps())
397+
(localCompileClasspath() ++ resolvedIvyDeps())
394398
.map(p => UnresolvedPath.ResolvedPath(p.path))
395399
}
396400

397401
/**
398402
* Resolved dependencies based on [[transitiveIvyDeps]] and [[transitiveCompileIvyDeps]].
399403
*/
400404
def resolvedIvyDeps: T[Agg[PathRef]] = T {
401-
resolveDeps(T.task {
402-
transitiveCompileIvyDeps() ++ transitiveIvyDeps()
403-
})()
405+
resolveDeps(T.task { transitiveCompileIvyDeps() ++ transitiveIvyDeps() })()
404406
}
405407

406408
/**
407409
* All upstream classfiles and resources necessary to build and executable
408410
* assembly, but without this module's contribution
409411
*/
410412
def upstreamAssemblyClasspath: T[Agg[PathRef]] = T {
411-
transitiveLocalClasspath() ++
412-
unmanagedClasspath() ++
413-
resolvedRunIvyDeps()
413+
resolvedRunIvyDeps() ++ transitiveLocalClasspath()
414414
}
415415

416416
def resolvedRunIvyDeps: T[Agg[PathRef]] = T {
417-
resolveDeps(T.task {
418-
runIvyDeps().map(bindDependency()) ++ transitiveIvyDeps()
419-
})()
417+
resolveDeps(T.task { runIvyDeps().map(bindDependency()) ++ transitiveIvyDeps() })()
420418
}
421419

422420
/**
423421
* All classfiles and resources from upstream modules and dependencies
424422
* necessary to run this module's code after compilation
425423
*/
426424
def runClasspath: T[Seq[PathRef]] = T {
427-
localClasspath() ++
428-
upstreamAssemblyClasspath()
425+
resolvedRunIvyDeps().toSeq ++ transitiveLocalClasspath() ++ localClasspath()
429426
}
430427

431428
/**
@@ -470,10 +467,7 @@ trait JavaModule
470467
* without those from upstream modules and dependencies
471468
*/
472469
def jar: T[PathRef] = T {
473-
Jvm.createJar(
474-
localClasspath().map(_.path).filter(os.exists),
475-
manifest()
476-
)
470+
Jvm.createJar(localClasspath().map(_.path).filter(os.exists), manifest())
477471
}
478472

479473
/**

0 commit comments

Comments
 (0)