Options.java revision 3034:c8206f440046
1/* 2 * Copyright (c) 2014, 2015, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 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 26package com.sun.tools.sjavac.options; 27 28import java.nio.file.Path; 29import java.util.ArrayList; 30import java.util.Arrays; 31import java.util.Collection; 32import java.util.HashMap; 33import java.util.List; 34import java.util.Map; 35import java.util.Set; 36import java.util.HashSet; 37 38import com.sun.tools.sjavac.Transformer; 39import com.sun.tools.sjavac.Util; 40 41/** 42 * Instances of this class represent values for sjavac command line options. 43 * 44 * <p><b>This is NOT part of any supported API. 45 * If you write code that depends on this, you do so at your own risk. 46 * This code and its internal interfaces are subject to change or 47 * deletion without notice.</b> 48 */ 49public class Options { 50 51 // Output directories 52 private Path destDir, genSrcDir, headerDir, stateDir; 53 54 // Input directories 55 private List<SourceLocation> sources = new ArrayList<>(); 56 private List<SourceLocation> sourceSearchPaths = new ArrayList<>(); 57 private List<SourceLocation> classSearchPaths = new ArrayList<>(); 58 private List<SourceLocation> moduleSearchPaths = new ArrayList<>(); 59 60 private String logLevel = "info"; 61 62 private Set<String> permitted_artifacts = new HashSet<>(); 63 private boolean permitUnidentifiedArtifacts = false; 64 private boolean permitSourcesInDefaultPackage = false; 65 66 private Path sourceReferenceList; 67 private int numCores = 4; 68 private String implicitPolicy = "none"; 69 private List<String> javacArgs = new ArrayList<>(); 70 71 private Map<String, Transformer> trRules = new HashMap<>(); 72 73 private boolean startServer = false; 74 75 // Server configuration string 76 private String serverConf; 77 78 /** Get the policy for implicit classes */ 79 public String getImplicitPolicy() { 80 return implicitPolicy; 81 } 82 83 /** Get the path for generated sources (or null if no such path is set) */ 84 public Path getGenSrcDir() { 85 return genSrcDir; 86 } 87 88 /** Get the path for the destination directory */ 89 public Path getDestDir() { 90 return destDir; 91 } 92 93 /** Get the path for the header directory (or null if no such path is set) */ 94 public Path getHeaderDir() { 95 return headerDir; 96 } 97 98 /** Get the path for the state directory, defaults to destDir. */ 99 public Path getStateDir() { 100 return stateDir; 101 } 102 103 /** Get all source locations for files to be compiled */ 104 public List<SourceLocation> getSources() { 105 return sources; 106 } 107 108 /** 109 * Get all paths to search for classes in .java format. (Java-files in 110 * found here should not be compiled. 111 */ 112 public List<SourceLocation> getSourceSearchPaths() { 113 return sourceSearchPaths; 114 } 115 116 /** Get all paths to search for classes in. */ 117 public List<SourceLocation> getClassSearchPath() { 118 return classSearchPaths; 119 } 120 121 /** Get all paths to search for modules in. */ 122 public List<SourceLocation> getModuleSearchPaths() { 123 return moduleSearchPaths; 124 } 125 126 /** Get the log level. */ 127 public String getLogLevel() { 128 return logLevel; 129 } 130 131 /** Returns true iff the artifact is permitted in the output dir. */ 132 public boolean isUnidentifiedArtifactPermitted(String f) { 133 return permitted_artifacts.contains(f); 134 } 135 136 /** Returns true iff artifacts in the output directories should be kept, 137 * even if they would not be generated in a clean build. */ 138 public boolean areUnidentifiedArtifactsPermitted() { 139 return permitUnidentifiedArtifacts; 140 } 141 142 /** Returns true iff sources in the default package should be permitted. */ 143 public boolean isDefaultPackagePermitted() { 144 return permitSourcesInDefaultPackage; 145 } 146 147 /** Get the path to the list of reference sources (or null if none is set) */ 148 public Path getSourceReferenceList() { 149 return sourceReferenceList; 150 } 151 152 /** Get the number of cores to be used by sjavac */ 153 public int getNumCores() { 154 return numCores; 155 } 156 157 /** Returns all arguments relevant to javac but irrelevant to sjavac. */ 158 public List<String> getJavacArgs() { 159 return javacArgs; 160 } 161 162 /** 163 * Get a map which maps suffixes to transformers (for example 164 * ".java" {@literal ->} CompileJavaPackages) 165 */ 166 public Map<String, Transformer> getTranslationRules() { 167 return trRules; 168 } 169 170 /** Return true iff a new server should be started */ 171 public boolean startServerFlag() { 172 return startServer; 173 } 174 175 /** Return the server configuration string. */ 176 public String getServerConf() { 177 return serverConf; 178 } 179 180 /** 181 * Parses the given argument array and returns a corresponding Options 182 * instance. 183 */ 184 public static Options parseArgs(String... args) { 185 Options options = new Options(); 186 options.new ArgDecoderOptionHelper().traverse(args); 187 return options; 188 } 189 190 /** Returns true iff a .java file is among the javac arguments */ 191 public boolean isJavaFilesAmongJavacArgs() { 192 for (String javacArg : javacArgs) 193 if (javacArg.endsWith(".java")) 194 return true; 195 return false; 196 } 197 198 /** 199 * Returns a string representation of the options that affect the result of 200 * the compilation. (Used for saving the state of the options used in a 201 * previous compile.) 202 */ 203 public String getStateArgsString() { 204 205 // Local utility class for collecting the arguments 206 class StateArgs { 207 208 private List<String> args = new ArrayList<>(); 209 210 void addArg(Option opt) { 211 args.add(opt.arg); 212 } 213 214 void addArg(Option opt, Object val) { 215 addArg(opt); 216 args.add(val.toString()); 217 } 218 219 void addSourceLocations(Option opt, List<SourceLocation> locs) { 220 for (SourceLocation sl : locs) { 221 for (String pkg : sl.includes) addArg(Option.I, pkg); 222 for (String pkg : sl.excludes) addArg(Option.X, pkg); 223 for (String f : sl.excludedFiles) addArg(Option.XF, f); 224 for (String f : sl.includedFiles) addArg(Option.IF, f); 225 addArg(opt, sl.getPath()); 226 } 227 } 228 229 String getResult() { 230 String result = ""; 231 for (String s : args) 232 result += s + " "; 233 return result.trim(); 234 } 235 236 public void addAll(Collection<String> toAdd) { 237 args.addAll(toAdd); 238 } 239 } 240 241 StateArgs args = new StateArgs(); 242 243 // Directories 244 if (genSrcDir != null) 245 args.addArg(Option.S, genSrcDir.normalize()); 246 247 if (headerDir != null) 248 args.addArg(Option.H, headerDir.normalize()); 249 250 if (destDir != null) 251 args.addArg(Option.D, destDir.normalize()); 252 253 if (stateDir != null) 254 args.addArg(Option.STATE_DIR, stateDir.normalize()); 255 256 // Source roots 257 args.addSourceLocations(Option.SRC, sources); 258 args.addSourceLocations(Option.SOURCEPATH, sourceSearchPaths); 259 args.addSourceLocations(Option.CLASSPATH, classSearchPaths); 260 args.addSourceLocations(Option.MODULEPATH, moduleSearchPaths); 261 262 // Boolean options 263 if (permitSourcesInDefaultPackage) 264 args.addArg(Option.PERMIT_SOURCES_WITHOUT_PACKAGE); 265 266 for (String f : permitted_artifacts) { 267 args.addArg(Option.PERMIT_ARTIFACT, f); 268 } 269 270 if (permitUnidentifiedArtifacts) 271 args.addArg(Option.PERMIT_UNIDENTIFIED_ARTIFACTS); 272 273 // Translation rules 274 for (Map.Entry<String, Transformer> tr : trRules.entrySet()) { 275 String val = tr.getKey() + "=" + tr.getValue().getClass().getName(); 276 args.addArg(Option.TR, val); 277 } 278 279 // Javac args 280 args.addAll(javacArgs); 281 282 return args.getResult(); 283 } 284 285 286 /** Extract the arguments to be passed on to javac. */ 287 public String[] prepJavacArgs() { 288 List<String> args = new ArrayList<>(); 289 290 // Output directories 291 args.add("-d"); 292 args.add(destDir.toString()); 293 294 if (getGenSrcDir() != null) { 295 args.add("-s"); 296 args.add(genSrcDir.toString()); 297 } 298 299 if (headerDir != null) { 300 args.add("-h"); 301 args.add(headerDir.toString()); 302 } 303 304 // Prep sourcepath 305 List<SourceLocation> sourcepath = new ArrayList<>(); 306 sourcepath.addAll(sources); 307 sourcepath.addAll(sourceSearchPaths); 308 if (sourcepath.size() > 0) { 309 args.add("-sourcepath"); 310 args.add(concatenateSourceLocations(sourcepath)); 311 } 312 313 // Prep classpath 314 if (classSearchPaths.size() > 0) { 315 args.add("-classpath"); 316 args.add(concatenateSourceLocations(classSearchPaths)); 317 } 318 319 // Enable dependency generation 320 args.add("-XDcompletionDeps=source,class"); 321 322 // This can't be anything but 'none'. Enforced by sjavac main method. 323 args.add("-implicit:" + implicitPolicy); 324 325 // If this option is not used, Object for instance is erroneously 326 // picked up from PLATFORM_CLASS_PATH instead of CLASS_PATH. 327 // 328 // Discussing this further led to the decision of letting bootclasspath 329 // be a dummy (empty) directory when building the JDK. 330 //args.add("-XXuserPathsFirst"); 331 332 // Append javac-options (i.e. pass through options not recognized by 333 // sjavac to javac.) 334 args.addAll(javacArgs); 335 336 return args.toArray(new String[args.size()]); 337 } 338 339 // Helper method to join a list of source locations separated by 340 // File.pathSeparator 341 private static String concatenateSourceLocations(List<SourceLocation> locs) { 342 String s = ""; 343 for (SourceLocation loc : locs) 344 s += (s.isEmpty() ? "" : java.io.File.pathSeparator) + loc.getPath(); 345 return s; 346 } 347 348 // OptionHelper that records the traversed options in this Options instance. 349 private class ArgDecoderOptionHelper extends OptionHelper { 350 351 List<String> includes, excludes, includeFiles, excludeFiles; 352 { 353 resetFilters(); 354 } 355 356 boolean headerProvided = false; 357 boolean genSrcProvided = false; 358 boolean stateProvided = false; 359 360 @Override 361 public void reportError(String msg) { 362 throw new IllegalArgumentException(msg); 363 } 364 365 @Override 366 public void sourceRoots(List<Path> paths) { 367 sources.addAll(createSourceLocations(paths)); 368 } 369 370 @Override 371 public void exclude(String exclPattern) { 372 exclPattern = Util.normalizeDriveLetter(exclPattern); 373 excludes.add(exclPattern); 374 } 375 376 @Override 377 public void include(String inclPattern) { 378 inclPattern = Util.normalizeDriveLetter(inclPattern); 379 includes.add(inclPattern); 380 } 381 382 @Override 383 public void excludeFile(String exclFilePattern) { 384 exclFilePattern = Util.normalizeDriveLetter(exclFilePattern); 385 excludeFiles.add(exclFilePattern); 386 } 387 388 @Override 389 public void includeFile(String inclFilePattern) { 390 inclFilePattern = Util.normalizeDriveLetter(inclFilePattern); 391 includeFiles.add(inclFilePattern); 392 } 393 394 @Override 395 public void addTransformer(String suffix, Transformer tr) { 396 if (trRules.containsKey(suffix)) { 397 reportError("More than one transformer specified for " + 398 "suffix " + suffix + "."); 399 return; 400 } 401 trRules.put(suffix, tr); 402 } 403 404 @Override 405 public void sourcepath(List<Path> paths) { 406 sourceSearchPaths.addAll(createSourceLocations(paths)); 407 } 408 409 @Override 410 public void modulepath(List<Path> paths) { 411 moduleSearchPaths.addAll(createSourceLocations(paths)); 412 } 413 414 @Override 415 public void classpath(List<Path> paths) { 416 classSearchPaths.addAll(createSourceLocations(paths)); 417 } 418 419 @Override 420 public void numCores(int n) { 421 numCores = n; 422 } 423 424 @Override 425 public void logLevel(String level) { 426 logLevel = level; 427 } 428 429 @Override 430 public void compareFoundSources(Path referenceList) { 431 sourceReferenceList = referenceList; 432 } 433 434 @Override 435 public void permitArtifact(String f) { 436 permitted_artifacts.add(f); 437 } 438 439 @Override 440 public void permitUnidentifiedArtifacts() { 441 permitUnidentifiedArtifacts = true; 442 } 443 444 @Override 445 public void permitDefaultPackage() { 446 permitSourcesInDefaultPackage = true; 447 } 448 449 @Override 450 public void serverConf(String conf) { 451 if (serverConf != null) 452 reportError("Can not specify more than one server configuration."); 453 else 454 serverConf = conf; 455 } 456 457 @Override 458 public void implicit(String policy) { 459 implicitPolicy = policy; 460 } 461 462 @Override 463 public void startServerConf(String conf) { 464 if (serverConf != null) 465 reportError("Can not specify more than one server configuration."); 466 else { 467 startServer = true; 468 serverConf = conf; 469 } 470 } 471 472 @Override 473 public void javacArg(String... arg) { 474 javacArgs.addAll(Arrays.asList(arg)); 475 } 476 477 @Override 478 public void destDir(Path dir) { 479 if (destDir != null) { 480 reportError("Destination directory already specified."); 481 return; 482 } 483 destDir = dir.toAbsolutePath(); 484 } 485 486 @Override 487 public void generatedSourcesDir(Path dir) { 488 if (genSrcProvided) { 489 reportError("Directory for generated sources already specified."); 490 return; 491 } 492 genSrcProvided = true; 493 genSrcDir = dir.toAbsolutePath(); 494 } 495 496 @Override 497 public void headerDir(Path dir) { 498 if (headerProvided) { 499 reportError("Header directory already specified."); 500 return; 501 } 502 headerProvided = true; 503 headerDir = dir.toAbsolutePath(); 504 } 505 506 @Override 507 public void stateDir(Path dir) { 508 if (stateProvided) { 509 reportError("State directory already specified."); 510 return; 511 } 512 stateProvided = true; 513 stateDir = dir.toAbsolutePath(); 514 } 515 516 private List<SourceLocation> createSourceLocations(List<Path> paths) { 517 List<SourceLocation> result = new ArrayList<>(); 518 for (Path path : paths) { 519 result.add(new SourceLocation( 520 path, 521 includes, 522 excludes, 523 includeFiles, 524 excludeFiles)); 525 } 526 resetFilters(); 527 return result; 528 } 529 530 private void resetFilters() { 531 includes = new ArrayList<>(); 532 excludes = new ArrayList<>(); 533 includeFiles = new ArrayList<>(); 534 excludeFiles = new ArrayList<>(); 535 } 536 } 537 538} 539