< prev index next >
src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java
Print this page
@@ -44,27 +44,30 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.nio.file.attribute.PosixFilePermission;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
+import java.util.stream.Stream;
import static java.util.stream.Collectors.*;
import jdk.tools.jlink.internal.BasicImageWriter;
import jdk.tools.jlink.internal.plugins.FileCopierPlugin.SymImageFile;
import jdk.tools.jlink.internal.ExecutableImage;
import jdk.tools.jlink.plugin.ResourcePool;
import jdk.tools.jlink.plugin.ResourcePoolEntry;
import jdk.tools.jlink.plugin.ResourcePoolModule;
+import jdk.tools.jlink.plugin.ResourcePoolModuleView;
import jdk.tools.jlink.plugin.PluginException;
/**
*
* Default Image Builder. This builder creates the default runtime image layout.
@@ -139,35 +142,90 @@
this.root = root;
this.mdir = root.resolve("lib");
Files.createDirectories(mdir);
}
- private void storeFiles(Set<String> modules, Properties release) throws IOException {
+ private void storeFiles(List<String> modules, Properties release) throws IOException {
if (release != null) {
addModules(release, modules);
File r = new File(root.toFile(), "release");
try (FileOutputStream fo = new FileOutputStream(r)) {
release.store(fo, null);
}
}
}
- private void addModules(Properties props, Set<String> modules) throws IOException {
+ private void addModules(Properties props, List<String> modules) throws IOException {
+ int size = modules.size();
StringBuilder builder = new StringBuilder();
int i = 0;
for (String m : modules) {
builder.append(m);
- if (i < modules.size() - 1) {
- builder.append(",");
+ if (i < size - 1) {
+ builder.append(' ');
}
i++;
}
props.setProperty("MODULES", quote(builder.toString()));
}
+ // utility class to (topological) sort the module names
+ static class ModuleNamesSorter {
+ // don't create me!
+ private ModuleNamesSorter() {}
+
+ // return a stream of dependent module names of the given module name
+ private static Stream<String> dependencies(String modName, ResourcePoolModuleView modView) {
+ Optional<ResourcePoolModule> mod = modView.findModule(modName);
+ if (mod.isPresent()) {
+ return mod.get().descriptor().requires().stream().map(ModuleDescriptor.Requires::name);
+ } else {
+ throw new RuntimeException("Missing module: " + modName);
+ }
+ }
+
+ // states for module visit
+ private static enum State {
+ VISITING, VISITED;
+ }
+
+ // topological sort helper
+ private static void tsort(String modName, Map<String, State> state,
+ ResourcePoolModuleView modView, List<String> ret) {
+ state.put(modName, State.VISITING);
+ dependencies(modName, modView).forEach(depModName -> {
+ State st = state.get(depModName);
+ if (st == null) {
+ tsort(depModName, state, modView, ret);
+ } else if (st == State.VISITING) {
+ throw new RuntimeException("Cyclic dependency: " + depModName);
+ }
+ assert st == State.VISITED;
+ });
+ state.put(modName, State.VISITED);
+ ret.add(modName);
+ }
+
+ // entry point to sort module names by topological sort
+ static List<String> sort(Set<String> rootMods, ResourcePoolModuleView modView) {
+ Map<String, State> state = new HashMap<>();
+ List<String> ret = new ArrayList<>();
+ for (String rootMod : rootMods) {
+ State st = state.get(rootMod);
+ if (st == null) {
+ tsort(rootMod, state, modView, ret);
+ } else if (st == State.VISITING) {
+ throw new RuntimeException("Cyclic dependency: " + rootMod);
+ }
+ assert st == State.VISITED;
+ }
+ return ret;
+ }
+ }
+
@Override
- public void storeFiles(ResourcePool files) {
+ public void storeFiles(Set<String> rootModules, ResourcePool files) {
try {
// populate release properties up-front. targetOsName
// field is assigned from there and used elsewhere.
Properties release = releaseProperties(files);
Path bin = root.resolve("bin");
@@ -207,11 +265,12 @@
if (!m.packages().isEmpty()) {
modules.add(m.name());
}
});
- storeFiles(modules, release);
+ storeFiles(ModuleNamesSorter.sort(
+ rootModules.isEmpty()? modules : rootModules, files.moduleView()), release);
if (root.getFileSystem().supportedFileAttributeViews()
.contains("posix")) {
// launchers in the bin directory need execute permission.
// On Windows, "bin" also subdirectories containing jvm.dll.
< prev index next >