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 }