boolean (Iterable<? extends String> options, Iterable<? extends File> sources, Iterable<? extends File> classpath, Iterable<? extends File> platformClasspath, ModulePath modulePath, Iterable<? extends File> upgradeModulePath, Iterable<? extends File> sourcePath, final Map<File, Set<File>> outputDirToRoots, final DiagnosticOutputConsumer diagnosticConsumer, final OutputFileConsumer outputSink, CanceledStatus canceledStatus, @NotNull JavaCompilingTool compilingTool) { JavaCompiler compiler; try { compiler = compilingTool.createCompiler(); } catch (CannotCreateJavaCompilerException e) { diagnosticConsumer.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, e.getMessage())); return false; } for (File outputDir : outputDirToRoots.keySet()) { outputDir.mkdirs(); } final boolean usingJavac = compilingTool instanceof JavacCompilerTool; final boolean javacBefore9 = usingJavac && JAVA_RUNTIME_PRE_9; // since java 9 internal API's used by the optimizedFileManager have changed final JpsJavacFileManager fileManager = new JpsJavacFileManager( new ContextImpl(compiler, diagnosticConsumer, outputSink, modulePath, canceledStatus), javacBefore9, JavaSourceTransformer.getTransformers() ); if (javacBefore9 && !Iterators.isEmpty(platformClasspath)) { // for javac6 this will prevent lazy initialization of Paths.bootClassPathRtJar // and thus usage of symbol file for resolution, when this file is not expected to be used fileManager.handleOption("-bootclasspath", Collections.singleton("").iterator()); fileManager.handleOption("-extdirs", Collections.singleton("").iterator()); // this will clear cached stuff fileManager.handleOption("-endorseddirs", Collections.singleton("").iterator()); // this will clear cached stuff } final Iterable<String> _options = prepareOptions(options, compilingTool); try { // to be on the safe side, we'll have to apply all options _before_ calling any of manager's methods // i.e. getJavaFileObjectsFromFiles() // This way the manager will be properly initialized. Namely, the encoding will be set correctly // Note that due to lazy initialization in various components inside javac, handleOption() should be called before setLocation() and others // update: for some options their repetitive initialization would be considered as error: e.g. '--patch-module', // therefore we do the trick only for those options that may influence FileManager's state initialization before passing it to getTask() method for (Iterator<String> iterator = _options.iterator(); iterator.hasNext(); ) { final String option = iterator.next(); if (FILE_MANAGER_EARLY_INIT_OPTIONS.contains(option)) { fileManager.handleOption(option, iterator); } } try { fileManager.setOutputDirectories(outputDirToRoots); } catch (IOException e) { fileManager.getContext().reportMessage(Diagnostic.Kind.ERROR, e.getMessage()); return false; } if (!Iterators.isEmpty(platformClasspath)) { try { fileManager.handleOption("-bootclasspath", Collections.singleton("").iterator()); // this will clear cached stuff fileManager.setLocation(StandardLocation.PLATFORM_CLASS_PATH, buildPlatformClasspath(platformClasspath, _options)); } catch (IOException e) { fileManager.getContext().reportMessage(Diagnostic.Kind.ERROR, e.getMessage()); return false; } } if (!Iterators.isEmpty(upgradeModulePath)) { try { setLocation(fileManager, "UPGRADE_MODULE_PATH", upgradeModulePath); } catch (IOException e) { fileManager.getContext().reportMessage(Diagnostic.Kind.ERROR, e.getMessage()); return false; } } final boolean isAnnotationProcessingEnabled = isAnnotationProcessingEnabled(_options); if (!modulePath.isEmpty()) { try { setLocation(fileManager, "MODULE_PATH", modulePath.getPath()); if (isAnnotationProcessingEnabled && getLocation(fileManager, "ANNOTATION_PROCESSOR_MODULE_PATH") == null && fileManager.getLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH) == null) { // default annotation processing discovery path to module path if not explicitly set setLocation(fileManager, "ANNOTATION_PROCESSOR_MODULE_PATH", Iterators.filter(modulePath.getPath(), new BooleanFunction<File>() { @Override public boolean fun(File file) { return !outputDirToRoots.containsKey(file); } })); } } catch (IOException e) { fileManager.getContext().reportMessage(Diagnostic.Kind.ERROR, e.getMessage()); return false; } } if (!Iterators.isEmpty(classpath)) { // because module path has priority if present, initialize classpath after the module path try { fileManager.setLocation(StandardLocation.CLASS_PATH, classpath); if (!usingJavac && isAnnotationProcessingEnabled && !Iterators.contains(_options, "-processorpath") && !Iterators.contains(_options, "--processor-module-path") && getLocation(fileManager, "ANNOTATION_PROCESSOR_MODULE_PATH") == null) { // for non-javac file manager ensure annotation processor path defaults to classpath fileManager.setLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH, classpath); } } catch (IOException e) { fileManager.getContext().reportMessage(Diagnostic.Kind.ERROR, e.getMessage()); return false; } } if (javacBefore9 || !Iterators.isEmpty(sourcePath) || modulePath.isEmpty()) { try { // ensure the source path is set; // otherwise, if not set, javac attempts to search both classes and sources in classpath; // so if some classpath jars contain sources, it will attempt to compile them // starting from javac9 it seems that setting empty source path may affect module compilation logic, so starting from javac9 // we avoid forcing empty sourcepath fileManager.setLocation(StandardLocation.SOURCE_PATH, sourcePath); } catch (IOException e) { fileManager.getContext().reportMessage(Diagnostic.Kind.ERROR, e.getMessage()); return false; } } final APIWrappers.ProcessingContext procContext; final DiagnosticOutputConsumer diagnosticListener; if (TRACK_AP_GENERATED_DEPENDENCIES && isAnnotationProcessingEnabled) { procContext = new APIWrappers.ProcessingContext(fileManager); // use real processor class names and not names of processor wrappers diagnosticListener = APIWrappers.newDiagnosticListenerWrapper(procContext, diagnosticConsumer); } else { procContext = null; diagnosticListener = diagnosticConsumer; } final LineOutputWriter out = new LineOutputWriter() { @Override protected void lineAvailable(String line) { if (usingJavac) { diagnosticListener.outputLineAvailable(line); } else { // todo: filter too verbose eclipse output? } } }; // methods added to newer versions of StandardJavaFileManager interfaces have default implementations that // do not delegate to corresponding methods of FileManager's base implementation // this proxy object makes sure the calls, not implemented in our file manager, are dispatched further to the base file manager implementation final StandardJavaFileManager fm = APIWrappers.wrap(StandardJavaFileManager.class, fileManager, fileManager.getClass().getSuperclass(), fileManager.getStdManager()); final JavaCompiler.CompilationTask task = tryInstallClientCodeWrapperCallDispatcher(compiler.getTask( out, fm, diagnosticListener, _options, null, fileManager.setInputSources(sources) ), fm); for (JavaCompilerToolExtension extension : JavaCompilerToolExtension.getExtensions()) { try { extension.beforeCompileTaskExecution(compilingTool, task, _options, diagnosticConsumer); } catch (Throwable e) { fileManager.getContext().reportMessage(Diagnostic.Kind.MANDATORY_WARNING, extension.getClass() + " : " + e.getMessage()); e.printStackTrace(System.err); } } if (TRACK_AP_GENERATED_DEPENDENCIES && isAnnotationProcessingEnabled) { final Iterable<Processor> processors = lookupAnnotationProcessors(procContext, getAnnotationProcessorNames(_options)); if (processors != null) { task.setProcessors(processors); } } return task.call(); } catch(IllegalArgumentException | IllegalStateException e) { diagnosticConsumer.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, e.getMessage())); } catch (CompilationCanceledException e) { diagnosticConsumer.report(new JpsInfoDiagnostic(e.getMessage())); } catch (RuntimeException e) { final Throwable cause = e.getCause(); if (cause != null) { if (cause instanceof CompilationCanceledException) { diagnosticConsumer.report(new JpsInfoDiagnostic(cause.getMessage())); } else { diagnosticConsumer.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, buildCompilerErrorMessage(e))); throw e; } } else { throw e; } } finally { fileManager.close(); if (usingJavac) { cleanupJavacNameTable(); } } return false; }