jlink --module-path 是有序路径吗?

Is the jlink --module-path an ordered path?

我一直在尝试通过 Hello World 和 Hello JFX World 程序将我的程序迁移到 jlink。当涉及到 运行 程序时,我遵循的示例似乎指定了 --add-modules。我不明白为什么程序需要在 运行 时间提供它在 jlink 时间提供的信息。

我现在已经成功构建了一个简单的 jlink Hello World 程序,它将 运行 无需 --add-modules 在命令行上。诀窍是更改在 jlink 模块路径上指定的模块的顺序。我不知道为什么会这样。

JDK-9、JDK-10 或 JDK-11 文档中指定或描述的 jlink 行为在哪里?应该如何构建模块路径?

旁白:这种有序的 linking 在 30 年前很常见,当时我曾经在 DEC PDP-11 小型计算机上 link Fortran IV 和 Macro-11 程序.我想尝试摆弄 jlink 的顺序,当时我正要放弃

模块-info.java:

module TestFXord {
    requires javafx.controls;
    exports testfxord to javafx.graphics;
}

TestFXord.java:

package testfxord;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class TestFXord extends Application {

    @Override
    public void start(Stage primaryStage) {

        Button btn = new Button();
        btn.setText("Say 'Hello World'");
        btn.setOnAction((ActionEvent event) -> {
            System.out.println("Hello World!");
        });

        StackPane root = new StackPane();
        root.getChildren().add(btn);
        Scene scene = new Scene(root, 300, 250);

        primaryStage.setTitle("Hello World!");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

}

jlink 命令不产生 运行 可用图像

#! /bin/sh
<jdk-11-path>/bin/jlink --module-path <jdk-11-path>/jmods:<javafx-sdk-11-path>/lib/javafx.base.jar:<javafx-sdk-11-path>/lib/javafx.controls.jar:<javafx-sdk-11-path>/lib/javafx.graphics.jar:<javafx-jmods-11-path>:<path-to-projects>/TestFXord/dist/TestFXord.jar --add-modules TestFXord --strip-debug --launcher TestFXord=TestFXord/testfxord.TestFXord --output dist/jlink/TestFXord

jlink 命令构建了一个 运行nable 图像。请注意,现在紧跟在它所依赖的之后。

#! /bin/sh
    <jdk-11-path>/bin/jlink --module-path <jdk-11-path>/jmods:<javafx-jmods-11-path>:<javafx-sdk-11-path>/lib/javafx.base.jar:<javafx-sdk-11-path>/lib/javafx.controls.jar:<javafx-sdk-11-path>/lib/javafx.graphics.jar:<path-to-projects>/TestFXord/dist/TestFXord.jar --add-modules TestFXord --strip-debug --launcher TestFXord=TestFXord/testfxord.TestFXord --output dist/jlink/TestFXord

我估计 jlink 逐步构建一个符号 table,将符号映射到地址,从左到右沿着模块路径工作并解析 (找到地址)它有地址的符号,并添加它找到的新符号条目,这些条目可用于解析以后模块中的调用。如果模块路径的顺序正确,则在此过程中将解析每个符号。如果模块路径的顺序不正确,则会有未解析的符号。当涉及到 运行 图像时,用户将不得不添加模块来解析剩余的符号。

换句话说,我不认为 jlink 返回列表来解析它刚刚发现的早期模块中的符号。考虑一下,我怀疑这样做的原因是每次添加新模块时返回搜索未解析的符号对于大型应用程序来说需要更长的 linking 过程。听起来对吗?

作为@AlanBateman :

The module path specified to --module-path is a path of directories or modules. So the order does matter if you specify multiple locations that have different versions of the same module.

在您的两个示例中,您都将 JavaFX JMOD 文件和 JavaFX JAR 文件包含在 --module-path 中。不同之处在于您包含它们的顺序。

  • 工作示例:首先是 JMOD 文件
    • jlink 将使用 JMOD 文件中包含的模块
  • 非工作示例:JMOD 文件是最后一个
    • jlink 将使用 JAR 文件中包含的模块

JavaFX SDK 附带的 JAR 文件不包含任何必要的本机代码。如果您 link 针对 JAR 文件,生成的图像将无法执行。

但是,JMOD 文件包含必要的本机代码。事实上,将本机代码与 Java 代码捆绑在一起是实现 JMOD 格式的主要原因之一。来自 JEP 261:

The new JMOD format goes beyond JAR files to include native code, configuration files, and other kinds of data that do not fit naturally, if at all, into JAR files. JMOD files are used to package the modules of the JDK itself; they can also be used by developers to package their own modules, if desired.

JMOD files can be used at compile time and link time, but not at run time. To support them at run time would require, in general, that we be prepared to extract and link native-code libraries on-the-fly. This is feasible on most platforms, though it can be very tricky, and we have not seen many use cases that require this capability, so for simplicity we have chosen to limit the utility of JMOD files in this release.

使用 jlink 时,您应该 link 对可用的 JMOD 文件。如果库不提供 JMOD 文件,则 link 针对 JAR 文件。

综上所述,您应该从 --module-path 中完全删除 JavaFX JAR 文件——它们是不必要的并且会造成混淆。