跳到主要内容

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 MM < N,需要平台版本 M 的已记录 API 的签名数据。此数据存储在该$JDK_ROOT/lib/ct.sym文件中,该文件与 JDK 8 中的同名文件相似但不相同。该ct.sym文件是一个 ZIP 文件,其中包含与目标平台版本中的类文件相对应的精简类文件。

对于 JDK N 和 JDK --release N,JDK 自己的映像用作要编译的类文件的源。然而,可观察模块的列表仅限于已记录的模块和 jdk.unsupported 模块。

风险和假设

JDK 源代码存储库需要包含过去版本的平台 API 的描述。描述的大小可能相当大,并且生成的 JDK 版本也会更大。我们已尽力减少这些空间开销。