Skip to content

Commit 27414a4

Browse files
committed
Add support for alternative system images to the compiler
This PR adds a new `-system` / `--system` setting to scalac which mimics its counterpart in javac. This fixes the biggest problem (at least for us) of scala/bug#13015. It is now possible to compile code against an older system image without enforcing strict module access. scalac generally does not enforce modules (scala/scala-dev#529) but it does when using `-release` (with class lookup based on `ct.sym`) and there was no way to opt out of these restrictions. The usual opt-out in javac is `--add-exports` but it is not supported for system modules in combination with `--release` (https://bugs.openjdk.org/browse/JDK-8178152) so there is no expectation that scalac could support it. Instead the solution for javac is to replace `--release` with a combination of `-source`, `-target` and a system image for the target version via `--system`. This combination, unlike `--release`, can be used with `--add-exports`. If scalac adds full module support at a later time (with access restrictions enabled by default) it will also need to support `--add-exports` and allow its use in combination with `--system`. I am also un-deprecating `-target` (which was deprecated in favor of `-release`) because it now has a legitimate use in combination with an alternative system image (just like in javac where it is serves the same purpose and is not deprecated, either).
1 parent d76f5d7 commit 27414a4

File tree

3 files changed

+17
-6
lines changed

3 files changed

+17
-6
lines changed

src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,9 @@ trait JFileDirectoryLookup[FileEntryType <: ClassRepresentation] extends Directo
129129

130130
object JrtClassPath {
131131
import java.nio.file._, java.net.URI
132-
private val jrtClassPathCache = new FileBasedCache[Unit, JrtClassPath]()
132+
private val jrtClassPathCache = new FileBasedCache[Option[String], JrtClassPath]()
133133
private val ctSymClassPathCache = new FileBasedCache[String, CtSymClassPath]()
134-
def apply(release: Option[String], closeableRegistry: CloseableRegistry): Option[ClassPath] = {
134+
def apply(release: Option[String], systemPath: Option[String], closeableRegistry: CloseableRegistry): Option[ClassPath] = {
135135
import scala.util.Properties._
136136
if (!isJavaAtLeast("9")) None
137137
else {
@@ -157,8 +157,13 @@ object JrtClassPath {
157157
}
158158
case _ =>
159159
try {
160-
val fs = FileSystems.getFileSystem(URI.create("jrt:/"))
161-
val classPath = jrtClassPathCache.getOrCreate((), Nil, () => new JrtClassPath(fs), closeableRegistry, false)
160+
val classPath = jrtClassPathCache.getOrCreate(systemPath, Nil, () => {
161+
val fs = systemPath match {
162+
case Some(javaHome) => FileSystems.newFileSystem(URI.create("jrt:/"), util.Collections.singletonMap("java.home", javaHome))
163+
case None => FileSystems.getFileSystem(URI.create("jrt:/"))
164+
}
165+
new JrtClassPath(fs, systemPath.isDefined)
166+
}, closeableRegistry, false)
162167
Some(classPath)
163168
} catch {
164169
case _: ProviderNotFoundException | _: FileSystemNotFoundException => None
@@ -176,7 +181,7 @@ object JrtClassPath {
176181
*
177182
* The implementation assumes that no classes exist in the empty package.
178183
*/
179-
final class JrtClassPath(fs: java.nio.file.FileSystem) extends ClassPath with NoSourcePaths {
184+
final class JrtClassPath(fs: java.nio.file.FileSystem, closeFS: Boolean) extends ClassPath with NoSourcePaths with Closeable {
180185
import java.nio.file.Path, java.nio.file._
181186
type F = Path
182187
private val dir: Path = fs.getPath("/packages")
@@ -223,6 +228,9 @@ final class JrtClassPath(fs: java.nio.file.FileSystem) extends ClassPath with No
223228
}.take(1).toList.headOption
224229
}
225230
}
231+
232+
def close(): Unit =
233+
if (closeFS) fs.close()
226234
}
227235

228236
/**

src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ trait StandardScalaSettings { _: MutableSettings =>
3737
val javaextdirs = PathSetting ("-javaextdirs", "Override java extdirs classpath.", Defaults.javaExtDirs)
3838
val sourcepath = PathSetting ("-sourcepath", "Specify location(s) of source files.", "") // Defaults.scalaSourcePath
3939
val rootdir = PathSetting ("-rootdir", "The absolute path of the project root directory, usually the git/scm checkout. Used by -Wconf.", "") withAbbreviation "--root-directory"
40+
val systemPath = PathSetting ("-system", "Override location of Java system modules", "") withAbbreviation "--system"
4041

4142
/** Other settings.
4243
*/
@@ -62,8 +63,10 @@ trait StandardScalaSettings { _: MutableSettings =>
6263
val current = setting.value.toInt
6364
if (!isJavaAtLeast("9") && current > 8) errorFn.apply("-release is only supported on JVM 9 and higher")
6465
if (target.valueSetByUser.map(_.toInt > current).getOrElse(false)) errorFn("-release cannot be less than -target")
66+
if (systemPath.isSetByUser) errorFn("-release cannot be used with -system")
6567
}
6668
def releaseValue: Option[String] = release.valueSetByUser
69+
def systemPathValue: Option[String] = systemPath.valueSetByUser
6770
val target =
6871
ChoiceSetting("-target", "target", "Target platform for object files. All JVM 1.5 - 1.7 targets are deprecated.", AllTargetVersions, DefaultTargetVersion)
6972
.withPreSetHook(normalizeTarget)

src/compiler/scala/tools/util/PathResolver.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ final class PathResolver(settings: Settings, closeableRegistry: CloseableRegistr
271271
sourcesInPath(sourcePath) // 7. The Scala source path.
272272
)
273273

274-
private def jrt: Option[ClassPath] = JrtClassPath.apply(settings.releaseValue, closeableRegistry)
274+
private def jrt: Option[ClassPath] = JrtClassPath.apply(settings.releaseValue, settings.systemPathValue, closeableRegistry)
275275

276276
lazy val containers = basis.flatten.distinct
277277

0 commit comments

Comments
 (0)