public static boolean compile(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;
  }
public static boolean compile(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)