Reputation: 188
I have been experimenting with migrating my programs to jlink via experiments with a Hello World and a Hello JFX World program. The examples I had followed seem to specify --add-modules when it comes to running the program. I do not understand why the program should need information supplied at run-time that it had at jlink time.
I have now successfully built a simple jlink Hello World program that will run without having --add-modules on the command line. The trick was to change the order of the modules specified on the jlink module path. I don't know why this worked.
Where is this jlink behaviour specified or described in JDK-9, JDK-10 or JDK-11 documentation? How should one go about constructing the module-path?
Aside: This sort of ordered linking was common 30 years ago when I used to link Fortran IV and Macro-11 programs on a DEC PDP-11 minicomputer. I thought to try fiddling with the ordering for jlink when I was about to give up
module-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 command that does not produce runnable image
#! /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 command that does build a runnable image. Note that the now appears immediately after the on which it depends.
#! /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
I reckon jlink progressively builds a symbol table, mapping symbols to addresses, working left to right down the module-path and resolves (finding the addresses for) the symbols for which it has an address and adding new symbol entries that it finds that can be used to resolve calls in later modules. If the module-path is in the right order every symbol will be resolved in this process. If the module-path is not in the correct order there will be symbols that have not been resolved. When it comes to running the image the user will have to add-modules to resolve the leftover symbols.
In other words I don't think jlink goes back up the list to resolve symbols in earlier modules it has just discovered. Thinking about it, I suspect the reason this would be done is that going back to search for unresolved symbols every time you add a new module would require a much longer linking process for large applications. Does that sound about right?
Upvotes: 2
Views: 3140
Reputation: 45776
As @AlanBateman said in his comment:
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.
In both your examples you include the JavaFX JMOD files and JavaFX JAR files in the --module-path
. The difference is the order you include them.
jlink
will use the modules contained in the JMOD filesjlink
will use the modules contained in the JAR filesThe JAR files shipped with the JavaFX SDK do not contain any of the necessary native code. If you link against the JAR files the resulting image will fail to execute.
The JMOD files, however, do contain the necessary native code. In fact, bundling native code with Java code is one of the main reasons the JMOD format was implemented. From 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.
When using jlink
you should link against the JMOD files where available. If a library doesn't provide JMOD files then link against the JAR files.
With all that said, you should remove the JavaFX JAR files from the --module-path
altogether—they're unnecessary and cause confusion.
Upvotes: 2