langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/client/ClientMain.java
changeset 32335 7df616378cf3
parent 31115 8d8e98052d5d
child 32542 f4e4f4c4f9f4
equal deleted inserted replaced
32334:fd65e32e16b3 32335:7df616378cf3
    23  * questions.
    23  * questions.
    24  */
    24  */
    25 
    25 
    26 package com.sun.tools.sjavac.client;
    26 package com.sun.tools.sjavac.client;
    27 
    27 
    28 import java.io.IOException;
       
    29 import java.io.PrintStream;
    28 import java.io.PrintStream;
    30 import java.nio.file.Files;
       
    31 import java.nio.file.Path;
       
    32 import java.util.ArrayList;
       
    33 import java.util.Collections;
       
    34 import java.util.HashMap;
       
    35 import java.util.HashSet;
       
    36 import java.util.List;
       
    37 import java.util.Map;
       
    38 import java.util.Set;
       
    39 
    29 
    40 import com.sun.tools.sjavac.JavacState;
       
    41 import com.sun.tools.sjavac.Log;
    30 import com.sun.tools.sjavac.Log;
    42 import com.sun.tools.sjavac.Module;
       
    43 import com.sun.tools.sjavac.ProblemException;
       
    44 import com.sun.tools.sjavac.Source;
       
    45 import com.sun.tools.sjavac.Transformer;
       
    46 import com.sun.tools.sjavac.Util;
    31 import com.sun.tools.sjavac.Util;
    47 import com.sun.tools.sjavac.comp.PooledSjavac;
       
    48 import com.sun.tools.sjavac.comp.SjavacImpl;
    32 import com.sun.tools.sjavac.comp.SjavacImpl;
    49 import com.sun.tools.sjavac.options.Options;
    33 import com.sun.tools.sjavac.options.Options;
    50 import com.sun.tools.sjavac.options.SourceLocation;
    34 import com.sun.tools.sjavac.server.CompilationResult;
    51 import com.sun.tools.sjavac.server.Sjavac;
    35 import com.sun.tools.sjavac.server.Sjavac;
    52 
    36 
    53 /**
    37 /**
    54  *  <p><b>This is NOT part of any supported API.
    38  *  <p><b>This is NOT part of any supported API.
    55  *  If you write code that depends on this, you do so at your own risk.
    39  *  If you write code that depends on this, you do so at your own risk.
    72         } catch (IllegalArgumentException e) {
    56         } catch (IllegalArgumentException e) {
    73             Log.error(e.getMessage());
    57             Log.error(e.getMessage());
    74             return -1;
    58             return -1;
    75         }
    59         }
    76 
    60 
    77         Log.setLogLevel(options.getLogLevel());
       
    78 
       
    79         if (!validateOptions(options))
       
    80             return -1;
       
    81 
       
    82         if (!createIfMissing(options.getDestDir()))
       
    83             return -1;
       
    84 
       
    85         if (!createIfMissing(options.getStateDir()))
       
    86             return -1;
       
    87 
       
    88         Path gensrc = options.getGenSrcDir();
       
    89         if (gensrc != null && !createIfMissing(gensrc))
       
    90             return -1;
       
    91 
       
    92         Path hdrdir = options.getHeaderDir();
       
    93         if (hdrdir != null && !createIfMissing(hdrdir))
       
    94             return -1;
       
    95 
       
    96         Log.debug("==========================================================");
    61         Log.debug("==========================================================");
    97         Log.debug("Launching sjavac client with the following parameters:");
    62         Log.debug("Launching sjavac client with the following parameters:");
    98         Log.debug("    " + options.getStateArgsString());
    63         Log.debug("    " + options.getStateArgsString());
    99         Log.debug("==========================================================");
    64         Log.debug("==========================================================");
   100 
    65 
   101         // Load the prev build state database.
    66         // Prepare sjavac object
   102         JavacState javac_state = JavacState.load(options, out, err);
    67         boolean background = Util.extractBooleanOption("background", options.getServerConf(), true);
   103 
    68         Sjavac sjavac;
   104         // Setup the suffix rules from the command line.
    69         // Create an sjavac implementation to be used for compilation
   105         Map<String, Transformer> suffixRules = new HashMap<>();
    70         if (background) {
   106 
    71             try {
   107         // Handling of .java-compilation
    72                 sjavac = new SjavacClient(options);
   108         suffixRules.putAll(javac_state.getJavaSuffixRule());
    73             } catch (PortFileInaccessibleException e) {
   109 
    74                 Log.error("Port file inaccessible.");
   110         // Handling of -copy and -tr
    75                 return -1;
   111         suffixRules.putAll(options.getTranslationRules());
    76             }
   112 
    77         } else {
   113         // All found modules are put here.
    78             sjavac = new SjavacImpl();
   114         Map<String,Module> modules = new HashMap<>();
       
   115         // We start out in the legacy empty no-name module.
       
   116         // As soon as we stumble on a module-info.java file we change to that module.
       
   117         Module current_module = new Module("", "");
       
   118         modules.put("", current_module);
       
   119 
       
   120         // Find all sources, use the suffix rules to know which files are sources.
       
   121         Map<String,Source> sources = new HashMap<>();
       
   122 
       
   123         // Find the files, this will automatically populate the found modules
       
   124         // with found packages where the sources are found!
       
   125         findSourceFiles(options.getSources(),
       
   126                         suffixRules.keySet(),
       
   127                         sources,
       
   128                         modules,
       
   129                         current_module,
       
   130                         options.isDefaultPackagePermitted(),
       
   131                         false);
       
   132 
       
   133         if (sources.isEmpty()) {
       
   134             Log.error("Found nothing to compile!");
       
   135             return -1;
       
   136         }
    79         }
   137 
    80 
   138         // Create a map of all source files that are available for linking. Both -src and
    81         CompilationResult cr = sjavac.compile(args);
   139         // -sourcepath point to such files. It is possible to specify multiple
       
   140         // -sourcepath options to enable different filtering rules. If the
       
   141         // filters are the same for multiple sourcepaths, they may be concatenated
       
   142         // using :(;). Before sending the list of sourcepaths to javac, they are
       
   143         // all concatenated. The list created here is used by the SmartFileWrapper to
       
   144         // make sure only the correct sources are actually available.
       
   145         // We might find more modules here as well.
       
   146         Map<String,Source> sources_to_link_to = new HashMap<>();
       
   147 
    82 
   148         List<SourceLocation> sourceResolutionLocations = new ArrayList<>();
    83         out.print(cr.stdout);
   149         sourceResolutionLocations.addAll(options.getSources());
    84         err.print(cr.stderr);
   150         sourceResolutionLocations.addAll(options.getSourceSearchPaths());
       
   151         findSourceFiles(sourceResolutionLocations,
       
   152                         Collections.singleton(".java"),
       
   153                         sources_to_link_to,
       
   154                         modules,
       
   155                         current_module,
       
   156                         options.isDefaultPackagePermitted(),
       
   157                         true);
       
   158 
    85 
   159         // Find all class files allowable for linking.
    86         if (!background)
   160         // And pickup knowledge of all modules found here.
    87             sjavac.shutdown();
   161         // This cannot currently filter classes inside jar files.
       
   162 //      Map<String,Source> classes_to_link_to = new HashMap<String,Source>();
       
   163 //      findFiles(args, "-classpath", Util.set(".class"), classes_to_link_to, modules, current_module, true);
       
   164 
    88 
   165         // Find all module sources allowable for linking.
    89         return cr.returnCode;
   166 //      Map<String,Source> modules_to_link_to = new HashMap<String,Source>();
       
   167 //      findFiles(args, "-modulepath", Util.set(".class"), modules_to_link_to, modules, current_module, true);
       
   168 
       
   169         // Add the set of sources to the build database.
       
   170         javac_state.now().flattenPackagesSourcesAndArtifacts(modules);
       
   171         javac_state.now().checkInternalState("checking sources", false, sources);
       
   172         javac_state.now().checkInternalState("checking linked sources", true, sources_to_link_to);
       
   173         javac_state.setVisibleSources(sources_to_link_to);
       
   174 
       
   175         int round = 0;
       
   176         printRound(round);
       
   177 
       
   178         // If there is any change in the source files, taint packages
       
   179         // and mark the database in need of saving.
       
   180         javac_state.checkSourceStatus(false);
       
   181 
       
   182         // Find all existing artifacts. Their timestamp will match the last modified timestamps stored
       
   183         // in javac_state, simply because loading of the JavacState will clean out all artifacts
       
   184         // that do not match the javac_state database.
       
   185         javac_state.findAllArtifacts();
       
   186 
       
   187         // Remove unidentified artifacts from the bin, gensrc and header dirs.
       
   188         // (Unless we allow them to be there.)
       
   189         // I.e. artifacts that are not known according to the build database (javac_state).
       
   190         // For examples, files that have been manually copied into these dirs.
       
   191         // Artifacts with bad timestamps (ie the on disk timestamp does not match the timestamp
       
   192         // in javac_state) have already been removed when the javac_state was loaded.
       
   193         if (!options.areUnidentifiedArtifactsPermitted()) {
       
   194             javac_state.removeUnidentifiedArtifacts();
       
   195         }
       
   196         // Go through all sources and taint all packages that miss artifacts.
       
   197         javac_state.taintPackagesThatMissArtifacts();
       
   198 
       
   199         // Check recorded classpath public apis. Taint packages that depend on
       
   200         // classpath classes whose public apis have changed.
       
   201         javac_state.taintPackagesDependingOnChangedClasspathPackages();
       
   202 
       
   203         // Now clean out all known artifacts belonging to tainted packages.
       
   204         javac_state.deleteClassArtifactsInTaintedPackages();
       
   205         // Copy files, for example property files, images files, xml files etc etc.
       
   206         javac_state.performCopying(Util.pathToFile(options.getDestDir()), suffixRules);
       
   207         // Translate files, for example compile properties or compile idls.
       
   208         javac_state.performTranslation(Util.pathToFile(gensrc), suffixRules);
       
   209         // Add any potentially generated java sources to the tobe compiled list.
       
   210         // (Generated sources must always have a package.)
       
   211         Map<String,Source> generated_sources = new HashMap<>();
       
   212 
       
   213         try {
       
   214 
       
   215             Source.scanRoot(Util.pathToFile(options.getGenSrcDir()), Util.set(".java"), null, null, null, null,
       
   216                     generated_sources, modules, current_module, false, true, false);
       
   217             javac_state.now().flattenPackagesSourcesAndArtifacts(modules);
       
   218             // Recheck the the source files and their timestamps again.
       
   219             javac_state.checkSourceStatus(true);
       
   220 
       
   221             // Now do a safety check that the list of source files is identical
       
   222             // to the list Make believes we are compiling. If we do not get this
       
   223             // right, then incremental builds will fail with subtility.
       
   224             // If any difference is detected, then we will fail hard here.
       
   225             // This is an important safety net.
       
   226             javac_state.compareWithMakefileList(Util.pathToFile(options.getSourceReferenceList()));
       
   227 
       
   228             // Do the compilations, repeatedly until no tainted packages exist.
       
   229             boolean again;
       
   230             // Collect the name of all compiled packages.
       
   231             Set<String> recently_compiled = new HashSet<>();
       
   232             boolean[] rc = new boolean[1];
       
   233             boolean background = Util.extractBooleanOption("background", options.getServerConf(), true);
       
   234             Sjavac sjavac;
       
   235             // Create an sjavac implementation to be used for compilation
       
   236             if (background) {
       
   237                 sjavac = new SjavacClient(options);
       
   238             } else {
       
   239                 int poolsize = Util.extractIntOption("poolsize", options.getServerConf());
       
   240                 if (poolsize <= 0)
       
   241                     poolsize = Runtime.getRuntime().availableProcessors();
       
   242                 sjavac = new PooledSjavac(new SjavacImpl(), poolsize);
       
   243             }
       
   244 
       
   245             do {
       
   246                 if (round > 0)
       
   247                     printRound(round);
       
   248                 // Clean out artifacts in tainted packages.
       
   249                 javac_state.deleteClassArtifactsInTaintedPackages();
       
   250                 again = javac_state.performJavaCompilations(sjavac, options, recently_compiled, rc);
       
   251                 if (!rc[0]) {
       
   252                     Log.debug("Compilation failed.");
       
   253                     break;
       
   254                 }
       
   255                 if (!again) {
       
   256                     Log.debug("Nothing left to do.");
       
   257                 }
       
   258                 round++;
       
   259             } while (again);
       
   260             Log.debug("No need to do another round.");
       
   261 
       
   262             // Only update the state if the compile went well.
       
   263             if (rc[0]) {
       
   264                 javac_state.save();
       
   265                 // Reflatten only the artifacts.
       
   266                 javac_state.now().flattenArtifacts(modules);
       
   267                 // Remove artifacts that were generated during the last compile, but not this one.
       
   268                 javac_state.removeSuperfluousArtifacts(recently_compiled);
       
   269             }
       
   270             if (!background)
       
   271                 sjavac.shutdown();
       
   272 
       
   273             return rc[0] ? 0 : -1;
       
   274         } catch (ProblemException e) {
       
   275             Log.error(e.getMessage());
       
   276             return -1;
       
   277         } catch (Exception e) {
       
   278             e.printStackTrace(err);
       
   279             return -1;
       
   280         }
       
   281     }
    90     }
   282 
       
   283     private static boolean validateOptions(Options options) {
       
   284 
       
   285         String err = null;
       
   286 
       
   287         if (options.getDestDir() == null) {
       
   288             err = "Please specify output directory.";
       
   289         } else if (options.isJavaFilesAmongJavacArgs()) {
       
   290             err = "Sjavac does not handle explicit compilation of single .java files.";
       
   291         } else if (options.getServerConf() == null) {
       
   292             err = "No server configuration provided.";
       
   293         } else if (!options.getImplicitPolicy().equals("none")) {
       
   294             err = "The only allowed setting for sjavac is -implicit:none";
       
   295         } else if (options.getSources().isEmpty()) {
       
   296             err = "You have to specify -src.";
       
   297         } else if (options.getTranslationRules().size() > 1
       
   298                 && options.getGenSrcDir() == null) {
       
   299             err = "You have translators but no gensrc dir (-s) specified!";
       
   300         }
       
   301 
       
   302         if (err != null)
       
   303             Log.error(err);
       
   304 
       
   305         return err == null;
       
   306 
       
   307     }
       
   308 
       
   309     private static boolean createIfMissing(Path dir) {
       
   310 
       
   311         if (Files.isDirectory(dir))
       
   312             return true;
       
   313 
       
   314         if (Files.exists(dir)) {
       
   315             Log.error(dir + " is not a directory.");
       
   316             return false;
       
   317         }
       
   318 
       
   319         try {
       
   320             Files.createDirectories(dir);
       
   321         } catch (IOException e) {
       
   322             Log.error("Could not create directory: " + e.getMessage());
       
   323             return false;
       
   324         }
       
   325 
       
   326         return true;
       
   327     }
       
   328 
       
   329 
       
   330     /** Find source files in the given source locations. */
       
   331     public static void findSourceFiles(List<SourceLocation> sourceLocations,
       
   332                                        Set<String> sourceTypes,
       
   333                                        Map<String,Source> foundFiles,
       
   334                                        Map<String, Module> foundModules,
       
   335                                        Module currentModule,
       
   336                                        boolean permitSourcesInDefaultPackage,
       
   337                                        boolean inLinksrc) {
       
   338 
       
   339         for (SourceLocation source : sourceLocations) {
       
   340             source.findSourceFiles(sourceTypes,
       
   341                                    foundFiles,
       
   342                                    foundModules,
       
   343                                    currentModule,
       
   344                                    permitSourcesInDefaultPackage,
       
   345                                    inLinksrc);
       
   346         }
       
   347     }
       
   348 
       
   349     private static void printRound(int round) {
       
   350         Log.debug("****************************************");
       
   351         Log.debug("* Round " + round + "                              *");
       
   352         Log.debug("****************************************");
       
   353     }
       
   354 
       
   355 }
    91 }