Skip to content

Commit

Permalink
Fix add resource plugin for Windows.
Browse files Browse the repository at this point in the history
jlink on Windows transforms libraries from lib (jmod location)
to bin (final image location). Therefore, the resource plugin,
which tracks native libs needs to do the same transformation
so that the copy from the original image works.
  • Loading branch information
jerboaa committed Jun 13, 2023
1 parent b9eb8e8 commit 6a54be1
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,11 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

import jdk.tools.jlink.internal.Platform;
import jdk.tools.jlink.plugin.ResourcePool;
import jdk.tools.jlink.plugin.ResourcePoolBuilder;
import jdk.tools.jlink.plugin.ResourcePoolEntry;
import jdk.tools.jlink.plugin.ResourcePoolModule;


/**
Expand All @@ -45,6 +47,8 @@
*/
public final class AddJmodResourcesPlugin extends AbstractPlugin {

private static final String BIN_DIRNAME = "bin";
private static final String LIB_DIRNAME = "lib";
private static final String NAME = "add-jmod-resources";
// This ought to be a package-less resource so as to not conflict with
// packages listed in the module descriptors. Making it package-less ensures
Expand All @@ -61,12 +65,23 @@ public AddJmodResourcesPlugin() {

@Override
public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) {
in.transformAndCopy(e -> { ResourcePoolEntry retval = recordAndFilterEntry(e);
Platform targetPlatform = getTargetPlatform(in);
in.transformAndCopy(e -> { ResourcePoolEntry retval = recordAndFilterEntry(e, targetPlatform);
return retval;}, out);
addModuleResourceEntries(out);
return out.build();
}

private Platform getTargetPlatform(ResourcePool in) {
String platform = in.moduleView().findModule("java.base")
.map(ResourcePoolModule::targetPlatform)
.orElse(null);
if (platform == null) {
throw new IllegalStateException("java.base not part of the image?");
}
return Platform.toPlatform(platform);
}

private void addModuleResourceEntries(ResourcePoolBuilder out) {
for (String module: nonClassResEntries.keySet()) {
String mResource = String.format(RESPATH, module);
Expand All @@ -80,24 +95,49 @@ private void addModuleResourceEntries(ResourcePoolBuilder out) {
}
}

private ResourcePoolEntry recordAndFilterEntry(ResourcePoolEntry entry) {
private ResourcePoolEntry recordAndFilterEntry(ResourcePoolEntry entry, Platform platform) {
// Note that the jmod_resources file is a resource file, so we cannot
// add ourselves due to this condition. However, we want to not add
// an old version of the resource file again.
if (entry.type() != ResourcePoolEntry.Type.CLASS_OR_RESOURCE) {
List<String> moduleResources = nonClassResEntries.computeIfAbsent(entry.moduleName(), a -> new ArrayList<>());
String type = Integer.toString(entry.type().ordinal());
String resPathWithoutMod = entry.path().substring(entry.moduleName().length() + 2 /* prefixed and suffixed '/' */);
String resPathWithoutMod = resPathWithoutModule(entry, platform);
moduleResources.add(String.format(TYPE_FILE_FORMAT, type, resPathWithoutMod));
} else if (entry.type() == ResourcePoolEntry.Type.CLASS_OR_RESOURCE &&
String.format(RESPATH, entry.moduleName()).equals(entry.path())) {
// Filter /<module>/jmod_resources file which we create later
return null;
}

return entry;
}

private String resPathWithoutModule(ResourcePoolEntry entry, Platform platform) {
String resPath = entry.path().substring(entry.moduleName().length() + 2 /* prefixed and suffixed '/' */);
if (platform != Platform.WINDOWS) {
return resPath;
}
// For Windows the libraries live in the 'bin' folder rather than the 'lib' folder
// in the final image. Note that going by the NATIVE_LIB type only is insufficient since
// only files with suffix .dll/diz/map/pdb are transplanted to 'bin'.
// See: DefaultImageBuilder.nativeDir()
return nativeDir(entry, resPath);
}

private String nativeDir(ResourcePoolEntry entry, String resPath) {
if (entry.type() != ResourcePoolEntry.Type.NATIVE_LIB) {
return resPath;
}
// precondition: Native lib, windows platform
if (resPath.endsWith(".dll") || resPath.endsWith(".diz")
|| resPath.endsWith(".pdb") || resPath.endsWith(".map")) {
if (resPath.startsWith(LIB_DIRNAME + "/")) {
return BIN_DIRNAME + "/" + resPath.substring((LIB_DIRNAME + "/").length());
}
}
return resPath;
}

@Override
public Set<State> getState() {
return EnumSet.of(State.AUTO_ENABLED, State.FUNCTIONAL);
Expand Down
3 changes: 2 additions & 1 deletion test/jdk/tools/jlink/JLinkTestJmodsLess.java
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,8 @@ private static Path createJavaImageJmodLess(Helper helper, String name, String m

// Expect java.lang.String class
List<String> expectedLocations = List.of("java.lang.String");
Path libjvm = Path.of("lib", "server", System.mapLibraryName("jvm"));
// On Windows jvm.dll is in 'bin' after the jlink
Path libjvm = Path.of((isWindows() ? "bin" : "lib"), "server", System.mapLibraryName("jvm"));
// And expect libjvm (not part of the jimage) to be present in the resulting image
String[] expectedFiles = new String[] { libjvm.toString() };
return jlinkUsingImage(helper, jlinkJmodlessImage, name, module, expectedLocations, expectedFiles, extraOptions);
Expand Down

0 comments on commit 6a54be1

Please sign in to comment.