1 /*
   2  * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 
  25 
  26 package jdk.tools.jaotc;
  27 
  28 import java.text.MessageFormat;
  29 import java.util.ArrayList;
  30 import java.util.LinkedList;
  31 import java.util.List;
  32 
  33 import jdk.tools.jaotc.collect.ClassSearch;
  34 import jdk.tools.jaotc.collect.ClassSource;
  35 import jdk.tools.jaotc.collect.SearchFor;
  36 import jdk.tools.jaotc.collect.SearchPath;
  37 import jdk.tools.jaotc.collect.classname.ClassNameSourceProvider;
  38 import jdk.tools.jaotc.collect.directory.DirectorySourceProvider;
  39 import jdk.tools.jaotc.collect.jar.JarSourceProvider;
  40 import jdk.tools.jaotc.collect.module.ModuleSourceProvider;
  41 
  42 final class Options {
  43     List<SearchFor> files = new LinkedList<>();
  44     String osName;
  45     String outputName = defaultOutputName();
  46     String methodList;
  47     List<ClassSource> sources = new ArrayList<>();
  48     String linkerpath = null;
  49     SearchPath searchPath = new SearchPath();
  50 
  51     /**
  52      * We don't see scaling beyond 16 threads.
  53      */
  54     private static final int COMPILER_THREADS = 16;
  55 
  56     int threads = Integer.min(COMPILER_THREADS, Runtime.getRuntime().availableProcessors());
  57 
  58     boolean ignoreClassLoadingErrors;
  59     boolean exitOnError;
  60     boolean info;
  61     boolean verbose;
  62     boolean debug;
  63     boolean help;
  64     boolean version;
  65     boolean compileWithAssertions;
  66     boolean tiered;
  67 
  68     private String defaultOutputName() {
  69         osName = System.getProperty("os.name");
  70         String name = "unnamed.";
  71         String ext;
  72 
  73         switch (osName) {
  74             case "Linux":
  75                 ext = "so";
  76                 break;
  77             case "Mac OS X":
  78                 ext = "dylib";
  79                 break;
  80             default:
  81                 if (osName.startsWith("Windows")) {
  82                     ext = "dll";
  83                 } else {
  84                     ext = "so";
  85                 }
  86         }
  87 
  88         return name + ext;
  89     }
  90 
  91     static class BadArgs extends Exception {
  92         private static final long serialVersionUID = 1L;
  93         final String key;
  94         final Object[] args;
  95         boolean showUsage;
  96 
  97         BadArgs(String key, Object... args) {
  98             super(MessageFormat.format(key, args));
  99             this.key = key;
 100             this.args = args;
 101         }
 102 
 103         BadArgs showUsage(boolean b) {
 104             showUsage = b;
 105             return this;
 106         }
 107     }
 108 
 109     abstract static class Option {
 110         final String help;
 111         final boolean hasArg;
 112         final String[] aliases;
 113 
 114         Option(String help, boolean hasArg, String... aliases) {
 115             this.help = help;
 116             this.hasArg = hasArg;
 117             this.aliases = aliases;
 118         }
 119 
 120         boolean isHidden() {
 121             return false;
 122         }
 123 
 124         boolean matches(String opt) {
 125             for (String a : aliases) {
 126                 if (a.equals(opt)) {
 127                     return true;
 128                 } else if (opt.startsWith("--") && hasArg && opt.startsWith(a + "=")) {
 129                     return true;
 130                 }
 131             }
 132             return false;
 133         }
 134 
 135         boolean ignoreRest() {
 136             return false;
 137         }
 138 
 139         abstract void process(Main task, String opt, String arg) throws BadArgs;
 140     }
 141 
 142     static Option[] recognizedOptions = {new Option("  --output <file>            Output file name", true, "--output") {
 143         @Override
 144         void process(Main task, String opt, String arg) {
 145             String name = arg;
 146             task.options.outputName = name;
 147         }
 148     }, new Option("  --class-name <class names> List of classes to compile", true, "--class-name", "--classname") {
 149         @Override
 150         void process(Main task, String opt, String arg) {
 151             task.options.files.addAll(ClassSearch.makeList(ClassNameSourceProvider.TYPE, arg));
 152         }
 153     }, new Option("  --jar <jarfiles>           List of jar files to compile", true, "--jar") {
 154         @Override
 155         void process(Main task, String opt, String arg) {
 156             task.options.files.addAll(ClassSearch.makeList(JarSourceProvider.TYPE, arg));
 157         }
 158     }, new Option("  --module <modules>         List of modules to compile", true, "--module") {
 159         @Override
 160         void process(Main task, String opt, String arg) {
 161             task.options.files.addAll(ClassSearch.makeList(ModuleSourceProvider.TYPE, arg));
 162         }
 163     }, new Option("  --directory <dirs>         List of directories where to search for files to compile", true, "--directory") {
 164         @Override
 165         void process(Main task, String opt, String arg) {
 166             task.options.files.addAll(ClassSearch.makeList(DirectorySourceProvider.TYPE, arg));
 167         }
 168     }, new Option("  --search-path <dirs>       List of directories where to search for specified files", true, "--search-path") {
 169         @Override
 170         void process(Main task, String opt, String arg) {
 171             String[] elements = arg.split(":");
 172             task.options.searchPath.add(elements);
 173         }
 174     }, new Option("  --compile-commands <file>  Name of file with compile commands", true, "--compile-commands") {
 175         @Override
 176         void process(Main task, String opt, String arg) {
 177             task.options.methodList = arg;
 178         }
 179     }, new Option("  --compile-for-tiered       Generate profiling code for tiered compilation", false, "--compile-for-tiered") {
 180         @Override
 181         void process(Main task, String opt, String arg) {
 182             task.options.tiered = true;
 183         }
 184     }, new Option("  --compile-with-assertions  Compile with java assertions", false, "--compile-with-assertions") {
 185         @Override
 186         void process(Main task, String opt, String arg) {
 187             task.options.compileWithAssertions = true;
 188         }
 189     }, new Option("  --compile-threads <number> Number of compilation threads to be used", true, "--compile-threads", "--threads") {
 190         @Override
 191         void process(Main task, String opt, String arg) {
 192             int threads = Integer.parseInt(arg);
 193             final int available = Runtime.getRuntime().availableProcessors();
 194             if (threads <= 0) {
 195                 task.warning("invalid number of threads specified: {0}, using: {1}", threads, available);
 196                 threads = available;
 197             }
 198             if (threads > available) {
 199                 task.warning("too many threads specified: {0}, limiting to: {1}", threads, available);
 200             }
 201             task.options.threads = Integer.min(threads, available);
 202         }
 203     }, new Option("  --ignore-errors            Ignores all exceptions thrown during class loading", false, "--ignore-errors") {
 204         @Override
 205         void process(Main task, String opt, String arg) {
 206             task.options.ignoreClassLoadingErrors = true;
 207         }
 208     }, new Option("  --exit-on-error            Exit on compilation errors", false, "--exit-on-error") {
 209         @Override
 210         void process(Main task, String opt, String arg) {
 211             task.options.exitOnError = true;
 212         }
 213     }, new Option("  --info                     Print information during compilation", false, "--info") {
 214         @Override
 215         void process(Main task, String opt, String arg) throws BadArgs {
 216             task.options.info = true;
 217         }
 218     }, new Option("  --verbose                  Print verbose information", false, "--verbose") {
 219         @Override
 220         void process(Main task, String opt, String arg) throws BadArgs {
 221             task.options.info = true;
 222             task.options.verbose = true;
 223         }
 224     }, new Option("  --debug                    Print debug information", false, "--debug") {
 225         @Override
 226         void process(Main task, String opt, String arg) throws BadArgs {
 227             task.options.info = true;
 228             task.options.verbose = true;
 229             task.options.debug = true;
 230         }
 231     }, new Option("  -? -h --help               Print this help message", false, "--help", "-h", "-?") {
 232         @Override
 233         void process(Main task, String opt, String arg) {
 234             task.options.help = true;
 235         }
 236     }, new Option("  --version                  Version information", false, "--version") {
 237         @Override
 238         void process(Main task, String opt, String arg) {
 239             task.options.version = true;
 240         }
 241     }, new Option("  --linker-path              Full path to linker executable", true, "--linker-path") {
 242         @Override
 243         void process(Main task, String opt, String arg) {
 244             task.options.linkerpath = arg;
 245         }
 246     }, new Option("  -J<flag>                   Pass <flag> directly to the runtime system", false, "-J") {
 247         @Override
 248         void process(Main task, String opt, String arg) {
 249         }
 250     }};
 251 
 252     static void handleOptions(Main task, String[] args) throws BadArgs {
 253         if (args.length == 0) {
 254             task.options.help = true;
 255             return;
 256         }
 257 
 258         // Make checkstyle happy.
 259         int i = 0;
 260         while (i < args.length) {
 261             String arg = args[i];
 262 
 263             if (arg.charAt(0) == '-') {
 264                 Option option = getOption(arg);
 265                 String param = null;
 266 
 267                 if (option.hasArg) {
 268                     if (arg.startsWith("--") && arg.indexOf('=') > 0) {
 269                         param = arg.substring(arg.indexOf('=') + 1, arg.length());
 270                     } else if (i + 1 < args.length) {
 271                         param = args[++i];
 272                     }
 273 
 274                     if (param == null || param.isEmpty() || param.charAt(0) == '-') {
 275                         throw new BadArgs("missing argument for option: {0}", arg).showUsage(true);
 276                     }
 277                 }
 278 
 279                 option.process(task, arg, param);
 280 
 281                 if (option.ignoreRest()) {
 282                     break;
 283                 }
 284             } else {
 285                 task.options.files.add(new SearchFor(arg));
 286             }
 287             i++;
 288         }
 289     }
 290 
 291     static Option getOption(String name) throws BadArgs {
 292         for (Option o : recognizedOptions) {
 293             if (o.matches(name)) {
 294                 return o;
 295             }
 296         }
 297         throw new BadArgs("unknown option: {0}", name).showUsage(true);
 298     }
 299 
 300 }