JEP 247:针对旧平台版本进行编译
概括
进行增强javac
,使其可以编译 Java 程序以在选定的旧版本平台上运行。
动机
javac
提供了两个命令行选项-source
和-target
,分别可用于选择编译器接受的 Java 语言版本和生成的类文件的版本。不过,默认情况下,javac
会针对最新版本的平台 API 进行编译。因此,编译的程序可能会意外使用仅在当前版本的平台中可用的 API。无论传递给-source
和选项的值如何,此类程序都无法在旧版本的平台上运行-target
。这是一个长期的可用性痛点,因为用户期望通过使用这些选项,他们将获得可以在 -target 指定的平台版本上运行的类文件。
描述
定义了一个新的命令行选项--release
,它自动配置编译器以生成将链接到给定平台版本的实现的类文件。--release N
大致相当于:
- 对于 N < 9:
-source N -target N -bootclasspath <documented-APIs-from-N>
, - 对于 N >= 9:
-source N -target N --system <documented-APIs-from-N>
.
对于 N < 9,记录的 API 由 JDK N 的 javac 默认引导类路径上的公共 API 组成。
对于 N >= 9,记录的 API 包括 (i) 从 JDK 映像中的那些模 块导出的 API,这些模块是 JDK N 文档的一部分; (ii) 从 jdk.unsupported 模块导出的 API(记录在 JEP 260 中)。也就是说,记录的 API 主要是由JDK 映像中的模块与 JDK N 记录的模块_交集_导出的 API。JDK 映像中没有其他模块可观察到。如果使用--limit-modules,那么它只能进一步限制可观察的模块,而不能观察额外的模块。不允许访问 JDK 映像中模块的内部结构。
该--release N
选项与影响平台或系统类集的其他选项不兼容。这包括:
- 对于 N < 9:
-bootclasspath
、-Xbootclasspath
、-Xbootclasspath/a:
、-Xbootclasspath/p:
、-endorseddirs
、-Djava.endorsed.dirs
、-extdirs
、-Djava.ext.dirs
设置平台类的选项。 - 对于 N >= 9:设置系统模块(即 JDK 映像中的模块)的
--system
和选项,以及修改系统模块的、和选项。 (对于非系统模块,即不属于 JDK 映像的模块,允许使用、、 和。)--upgrade-module-path``--add-exports``--add-reads``--patch-module``--add-exports``--add-reads``--patch-module
- 对于任何 N,
-source
和-target
选项,因为它们会自动设置为 N。
假定记录的 API 仅在主要版本中才会更改。对于旧情况(JAX-WS 在 JDK 6 的次要版本中从 2.0 更新到 2.1),JAX-WS 2.1 被视为已记录的 API。
作为实现的限制--release
,编译期间不使用给定目标平台的 Unicode 版本;而是使用当前平台的 Unicode 版本。
执行
对于 JDK N 且--release M
M < N,需要平台版本 M 的已记录 API 的签名数据。此数据存储在该$JDK_ROOT/lib/ct.sym
文件中,该文件与 JDK 8 中的同名文件相似但不相同。该ct.sym
文件是一个 ZIP 文件,其中包含与目标平台版本中的类文件相对应的精简类文件。
对于 JDK N 和 JDK --release N
,JDK 自己的映像用作要编译的类文件的源。然而,可观察模块的列表仅限于已记录的模块和 jdk.unsupported 模块。
风险和假设
JDK 源代码存储库需要包含过去版本的平台 API 的描述。描述的大小可能相当大,并且生成的 JDK 版本也会更大。我们已尽力减少这些空间开销。