Skip to content

Commit

Permalink
Add support for custom modules via the module path
Browse files Browse the repository at this point in the history
  • Loading branch information
jerboaa committed Feb 26, 2024
1 parent 48a3577 commit e0484eb
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
Expand Down Expand Up @@ -406,14 +407,54 @@ private JlinkConfiguration initJlinkConfig() throws BadArgs {
}
finder = newModuleFinder(options.modulePath, options.limitMods, roots);
}
boolean isLinkFromRuntime = options.modulePath.isEmpty();
// In case of custom modules outside the JDK we may
// have a non-empty module path, which doesn't include
// java.base. In that case take the JDK modules from the
// current run-time image.
if (finder.find("java.base").isEmpty()) {
isLinkFromRuntime = true;
ModuleFinder runtimeImageFinder = ModuleFinder.ofSystem();
finder = combinedFinders(finder, runtimeImageFinder, options.limitMods, roots);
}


return new JlinkConfiguration(options.output,
roots,
finder,
options.modulePath.isEmpty(),
isLinkFromRuntime,
options.ignoreModifiedRuntime);
}

private ModuleFinder combinedFinders(ModuleFinder finder,
ModuleFinder runtimeImageFinder, Set<String> limitMods,
Set<String> roots) {
ModuleFinder combined = new ModuleFinder() {

@Override
public Optional<ModuleReference> find(String name) {
Optional<ModuleReference> basic = runtimeImageFinder.find(name);
if (basic.isEmpty()) {
return finder.find(name);
}
return basic;
}

@Override
public Set<ModuleReference> findAll() {
Set<ModuleReference> all = new HashSet<>();
all.addAll(runtimeImageFinder.findAll());
all.addAll(finder.findAll());
return Collections.unmodifiableSet(all);
}
};
// if limitmods is specified then limit the universe
if (limitMods != null && !limitMods.isEmpty()) {
return limitFinder(combined, limitMods, Objects.requireNonNull(roots));
}
return combined;
}

