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