Java 9 编译器中的 --release 标志是什么?

What is the --release flag in the Java 9 compiler?

Java 9 的 javac 有一个新标志 --release:

> javac --help
...

--release <release>
    Compile for a specific VM version. Supported targets: 6, 7, 8, 9

它与 -source-target 标志有何不同?它只是 -source X -target X 的快捷方式吗?

不完全是。

JEP 247: Compile for Older Platform Versions 定义了这个新的命令行选项,--release

We defined a new command-line option, --release, which automatically configures the compiler to produce class files that will link against an implementation of the given platform version. For the platforms predefined in javac, --release N is equivalent to -source N -target N -bootclasspath <bootclasspath-from-N>. (emphasis mine)

所以不,它不等同于 -source N -target N。添加的原因在 "Motivation" 部分中说明:

javac provides two command line options, -source and -target, which can be used to select the version of the Java language accepted by the compiler and the version of the class files it produces, respectively. By default, however, javac compiles against the most-recent version of the platform APIs. The compiled program can therefore accidentally use APIs only available in the current version of the platform. Such programs cannot run on older versions of the platform, regardless of the values passed to the -source and -target. options. This is a long-term usability pain point, since users expect that by using these options they'll get class files that can run on the specified platform version.

简而言之,指定源和目标选项不足以进行交叉编译。因为 javac,默认情况下,针对最新的平台 API 进行编译,所以不能保证它们在旧版本上 运行。您还需要指定与旧版本对应的 -bootclasspath 选项才能正确交叉编译。这将包括正确的 API 版本以进行编译并允许在旧版本上执行。由于它经常被遗忘,因此决定添加一个命令行选项,该选项可以执行正确交叉编译所需的所有操作。

进一步阅读 in the mailing list and Oracle Docs. The original bug was filed here。请注意,由于集成了此选项,JDK 构建已捆绑了对旧版本 API 平台的描述,在 "Risks and Assumptions" 部分中提到。这意味着您不需要在计算机上安装旧版本即可进行交叉编译。

--release X 不仅仅是 -source X -target X 的快捷方式,因为 -source-target 不足以安全地编译到旧版本。您还需要设置一个 -bootclasspath 标志,它必须对应于旧版本(并且这个标志经常被遗忘)。因此,在 Java 9 中,他们制作了一个 --release 标志来替代三个标志:-source-target-bootclasspath.

因此,这是一个编译为 Java 1.7:

的示例
javac --release 7 <source files>

请注意,您甚至不需要在计算机上安装 JDK 7。 JDK 9 已包含防止您意外链接到 JDK 7 中不存在的符号所需的信息。

另一个重要区别是在使用 --release 编译时只能使用 public API:

> javac --add-exports java.base/sun.invoke=ALL-UNNAMED --release 11 Main.java
error: exporting a package from system module java.base is not allowed with --release
1 error

如果要使用内部 API,则必须删除选项 --release:

> javac --add-exports java.base/sun.invoke=ALL-UNNAMED Main.java

> javac --add-exports java.base/sun.invoke=ALL-UNNAMED -source 11 -target 11  Main.java