/* * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package jdk.tools.jaotc; import java.text.MessageFormat; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import jdk.tools.jaotc.collect.ClassSearch; import jdk.tools.jaotc.collect.ClassSource; import jdk.tools.jaotc.collect.SearchFor; import jdk.tools.jaotc.collect.SearchPath; import jdk.tools.jaotc.collect.classname.ClassNameSourceProvider; import jdk.tools.jaotc.collect.directory.DirectorySourceProvider; import jdk.tools.jaotc.collect.jar.JarSourceProvider; import jdk.tools.jaotc.collect.module.ModuleSourceProvider; final class Options { List files = new LinkedList<>(); String osName; String outputName = defaultOutputName(); String methodList; List sources = new ArrayList<>(); String linkerpath = null; SearchPath searchPath = new SearchPath(); /** * We don't see scaling beyond 16 threads. */ private static final int COMPILER_THREADS = 16; int threads = Integer.min(COMPILER_THREADS, Runtime.getRuntime().availableProcessors()); boolean ignoreClassLoadingErrors; boolean exitOnError; boolean info; boolean verbose; boolean debug; boolean help; boolean version; boolean compileWithAssertions; boolean tiered; private String defaultOutputName() { osName = System.getProperty("os.name"); String name = "unnamed."; String ext; switch (osName) { case "Linux": ext = "so"; break; case "Mac OS X": ext = "dylib"; break; default: if (osName.startsWith("Windows")) { ext = "dll"; } else { ext = "so"; } } return name + ext; } static class BadArgs extends Exception { private static final long serialVersionUID = 1L; final String key; final Object[] args; boolean showUsage; BadArgs(String key, Object... args) { super(MessageFormat.format(key, args)); this.key = key; this.args = args; } BadArgs showUsage(boolean b) { showUsage = b; return this; } } abstract static class Option { final String help; final boolean hasArg; final String[] aliases; Option(String help, boolean hasArg, String... aliases) { this.help = help; this.hasArg = hasArg; this.aliases = aliases; } boolean isHidden() { return false; } boolean matches(String opt) { for (String a : aliases) { if (a.equals(opt)) { return true; } else if (opt.startsWith("--") && hasArg && opt.startsWith(a + "=")) { return true; } } return false; } boolean ignoreRest() { return false; } abstract void process(Main task, String opt, String arg) throws BadArgs; } static Option[] recognizedOptions = {new Option(" --output Output file name", true, "--output") { @Override void process(Main task, String opt, String arg) { String name = arg; task.options.outputName = name; } }, new Option(" --class-name List of classes to compile", true, "--class-name", "--classname") { @Override void process(Main task, String opt, String arg) { task.options.files.addAll(ClassSearch.makeList(ClassNameSourceProvider.TYPE, arg)); } }, new Option(" --jar List of jar files to compile", true, "--jar") { @Override void process(Main task, String opt, String arg) { task.options.files.addAll(ClassSearch.makeList(JarSourceProvider.TYPE, arg)); } }, new Option(" --module List of modules to compile", true, "--module") { @Override void process(Main task, String opt, String arg) { task.options.files.addAll(ClassSearch.makeList(ModuleSourceProvider.TYPE, arg)); } }, new Option(" --directory List of directories where to search for files to compile", true, "--directory") { @Override void process(Main task, String opt, String arg) { task.options.files.addAll(ClassSearch.makeList(DirectorySourceProvider.TYPE, arg)); } }, new Option(" --search-path List of directories where to search for specified files", true, "--search-path") { @Override void process(Main task, String opt, String arg) { String[] elements = arg.split(":"); task.options.searchPath.add(elements); } }, new Option(" --compile-commands Name of file with compile commands", true, "--compile-commands") { @Override void process(Main task, String opt, String arg) { task.options.methodList = arg; } }, new Option(" --compile-for-tiered Generate profiling code for tiered compilation", false, "--compile-for-tiered") { @Override void process(Main task, String opt, String arg) { task.options.tiered = true; } }, new Option(" --compile-with-assertions Compile with java assertions", false, "--compile-with-assertions") { @Override void process(Main task, String opt, String arg) { task.options.compileWithAssertions = true; } }, new Option(" --compile-threads Number of compilation threads to be used", true, "--compile-threads", "--threads") { @Override void process(Main task, String opt, String arg) { int threads = Integer.parseInt(arg); final int available = Runtime.getRuntime().availableProcessors(); if (threads <= 0) { task.warning("invalid number of threads specified: {0}, using: {1}", threads, available); threads = available; } if (threads > available) { task.warning("too many threads specified: {0}, limiting to: {1}", threads, available); } task.options.threads = Integer.min(threads, available); } }, new Option(" --ignore-errors Ignores all exceptions thrown during class loading", false, "--ignore-errors") { @Override void process(Main task, String opt, String arg) { task.options.ignoreClassLoadingErrors = true; } }, new Option(" --exit-on-error Exit on compilation errors", false, "--exit-on-error") { @Override void process(Main task, String opt, String arg) { task.options.exitOnError = true; } }, new Option(" --info Print information during compilation", false, "--info") { @Override void process(Main task, String opt, String arg) throws BadArgs { task.options.info = true; } }, new Option(" --verbose Print verbose information", false, "--verbose") { @Override void process(Main task, String opt, String arg) throws BadArgs { task.options.info = true; task.options.verbose = true; } }, new Option(" --debug Print debug information", false, "--debug") { @Override void process(Main task, String opt, String arg) throws BadArgs { task.options.info = true; task.options.verbose = true; task.options.debug = true; } }, new Option(" -? -h --help Print this help message", false, "--help", "-h", "-?") { @Override void process(Main task, String opt, String arg) { task.options.help = true; } }, new Option(" --version Version information", false, "--version") { @Override void process(Main task, String opt, String arg) { task.options.version = true; } }, new Option(" --linker-path Full path to linker executable", true, "--linker-path") { @Override void process(Main task, String opt, String arg) { task.options.linkerpath = arg; } }, new Option(" -J Pass directly to the runtime system", false, "-J") { @Override void process(Main task, String opt, String arg) { } }}; static void handleOptions(Main task, String[] args) throws BadArgs { if (args.length == 0) { task.options.help = true; return; } // Make checkstyle happy. int i = 0; while (i < args.length) { String arg = args[i]; if (arg.charAt(0) == '-') { Option option = getOption(arg); String param = null; if (option.hasArg) { if (arg.startsWith("--") && arg.indexOf('=') > 0) { param = arg.substring(arg.indexOf('=') + 1, arg.length()); } else if (i + 1 < args.length) { param = args[++i]; } if (param == null || param.isEmpty() || param.charAt(0) == '-') { throw new BadArgs("missing argument for option: {0}", arg).showUsage(true); } } option.process(task, arg, param); if (option.ignoreRest()) { break; } } else { task.options.files.add(new SearchFor(arg)); } i++; } } static Option getOption(String name) throws BadArgs { for (Option o : recognizedOptions) { if (o.matches(name)) { return o; } } throw new BadArgs("unknown option: {0}", name).showUsage(true); } }