private void createImage(JlinkConfiguration config) throws Exception {
if (options.output == null) {
throw taskHelper.newBadArgs("err.output.must.be.specified").showUsage(true);
Expand Down Expand Up @@ -633,14 +674,13 @@ private static ImageHelper createImageProvider(JlinkConfiguration config,
.orElse(Runtime.version());

Set<Archive> archives = mods.entrySet().stream()
.map(e -> config.linkFromRuntimeImage() ? new JRTArchive(e.getKey(), e.getValue(), !config.ignoreModifiedRuntime())
: newArchive(e.getKey(), e.getValue(), version, ignoreSigning))
.map(e -> newArchive(e.getKey(), e.getValue(), version, ignoreSigning, config))
.collect(Collectors.toSet());

return new ImageHelper(archives, targetPlatform, retainModulesPath);
}

private static Archive newArchive(String module, Path path, Runtime.Version version, boolean ignoreSigning) {
private static Archive newArchive(String module, Path path, Runtime.Version version, boolean ignoreSigning, JlinkConfiguration config) {
if (path.toString().endsWith(".jmod")) {
return new JmodArchive(module, path);
} else if (path.toString().endsWith(".jar")) {
Expand All @@ -667,6 +707,12 @@ private static Archive newArchive(String module, Path path, Runtime.Version vers
}
}
return modularJarArchive;
} else if (config.linkFromRuntimeImage()) {
// This is after jmod and modular jar branches, since, in runtime link
// mode custom - JDK external modules - are only supported via the
// module path. Directory module paths are not supported since those
// clash with JRT-FS based archives of JRTArchive.
return new JRTArchive(module, path, !config.ignoreModifiedRuntime());
} else if (Files.isDirectory(path)) {
Path modInfoPath = path.resolve("module-info.class");
if (Files.isRegularFile(modInfoPath)) {
Expand Down
32 changes: 30 additions & 2 deletions test/jdk/tools/jlink/JmodLess/AbstractLinkableRuntimeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,12 @@ protected Path jlinkUsingImage(JlinkSpec spec, OutputAnalyzerHandler handler, Pr
if (spec.getExtraJlinkOpts() != null && !spec.getExtraJlinkOpts().isEmpty()) {
jlinkCmd.addAll(spec.getExtraJlinkOpts());
}
if (spec.getModulePath() != null) {
for (String mp: spec.getModulePath()) {
jlinkCmd.add("--module-path");
jlinkCmd.add(mp);
}
}
jlinkCmd = Collections.unmodifiableList(jlinkCmd); // freeze
System.out.println("DEBUG: jmod-less jlink command: " + jlinkCmd.stream().collect(
Collectors.joining(" ")));
Expand Down Expand Up @@ -360,11 +366,13 @@ static class JlinkSpec {
final List<String> unexpectedLocations;
final String[] expectedFiles;
final List<String> extraJlinkOpts;
final List<String> modulePath;

JlinkSpec(Path imageToUse, Helper helper, String name, List<String> modules,
String validatingModule, List<String> expectedLocations,
List<String> unexpectedLocations, String[] expectedFiles,
List<String> extraJlinkOpts) {
List<String> extraJlinkOpts,
List<String> modulePath) {
this.imageToUse = imageToUse;
this.helper = helper;
this.name = name;
Expand All @@ -374,6 +382,7 @@ static class JlinkSpec {
this.unexpectedLocations = unexpectedLocations;
this.expectedFiles = expectedFiles;
this.extraJlinkOpts = extraJlinkOpts;
this.modulePath = modulePath;
}

public Path getImageToUse() {
Expand Down Expand Up @@ -411,6 +420,10 @@ public String[] getExpectedFiles() {
public List<String> getExtraJlinkOpts() {
return extraJlinkOpts;
}

public List<String> getModulePath() {
return modulePath;
}
}

static class JlinkSpecBuilder {
Expand All @@ -423,6 +436,7 @@ static class JlinkSpecBuilder {
List<String> unexpectedLocations = new ArrayList<>();
List<String> expectedFiles = new ArrayList<>();
List<String> extraJlinkOpts = new ArrayList<>();
List<String> modulePath = new ArrayList<>();

JlinkSpec build() {
if (imageToUse == null) {
Expand All @@ -437,7 +451,16 @@ JlinkSpec build() {
if (validatingModule == null) {
throw new IllegalStateException("No module specified for after generation validation!");
}
return new JlinkSpec(imageToUse, helper, name, modules, validatingModule, expectedLocations, unexpectedLocations, expectedFiles.toArray(new String[0]), extraJlinkOpts);
return new JlinkSpec(imageToUse,
helper,
name,
modules,
validatingModule,
expectedLocations,
unexpectedLocations,
expectedFiles.toArray(new String[0]),
extraJlinkOpts,
modulePath);
}

JlinkSpecBuilder imagePath(Path image) {
Expand Down Expand Up @@ -465,6 +488,11 @@ JlinkSpecBuilder validatingModule(String module) {
return this;
}

JlinkSpecBuilder addModulePath(String modulePath) {
this.modulePath.add(modulePath);
return this;
}

JlinkSpecBuilder expectedLocation(String location) {
expectedLocations.add(location);
return this;
Expand Down
17 changes: 8 additions & 9 deletions test/jdk/tools/jlink/JmodLess/CustomModuleJlinkTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@


/*
* FIXME: This needs thinking about
* @test
* @summary Test jmod-less jlink with a custom module
* @requires (vm.compMode != "Xcomp" & os.maxMemory >= 2g)
* @requires (jlink.runtime.linkable & vm.compMode != "Xcomp" & os.maxMemory >= 2g)
* @library ../../lib /test/lib
* @enablePreview
* @modules java.base/jdk.internal.classfile
Expand All @@ -54,22 +54,21 @@ void runTest(Helper helper) throws Exception {
String customModule = "leaf1";
helper.generateDefaultJModule(customModule);

// create a base image including jdk.jlink and the leaf1 module. This will
// add the leaf1 module's module path.
// create a base image for runtime linking
Path jlinkImage = createRuntimeLinkImage(new BaseJlinkSpecBuilder()
.helper(helper)
.name("cmod-jlink")
.addModule(customModule)
.validatingModule("java.base") // not used
.addModule("java.base")
.validatingModule("java.base")
.build());

// Now that the base image already includes the 'leaf1' module, it should
// be possible to jlink it again, asking for *only* the 'leaf1' plugin even
// though we won't have any jmods directories present.
// Next jlink using the current runtime image for java.base, but take
// the custom module from the module path.
Path finalImage = jlinkUsingImage(new JlinkSpecBuilder()
.imagePath(jlinkImage)
.helper(helper)
.name(customModule)
.addModulePath(helper.defaultModulePath(false))
.expectedLocation(String.format("/%s/%s/com/foo/bar/X.class", customModule, customModule))
.addModule(customModule)
.validatingModule(customModule)
Expand Down

0 comments on commit e0484eb

Please sign in to comment.