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 构建将更大。已经尽最大努力减少这些空间开销。