Skip to content

JEP 247: Compile for Older Platform Versions | 为旧平台版本编译

摘要

增强 javac,使其能够编译 Java 程序以在选择的旧版本平台上运行。

动机

javac 提供了两个命令行选项 -source-target,可以用于选择编译器接受的 Java 语言版本和生成的类文件的版本。然而,默认情况下,javac 编译针对最新版本的平台 API。因此,编译的程序可能会意外地使用仅在当前版本平台中可用的 API。无论传给 -source-target 选项的值如何,这样的程序都无法在旧版本的平台上运行。这是一个长期以来的可用性问题,因为用户期望通过使用这些选项,他们将获得可以在目标平台指定的版本上运行的类文件。

描述

定义了一个新的命令行选项 --release,它自动配置编译器以生成与给定平台版本的实现相链接的类文件。--release N 大致等效于:

  • 对于 N < 9:-source N -target N -bootclasspath <从 N 文档中获取的 API>,
  • 对于 N >= 9:-source N -target N --system <从 N 文档中获取的 API>

对于 N < 9,文档 API 包括 JDK N 的默认 bootclasspath 上的公共 API。

对于 N >= 9,文档 API 包括:(i) 从 JDK N 的文档中属于那些模块导出的 API;(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--upgrade-module-path 选项,以及通过修改系统模块来使用的 --add-exports--add-reads--patch-module 选项。(可以在非系统模块上使用 --add-exports--add-reads--patch-module,即不属于 JDK 镜像的模块。)
  • 对于任何 N,-source-target 选项,因为这些选项会自动设置为 N。

假设文档 API 只会在主要版本中发生变化。对于在 JDK 6 的一个次要版本中将 JAX-WS 从 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 和 --release N,使用 JDK 自身的映像作为编译的类文件源。然而,可观察到的模块列表仅限于文档模块和 jdk.unsupported 模块。

风险和假设

JDK 源代码存储库需要包含过去版本发布的平台 API 的描述。描述的大小可能相当大,并且生成的 JDK 构建将更大。已经尽最大努力减少这些空间开销。