< prev index next >

make/src/classes/build/tools/module/ImageBuilder.java

Print this page




   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package build.tools.module;
  27 
  28 import jdk.internal.jimage.Archive;
  29 import jdk.internal.jimage.ImageFile;
  30 import jdk.internal.jimage.ImageModules;
  31 
  32 import java.io.BufferedReader;
  33 import java.io.File;
  34 import java.io.IOException;
  35 import java.io.InputStream;
  36 import java.io.InputStreamReader;
  37 import java.io.PrintWriter;
  38 import java.io.UncheckedIOException;
  39 import java.nio.ByteOrder;
  40 import java.nio.file.Files;
  41 import java.nio.file.InvalidPathException;
  42 import java.nio.file.Path;
  43 import java.nio.file.Paths;
  44 import java.nio.file.attribute.PosixFilePermission;
  45 import java.util.ArrayList;
  46 import java.util.Collection;
  47 import java.util.HashMap;
  48 import java.util.HashSet;
  49 import java.util.LinkedList;
  50 import java.util.List;
  51 import java.util.Map;
  52 import java.util.Optional;
  53 import java.util.Set;
  54 import java.util.stream.Collectors;

  55 
  56 /**
  57  * A tool for building a runtime image.
  58  *
  59  * java build.tools.module.ImageBuilder <options> --output <path> top/modules.xml,...
  60  *  Possible options are:
  61  *  --cmds                  Location of native commands
  62  *  --configs               Location of config files
  63  *  --help                  Print this usage message
  64  *  --classes               Location of module classes files
  65  *  --libs                  Location of native libraries
  66  *  --mods                  Comma separated list of module names
  67  *  --output                Location of the output path
  68  *  --endian                Byte order of the target runtime; {little,big}
  69  */
  70 class ImageBuilder {
  71     static class BadArgs extends Exception {
  72         private static final long serialVersionUID = 0L;
  73         BadArgs(String format, Object... args) {
  74             super(String.format(format, args));
  75             this.format = format;
  76             this.args = args;
  77         }
  78         BadArgs showUsage(boolean b) {
  79             showUsage = b;
  80             return this;
  81         }
  82         final String format;
  83         final Object[] args;
  84         boolean showUsage;
  85     }
  86 
  87     static abstract class Option {






  88         final boolean hasArg;
  89         final String[] aliases;
  90         Option(boolean hasArg, String... aliases) {




  91             this.hasArg = hasArg;


  92             this.aliases = aliases;
  93         }
  94         boolean isHidden() {
  95             return false;
  96         }
  97         boolean matches(String opt) {
  98             for (String a : aliases) {
  99                 if (a.equals(opt)) {
 100                     return true;
 101                 } else if (opt.startsWith("--") && hasArg && opt.startsWith(a + "=")) {
 102                     return true;
 103                 }
 104             }
 105             return false;
 106         }
 107         boolean ignoreRest() {
 108             return false;
 109         }
 110         abstract void process(ImageBuilder task, String opt, String arg) throws BadArgs;
 111         abstract String description();




 112     }
 113 
 114     private static Path CWD = Paths.get("");
 115 
 116     private static List<Path> splitPath(String arg, String separator)
 117         throws BadArgs
 118     {
 119         List<Path> paths = new ArrayList<>();
 120         for (String p: arg.split(separator)) {
 121             if (p.length() > 0) {
 122                 try {
 123                     Path path = CWD.resolve(p);
 124                     if (Files.notExists(path))
 125                         throw new BadArgs("path not found: %s", path);
 126                     paths.add(path);
 127                 } catch (InvalidPathException x) {
 128                     throw new BadArgs("path not valid: %s", p);
 129                 }
 130             }
 131         }
 132         return paths;
 133     }
 134 
 135     static Option[] recognizedOptions = {
 136         new Option(true, "--cmds") {
 137             void process(ImageBuilder task, String opt, String arg) throws BadArgs {
 138                 task.options.cmds = splitPath(arg, File.pathSeparator);
 139             }
 140             String description() { return "Location of native commands"; }
 141         },
 142         new Option(true, "--configs") {
 143             void process(ImageBuilder task, String opt, String arg) throws BadArgs {
 144                 task.options.configs = splitPath(arg, File.pathSeparator);
 145             }
 146             String description() { return "Location of config files"; }
 147         },
 148         new Option(false, "--help") {
 149             void process(ImageBuilder task, String opt, String arg) {
 150                 task.options.help = true;
 151             }
 152             String description() { return "Print this usage message"; }
 153         },
 154         new Option(true, "--classes") {
 155             void process(ImageBuilder task, String opt, String arg) throws BadArgs {
 156                 task.options.classes = splitPath(arg, File.pathSeparator);
 157             }
 158             String description() { return "Location of module classes files"; }
 159         },
 160         new Option(true, "--libs") {
 161             void process(ImageBuilder task, String opt, String arg) throws BadArgs {
 162                 task.options.libs = splitPath(arg, File.pathSeparator);
 163             }
 164             String description() { return "Location of native libraries"; }
 165         },
 166         new Option(true, "--mods") {
 167             void process(ImageBuilder task, String opt, String arg) throws BadArgs {
 168                 for (String mn : arg.split(",")) {
 169                     if (mn.isEmpty())
 170                         throw new BadArgs("Module not found", mn);
 171                     task.options.mods.add(mn);
 172                 }

 173             }
 174             String description() { return "Comma separated list of module names"; }
 175         },
 176         new Option(true, "--output") {
 177             void process(ImageBuilder task, String opt, String arg) throws BadArgs {
 178                 Path path = Paths.get(arg);
 179                 task.options.output = path;
 180             }
 181             String description() { return "Location of the output path"; }
 182         },
 183         new Option(true, "--endian") {
 184             void process(ImageBuilder task, String opt, String arg) throws BadArgs {
 185                 if (arg.equals("little"))
 186                     task.options.endian = ByteOrder.LITTLE_ENDIAN;
 187                 else if (arg.equals("big"))
 188                     task.options.endian = ByteOrder.BIG_ENDIAN;
 189                 else
 190                     throw new BadArgs("Unknown byte order " + arg);
 191             }
 192             String description() { return "Byte order of the target runtime; {little,big}"; }
 193         }
 194     };
 195 
 196     private final Options options = new Options();
 197 
 198     private PrintWriter log;
 199     void setLog(PrintWriter out) {
 200         log = out;
 201     }
 202 
 203     Set<Module> moduleGraph = new java.util.HashSet<>();
 204 
 205     /** Module list files */
 206     private static final String BOOT_MODULES = "boot.modules";
 207     private static final String EXT_MODULES = "ext.modules";
 208 
 209     /**
 210      * Result codes.
 211      */
 212     static final int EXIT_OK = 0,       // Completed with no errors.
 213                      EXIT_ERROR = 1,    // Completed but reported errors.


 353         Collection<String> modules = resolve(options.mods);
 354         log.print(modules.stream().collect(Collectors.joining(" ")));
 355         ImageFileHelper imageHelper = new ImageFileHelper(modules);
 356         imageHelper.createModularImage(options.output);
 357 
 358         // jspawnhelper, might be in lib or lib/ARCH
 359         Path jspawnhelper = Paths.get("jspawnhelper");
 360         Path lib = options.output.resolve("lib");
 361         Optional<Path> helper = Files.walk(lib, 2)
 362                                      .filter(f -> f.getFileName().equals(jspawnhelper))
 363                                      .findFirst();
 364         if (helper.isPresent())
 365             helper.get().toFile().setExecutable(true, false);
 366     }
 367 
 368     private class ImageFileHelper {
 369         final Collection<String> modules;
 370         final Set<String> bootModules;
 371         final Set<String> extModules;
 372         final Set<String> appModules;
 373         final ImageModules imf;
 374 
 375         ImageFileHelper(Collection<String> modules) throws IOException {
 376             this.modules = modules;
 377             this.bootModules = modulesFor(BOOT_MODULES).stream()
 378                      .filter(modules::contains)
 379                      .collect(Collectors.toSet());
 380             this.extModules = modulesFor(EXT_MODULES).stream()
 381                     .filter(modules::contains)
 382                     .collect(Collectors.toSet());
 383             this.appModules = modules.stream()
 384                     .filter(m -> !bootModules.contains(m) && !extModules.contains(m))


 385                     .collect(Collectors.toSet());
 386 
 387             this.imf = new ImageModules(bootModules, extModules, appModules);
 388         }
 389 
 390         void createModularImage(Path output) throws IOException {
 391             Set<Archive> archives = modules.stream()






 392                                             .map(this::toModuleArchive)
 393                                             .collect(Collectors.toSet());
 394             ImageFile.create(output, archives, imf, options.endian);


 395         }
 396 
 397         ModuleArchive toModuleArchive(String mn) {
 398             return new ModuleArchive(mn,
 399                                      moduleToPath(mn, options.classes, false/*true*/),
 400                                      moduleToPath(mn, options.cmds, false),
 401                                      moduleToPath(mn, options.libs, false),
 402                                      moduleToPath(mn, options.configs, false));
 403         }
 404 
 405         private Path moduleToPath(String name, List<Path> paths, boolean expect) {
 406             Set<Path> foundPaths = new HashSet<>();
 407             if (paths != null) {
 408                 for (Path p : paths) {
 409                     Path rp = p.resolve(name);
 410                     if (Files.exists(rp))
 411                         foundPaths.add(rp);
 412                 }
 413             }
 414             if (foundPaths.size() > 1)




   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package build.tools.module;
  27 
  28 import jdk.internal.jimage.Archive;


  29 
  30 import java.io.BufferedReader;
  31 import java.io.File;
  32 import java.io.IOException;
  33 import java.io.InputStream;
  34 import java.io.InputStreamReader;
  35 import java.io.PrintWriter;

  36 import java.nio.ByteOrder;
  37 import java.nio.file.Files;
  38 import java.nio.file.InvalidPathException;
  39 import java.nio.file.Path;
  40 import java.nio.file.Paths;

  41 import java.util.ArrayList;
  42 import java.util.Collection;
  43 import java.util.HashMap;
  44 import java.util.HashSet;
  45 import java.util.LinkedList;
  46 import java.util.List;
  47 import java.util.Map;
  48 import java.util.Optional;
  49 import java.util.Set;
  50 import java.util.stream.Collectors;
  51 import jdk.internal.jimage.ImageFileCreator;
  52 
  53 /**
  54  * A tool for building a runtime image.
  55  *
  56  * java build.tools.module.ImageBuilder <options> --output <path> top/modules.xml,...
  57  *  Possible options are:
  58  *  --cmds                  Location of native commands
  59  *  --configs               Location of config files
  60  *  --help                  Print this usage message
  61  *  --classes               Location of module classes files
  62  *  --libs                  Location of native libraries
  63  *  --mods                  Comma separated list of module names
  64  *  --output                Location of the output path
  65  *  --endian                Byte order of the target runtime; {little,big}
  66  */
  67 class ImageBuilder {
  68     static class BadArgs extends Exception {
  69         private static final long serialVersionUID = 0L;
  70         BadArgs(String format, Object... args) {
  71             super(String.format(format, args));
  72             this.format = format;
  73             this.args = args;
  74         }
  75         BadArgs showUsage(boolean b) {
  76             showUsage = b;
  77             return this;
  78         }
  79         final String format;
  80         final Object[] args;
  81         boolean showUsage;
  82     }
  83 
  84     static class Option {
  85 
  86         interface Processing {
  87 
  88             void process(ImageBuilder task, String opt, String arg) throws BadArgs;
  89         }
  90 
  91         final boolean hasArg;
  92         final String[] aliases;
  93         final String description;
  94         final Processing processing;
  95 
  96         Option(boolean hasArg, String description, Processing processing,
  97                 String... aliases) {
  98             this.hasArg = hasArg;
  99             this.description = description;
 100             this.processing = processing;
 101             this.aliases = aliases;
 102         }
 103         boolean isHidden() {
 104             return false;
 105         }
 106         boolean matches(String opt) {
 107             for (String a : aliases) {
 108                 if (a.equals(opt)) {
 109                     return true;
 110                 } else if (opt.startsWith("--") && hasArg && opt.startsWith(a + "=")) {
 111                     return true;
 112                 }
 113             }
 114             return false;
 115         }
 116         boolean ignoreRest() {
 117             return false;
 118         }
 119         void process(ImageBuilder task, String opt, String arg) throws BadArgs {
 120             processing.process(task, opt, arg);
 121         }
 122         String description() {
 123             return description;
 124         }
 125     }
 126 
 127     private static Path CWD = Paths.get("");
 128 
 129     private static List<Path> splitPath(String arg, String separator)
 130         throws BadArgs
 131     {
 132         List<Path> paths = new ArrayList<>();
 133         for (String p: arg.split(separator)) {
 134             if (p.length() > 0) {
 135                 try {
 136                     Path path = CWD.resolve(p);
 137                     if (Files.notExists(path))
 138                         throw new BadArgs("path not found: %s", path);
 139                     paths.add(path);
 140                 } catch (InvalidPathException x) {
 141                     throw new BadArgs("path not valid: %s", p);
 142                 }
 143             }
 144         }
 145         return paths;
 146     }
 147 
 148     static Option[] recognizedOptions = {
 149         new Option(true, "Location of native commands", (task, opt, arg) -> {

 150             task.options.cmds = splitPath(arg, File.pathSeparator);
 151         }, "--cmds"),
 152         new Option(true, "Location of config files", (task, opt, arg) -> {



 153             task.options.configs = splitPath(arg, File.pathSeparator);
 154         }, "--configs"),
 155         new Option(false, "Print this usage message", (task, opt, arg) -> {



 156             task.options.help = true;
 157         }, "--help"),
 158         new Option(true, "Location of module classes files", (task, opt, arg) -> {



 159             task.options.classes = splitPath(arg, File.pathSeparator);
 160         }, "--classes"),
 161         new Option(true, "Location of native libraries", (task, opt, arg) -> {



 162             task.options.libs = splitPath(arg, File.pathSeparator);
 163         }, "--libs"),
 164         new Option(true, "Comma separated list of module names",
 165         (task, opt, arg) -> {


 166             for (String mn : arg.split(",")) {
 167                 if (mn.isEmpty()) {
 168                     throw new BadArgs("Module not found", mn);

 169                 }
 170                 task.options.mods.add(mn);
 171             }
 172         }, "--mods"),
 173         new Option(true, "Location of the output path", (task, opt, arg) -> {


 174             Path path = Paths.get(arg);
 175             task.options.output = path;
 176         }, "--output"),
 177         new Option(true, "Byte order of the target runtime; {little,big}",
 178         (task, opt, arg) -> {
 179             if (arg.equals("little")) {


 180                 task.options.endian = ByteOrder.LITTLE_ENDIAN;
 181             } else if (arg.equals("big")) {
 182                 task.options.endian = ByteOrder.BIG_ENDIAN;
 183             } else {
 184                 throw new BadArgs("Unknown byte order " + arg);
 185             }
 186         }, "--endian")

 187     };
 188 
 189     private final Options options = new Options();
 190 
 191     private PrintWriter log;
 192     void setLog(PrintWriter out) {
 193         log = out;
 194     }
 195 
 196     Set<Module> moduleGraph = new java.util.HashSet<>();
 197 
 198     /** Module list files */
 199     private static final String BOOT_MODULES = "boot.modules";
 200     private static final String EXT_MODULES = "ext.modules";
 201 
 202     /**
 203      * Result codes.
 204      */
 205     static final int EXIT_OK = 0,       // Completed with no errors.
 206                      EXIT_ERROR = 1,    // Completed but reported errors.


 346         Collection<String> modules = resolve(options.mods);
 347         log.print(modules.stream().collect(Collectors.joining(" ")));
 348         ImageFileHelper imageHelper = new ImageFileHelper(modules);
 349         imageHelper.createModularImage(options.output);
 350 
 351         // jspawnhelper, might be in lib or lib/ARCH
 352         Path jspawnhelper = Paths.get("jspawnhelper");
 353         Path lib = options.output.resolve("lib");
 354         Optional<Path> helper = Files.walk(lib, 2)
 355                                      .filter(f -> f.getFileName().equals(jspawnhelper))
 356                                      .findFirst();
 357         if (helper.isPresent())
 358             helper.get().toFile().setExecutable(true, false);
 359     }
 360 
 361     private class ImageFileHelper {
 362         final Collection<String> modules;
 363         final Set<String> bootModules;
 364         final Set<String> extModules;
 365         final Set<String> appModules;

 366 
 367         ImageFileHelper(Collection<String> modules) throws IOException {
 368             this.modules = modules;
 369             this.bootModules = modulesFor(BOOT_MODULES).stream()
 370                     .filter(modules::contains)
 371                     .collect(Collectors.toSet());
 372             this.extModules = modulesFor(EXT_MODULES).stream()
 373                     .filter(modules::contains)
 374                     .collect(Collectors.toSet());
 375             this.appModules = modules.stream()
 376                     .filter(m -> m.length() != 0 &&
 377                                  !bootModules.contains(m) &&
 378                                  !extModules.contains(m))
 379                     .collect(Collectors.toSet());


 380         }
 381 
 382         void createModularImage(Path output) throws IOException {
 383             Set<Archive> bootArchives = bootModules.stream()
 384                     .map(this::toModuleArchive)
 385                     .collect(Collectors.toSet());
 386             Set<Archive> extArchives = extModules.stream()
 387                     .map(this::toModuleArchive)
 388                     .collect(Collectors.toSet());
 389             Set<Archive> appArchives = appModules.stream()
 390                     .map(this::toModuleArchive)
 391                     .collect(Collectors.toSet());
 392             ImageFileCreator.create(output, "bootmodules", bootArchives, options.endian);
 393             ImageFileCreator.create(output, "extmodules", extArchives, options.endian);
 394             ImageFileCreator.create(output, "appmodules", appArchives, options.endian);
 395         }
 396 
 397         ModuleArchive toModuleArchive(String mn) {
 398             return new ModuleArchive(mn,
 399                                      moduleToPath(mn, options.classes, false/*true*/),
 400                                      moduleToPath(mn, options.cmds, false),
 401                                      moduleToPath(mn, options.libs, false),
 402                                      moduleToPath(mn, options.configs, false));
 403         }
 404 
 405         private Path moduleToPath(String name, List<Path> paths, boolean expect) {
 406             Set<Path> foundPaths = new HashSet<>();
 407             if (paths != null) {
 408                 for (Path p : paths) {
 409                     Path rp = p.resolve(name);
 410                     if (Files.exists(rp))
 411                         foundPaths.add(rp);
 412                 }
 413             }
 414             if (foundPaths.size() > 1)


< prev index next >