2

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

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

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

旁白:这种有序链接在 30 年前很常见,当时我曾经在 DEC PDP-11 小型计算机上链接 Fortran IV 和 Macro-11 程序。当我即将放弃时,我想尝试摆弄 jlink 的订购

模块信息.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 命令。请注意, now 出现在它所依赖的 the 之后。

#! /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逐步构建一个符号表,将符号映射到地址,从左到右沿着模块路径工作并解析(查找地址)它具有地址的符号并添加它发现的新符号条目可以是用于解析后续模块中的调用。如果模块路径的顺序正确,则每个符号都将在此过程中得到解析。如果模块路径的顺序不正确,则会出现尚未解析的符号。在运行图像时,用户必须添加模块来解析剩余的符号。

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

4

1 回答 1

2

正如@AlanBateman在他的评论中所说

指定给 --module-path 的模块路径是目录或模块的路径。因此,如果您指定具有同一模块不同版本的多个位置,则顺序确实很重要。

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

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

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

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

新的 JMOD 格式超越了 JAR 文件,将本机代码、配置文件和其他类型的数据自然地(如果有的话)包含在 JAR 文件中。JMOD文件用于打包JDK本身的模块;如果需要,开发人员也可以使用它们来打包自己的模块。

JMOD 文件可以在编译时和链接时使用,但不能在运行时使用。通常,要在运行时支持它们,我们需要准备好动态提取和链接本机代码库。这在大多数平台上都是可行的,尽管它可能非常棘手,而且我们还没有看到很多需要此功能的用例,因此为简单起见,我们选择在此版本中限制 JMOD 文件的实用程序。

使用时,jlink您应该链接到可用的 JMOD 文件。如果库不提供 JMOD 文件,则链接到 JAR 文件。

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

于 2018-11-12T14:41:44.267 回答