All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.tools.sjavac.comp.SjavacImpl Maven / Gradle / Ivy

There is a newer version: 9-dev-r4023-3
Show newest version
/*
 * Copyright (c) 2014, 2016, 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.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * 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 com.sun.tools.sjavac.comp;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;

import com.sun.tools.javac.file.JavacFileManager;
import com.sun.tools.javac.main.Main;
import com.sun.tools.javac.main.Main.Result;
import com.sun.tools.javac.util.Context;
import com.sun.tools.sjavac.JavacState;
import com.sun.tools.sjavac.Log;
import com.sun.tools.sjavac.Module;
import com.sun.tools.sjavac.ProblemException;
import com.sun.tools.sjavac.Source;
import com.sun.tools.sjavac.Transformer;
import com.sun.tools.sjavac.Util;
import com.sun.tools.sjavac.options.Option;
import com.sun.tools.sjavac.options.Options;
import com.sun.tools.sjavac.options.SourceLocation;
import com.sun.tools.sjavac.server.Sjavac;
import java.io.UncheckedIOException;

import javax.tools.JavaFileManager;

/**
 * The sjavac implementation that interacts with javac and performs the actual
 * compilation.
 *
 *  

This is NOT part of any supported API. * If you write code that depends on this, you do so at your own risk. * This code and its internal interfaces are subject to change or * deletion without notice. */ public class SjavacImpl implements Sjavac { @Override public Result compile(String[] args) { Options options; try { options = Options.parseArgs(args); } catch (IllegalArgumentException e) { Log.error(e.getMessage()); return Result.CMDERR; } if (!validateOptions(options)) return Result.CMDERR; if (srcDstOverlap(options.getSources(), options.getDestDir())) { return Result.CMDERR; } if (!createIfMissing(options.getDestDir())) return Result.ERROR; Path stateDir = options.getStateDir(); if (stateDir != null && !createIfMissing(options.getStateDir())) return Result.ERROR; Path gensrc = options.getGenSrcDir(); if (gensrc != null && !createIfMissing(gensrc)) return Result.ERROR; Path hdrdir = options.getHeaderDir(); if (hdrdir != null && !createIfMissing(hdrdir)) return Result.ERROR; if (stateDir == null) { // Prepare context. Direct logging to our byte array stream. Context context = new Context(); StringWriter strWriter = new StringWriter(); PrintWriter printWriter = new PrintWriter(strWriter); com.sun.tools.javac.util.Log.preRegister(context, printWriter); JavacFileManager.preRegister(context); // Prepare arguments String[] passThroughArgs = Stream.of(args) .filter(arg -> !arg.startsWith(Option.SERVER.arg)) .toArray(String[]::new); // Compile Result result = new Main("javac", printWriter).compile(passThroughArgs, context); // Process compiler output (which is always errors) printWriter.flush(); Util.getLines(strWriter.toString()).forEach(Log::error); // Clean up JavaFileManager fileManager = context.get(JavaFileManager.class); if (fileManager instanceof JavacFileManager) { try { ((JavacFileManager) fileManager).close(); } catch (IOException es) { throw new UncheckedIOException(es); } } return result; } else { // Load the prev build state database. JavacState javac_state = JavacState.load(options); // Setup the suffix rules from the command line. Map suffixRules = new HashMap<>(); // Handling of .java-compilation suffixRules.putAll(javac_state.getJavaSuffixRule()); // Handling of -copy and -tr suffixRules.putAll(options.getTranslationRules()); // All found modules are put here. Map modules = new HashMap<>(); // We start out in the legacy empty no-name module. // As soon as we stumble on a module-info.java file we change to that module. Module current_module = new Module("", ""); modules.put("", current_module); try { // Find all sources, use the suffix rules to know which files are sources. Map sources = new HashMap<>(); // Find the files, this will automatically populate the found modules // with found packages where the sources are found! findSourceFiles(options.getSources(), suffixRules.keySet(), sources, modules, current_module, options.isDefaultPackagePermitted(), false); if (sources.isEmpty()) { Log.error("Found nothing to compile!"); return Result.ERROR; } // Create a map of all source files that are available for linking. Both -src and // -sourcepath point to such files. It is possible to specify multiple // -sourcepath options to enable different filtering rules. If the // filters are the same for multiple sourcepaths, they may be concatenated // using :(;). Before sending the list of sourcepaths to javac, they are // all concatenated. The list created here is used by the SmartFileWrapper to // make sure only the correct sources are actually available. // We might find more modules here as well. Map sources_to_link_to = new HashMap<>(); List sourceResolutionLocations = new ArrayList<>(); sourceResolutionLocations.addAll(options.getSources()); sourceResolutionLocations.addAll(options.getSourceSearchPaths()); findSourceFiles(sourceResolutionLocations, Collections.singleton(".java"), sources_to_link_to, modules, current_module, options.isDefaultPackagePermitted(), true); // Add the set of sources to the build database. javac_state.now().flattenPackagesSourcesAndArtifacts(modules); javac_state.now().checkInternalState("checking sources", false, sources); javac_state.now().checkInternalState("checking linked sources", true, sources_to_link_to); javac_state.setVisibleSources(sources_to_link_to); int round = 0; printRound(round); // If there is any change in the source files, taint packages // and mark the database in need of saving. javac_state.checkSourceStatus(false); // Find all existing artifacts. Their timestamp will match the last modified timestamps stored // in javac_state, simply because loading of the JavacState will clean out all artifacts // that do not match the javac_state database. javac_state.findAllArtifacts(); // Remove unidentified artifacts from the bin, gensrc and header dirs. // (Unless we allow them to be there.) // I.e. artifacts that are not known according to the build database (javac_state). // For examples, files that have been manually copied into these dirs. // Artifacts with bad timestamps (ie the on disk timestamp does not match the timestamp // in javac_state) have already been removed when the javac_state was loaded. if (!options.areUnidentifiedArtifactsPermitted()) { javac_state.removeUnidentifiedArtifacts(); } // Go through all sources and taint all packages that miss artifacts. javac_state.taintPackagesThatMissArtifacts(); // Check recorded classpath public apis. Taint packages that depend on // classpath classes whose public apis have changed. javac_state.taintPackagesDependingOnChangedClasspathPackages(); // Now clean out all known artifacts belonging to tainted packages. javac_state.deleteClassArtifactsInTaintedPackages(); // Copy files, for example property files, images files, xml files etc etc. javac_state.performCopying(Util.pathToFile(options.getDestDir()), suffixRules); // Translate files, for example compile properties or compile idls. javac_state.performTranslation(Util.pathToFile(gensrc), suffixRules); // Add any potentially generated java sources to the tobe compiled list. // (Generated sources must always have a package.) Map generated_sources = new HashMap<>(); Source.scanRoot(Util.pathToFile(options.getGenSrcDir()), Util.set(".java"), Collections.emptyList(), Collections.emptyList(), generated_sources, modules, current_module, false, true, false); javac_state.now().flattenPackagesSourcesAndArtifacts(modules); // Recheck the the source files and their timestamps again. javac_state.checkSourceStatus(true); // Now do a safety check that the list of source files is identical // to the list Make believes we are compiling. If we do not get this // right, then incremental builds will fail with subtility. // If any difference is detected, then we will fail hard here. // This is an important safety net. javac_state.compareWithMakefileList(Util.pathToFile(options.getSourceReferenceList())); // Do the compilations, repeatedly until no tainted packages exist. boolean again; // Collect the name of all compiled packages. Set recently_compiled = new HashSet<>(); boolean[] rc = new boolean[1]; CompilationService compilationService = new CompilationService(); do { if (round > 0) printRound(round); // Clean out artifacts in tainted packages. javac_state.deleteClassArtifactsInTaintedPackages(); again = javac_state.performJavaCompilations(compilationService, options, recently_compiled, rc); if (!rc[0]) { Log.debug("Compilation failed."); break; } if (!again) { Log.debug("Nothing left to do."); } round++; } while (again); Log.debug("No need to do another round."); // Only update the state if the compile went well. if (rc[0]) { javac_state.save(); // Reflatten only the artifacts. javac_state.now().flattenArtifacts(modules); // Remove artifacts that were generated during the last compile, but not this one. javac_state.removeSuperfluousArtifacts(recently_compiled); } return rc[0] ? Result.OK : Result.ERROR; } catch (ProblemException e) { // For instance make file list mismatch. Log.error(e.getMessage()); Log.debug(e); return Result.ERROR; } catch (Exception e) { Log.error(e); return Result.ERROR; } } } @Override public void shutdown() { // Nothing to clean up } private static boolean validateOptions(Options options) { String err = null; if (options.getDestDir() == null) { err = "Please specify output directory."; } else if (options.isJavaFilesAmongJavacArgs()) { err = "Sjavac does not handle explicit compilation of single .java files."; } else if (!options.getImplicitPolicy().equals("none")) { err = "The only allowed setting for sjavac is -implicit:none"; } else if (options.getSources().isEmpty() && options.getStateDir() != null) { err = "You have to specify -src when using --state-dir."; } else if (options.getTranslationRules().size() > 1 && options.getGenSrcDir() == null) { err = "You have translators but no gensrc dir (-s) specified!"; } if (err != null) Log.error(err); return err == null; } private static boolean srcDstOverlap(List locs, Path dest) { for (SourceLocation loc : locs) { if (isOverlapping(loc.getPath(), dest)) { Log.error("Source location " + loc.getPath() + " overlaps with destination " + dest); return true; } } return false; } private static boolean isOverlapping(Path p1, Path p2) { p1 = p1.toAbsolutePath().normalize(); p2 = p2.toAbsolutePath().normalize(); return p1.startsWith(p2) || p2.startsWith(p1); } private static boolean createIfMissing(Path dir) { if (Files.isDirectory(dir)) return true; if (Files.exists(dir)) { Log.error(dir + " is not a directory."); return false; } try { Files.createDirectories(dir); } catch (IOException e) { Log.error("Could not create directory: " + e.getMessage()); return false; } return true; } /** Find source files in the given source locations. */ public static void findSourceFiles(List sourceLocations, Set sourceTypes, Map foundFiles, Map foundModules, Module currentModule, boolean permitSourcesInDefaultPackage, boolean inLinksrc) throws IOException { for (SourceLocation source : sourceLocations) { source.findSourceFiles(sourceTypes, foundFiles, foundModules, currentModule, permitSourcesInDefaultPackage, inLinksrc); } } private static void printRound(int round) { Log.debug("****************************************"); Log.debug("* Round " + round + " *"); Log.debug("****************************************"); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy