private Collection<File> getClasspathFiles(
      ModuleChunk chunk,
      JpsJavaClasspathKind kind,
      final boolean excludeMainModuleOutput,
      ClasspathPart classpathPart,
      final boolean exportedOnly) {
    final Set<File> files = new LinkedHashSet<File>();
    for (JpsModule module : chunk.getModules()) {
      JpsJavaDependenciesEnumerator enumerator =
          JpsJavaExtensionService.dependencies(module).includedIn(kind).recursively();
      if (exportedOnly) {
        enumerator = enumerator.exportedOnly();
      }
      if (classpathPart == ClasspathPart.BEFORE_JDK) {
        enumerator = enumerator.satisfying(new BeforeJavaSdkItemFilter(module));
      } else if (classpathPart == ClasspathPart.AFTER_JDK) {
        enumerator = enumerator.satisfying(new AfterJavaSdkItemFilter(module));
      }
      JpsJavaDependenciesRootsEnumerator rootsEnumerator = enumerator.classes();
      if (excludeMainModuleOutput) {
        rootsEnumerator = rootsEnumerator.withoutSelfModuleOutput();
      }
      files.addAll(rootsEnumerator.getRoots());
    }

    if (classpathPart == ClasspathPart.BEFORE_JDK) {
      for (JpsModule module : chunk.getModules()) {
        JpsSdk<JpsDummyElement> sdk = module.getSdk(JpsJavaSdkType.INSTANCE);
        if (sdk != null) {
          files.addAll(sdk.getParent().getFiles(JpsOrderRootType.COMPILED));
        }
      }
    }
    return files;
  }
 private static int getCompilerSdkVersion(CompileContext context) {
   final Integer cached = JAVA_COMPILER_VERSION_KEY.get(context);
   if (cached != null) {
     return cached;
   }
   int javaVersion = convertToNumber(SystemProperties.getJavaVersion());
   if (!USE_EMBEDDED_JAVAC) {
     // in case of external javac, run compiler from the newest jdk that is used in the project
     for (JpsSdk<?> sdk : context.getProjectDescriptor().getProjectJavaSdks()) {
       final String version = sdk.getVersionString();
       final int ver = convertToNumber(version);
       if (ver > javaVersion) {
         javaVersion = ver;
       }
     }
   }
   JAVA_COMPILER_VERSION_KEY.set(context, javaVersion);
   return javaVersion;
 }
  protected <T extends JpsElement> JpsModule addModule(
      String moduleName,
      String[] srcPaths,
      @Nullable String outputPath,
      @Nullable String testOutputPath,
      JpsSdk<T> sdk) {
    JpsModule module = myProject.addModule(moduleName, JpsJavaModuleType.INSTANCE);
    final JpsSdkType<T> sdkType = sdk.getSdkType();
    final JpsSdkReferencesTable sdkTable = module.getSdkReferencesTable();
    sdkTable.setSdkReference(sdkType, sdk.createReference());

    if (sdkType instanceof JpsJavaSdkTypeWrapper) {
      final JpsSdkReference<T> wrapperRef = sdk.createReference();
      sdkTable.setSdkReference(
          JpsJavaSdkType.INSTANCE,
          JpsJavaExtensionService.getInstance()
              .createWrappedJavaSdkReference((JpsJavaSdkTypeWrapper) sdkType, wrapperRef));
    }
    module.getDependenciesList().addSdkDependency(sdkType);
    if (srcPaths.length > 0 || outputPath != null) {
      for (String srcPath : srcPaths) {
        module.getContentRootsList().addUrl(JpsPathUtil.pathToUrl(srcPath));
        module.addSourceRoot(JpsPathUtil.pathToUrl(srcPath), JavaSourceRootType.SOURCE);
      }
      JpsJavaModuleExtension extension =
          JpsJavaExtensionService.getInstance().getOrCreateModuleExtension(module);
      if (outputPath != null) {
        extension.setOutputUrl(JpsPathUtil.pathToUrl(outputPath));
        if (!StringUtil.isEmpty(testOutputPath)) {
          extension.setTestOutputUrl(JpsPathUtil.pathToUrl(testOutputPath));
        } else {
          extension.setTestOutputUrl(extension.getOutputUrl());
        }
      } else {
        extension.setInheritOutput(true);
      }
    }
    return module;
  }
  private static synchronized JavacServerClient ensureJavacServerLaunched(CompileContext context)
      throws Exception {
    final ExternalJavacDescriptor descriptor = ExternalJavacDescriptor.KEY.get(context);
    if (descriptor != null) {
      return descriptor.client;
    }
    // start server here
    final int port = findFreePort();
    final int heapSize = getJavacServerHeapSize(context);

    // defaulting to the same jdk that used to run the build process
    String javaHome = SystemProperties.getJavaHome();
    int javaVersion = convertToNumber(SystemProperties.getJavaVersion());

    for (JpsSdk<?> sdk : context.getProjectDescriptor().getProjectJavaSdks()) {
      final String version = sdk.getVersionString();
      final int ver = convertToNumber(version);
      if (ver > javaVersion) {
        javaVersion = ver;
        javaHome = sdk.getHomePath();
      }
    }

    final BaseOSProcessHandler processHandler =
        JavacServerBootstrap.launchJavacServer(
            javaHome, heapSize, port, Utils.getSystemRoot(), getCompilationVMOptions(context));
    final JavacServerClient client = new JavacServerClient();
    try {
      client.connect("127.0.0.1", port);
    } catch (Throwable ex) {
      processHandler.destroyProcess();
      throw new Exception("Failed to connect to external javac process: ", ex);
    }
    ExternalJavacDescriptor.KEY.set(context, new ExternalJavacDescriptor(processHandler, client));
    return client;
  }
  private void addOtherOptions(final Element rootElement) {
    final Map<String, String> options =
        new THashMap<String, String>(myProjectLevelCompilerOptions.getAllOptions());
    options.putAll(myModuleLevelCompilerOptions.getAllOptions());
    options.putAll(myBC.getCompilerOptions().getAllOptions());

    final String addOptions =
        myProjectLevelCompilerOptions.getAdditionalOptions()
            + " "
            + myModuleLevelCompilerOptions.getAdditionalOptions()
            + " "
            + myBC.getCompilerOptions().getAdditionalOptions();
    final List<String> contextRootInAddOptions =
        FlexCommonUtils.getOptionValues(addOptions, "context-root", "compiler.context-root");

    if (options.get("compiler.context-root") == null && contextRootInAddOptions.isEmpty()) {
      final List<String> servicesInAddOptions =
          FlexCommonUtils.getOptionValues(addOptions, "services", "compiler.services");
      if (options.get("compiler.services") != null || !servicesInAddOptions.isEmpty()) {
        options.put("compiler.context-root", "");
      }
    }

    for (final Map.Entry<String, String> entry : options.entrySet()) {
      addOption(rootElement, CompilerOptionInfo.getOptionInfo(entry.getKey()), entry.getValue());
    }

    final String namespacesRaw = options.get("compiler.namespaces.namespace");
    if (namespacesRaw != null && myBC.getOutputType() == OutputType.Library) {
      final String namespaces =
          FlexCommonUtils.replacePathMacros(
              namespacesRaw, myModule, myFlexmojos ? "" : mySdk.getHomePath());
      final StringBuilder buf = new StringBuilder();
      for (final String listEntry :
          StringUtil.split(namespaces, CompilerOptionInfo.LIST_ENTRIES_SEPARATOR)) {
        final int tabIndex = listEntry.indexOf(CompilerOptionInfo.LIST_ENTRY_PARTS_SEPARATOR);
        assert tabIndex != -1 : namespaces;
        final String namespace = listEntry.substring(0, tabIndex);
        if (buf.length() > 0) buf.append(CompilerOptionInfo.LIST_ENTRIES_SEPARATOR);
        buf.append(namespace);
      }

      if (buf.length() > 0) {
        addOption(rootElement, CompilerOptionInfo.INCLUDE_NAMESPACES_INFO, buf.toString());
      }
    }
  }
  private Pair<String, ValueSource> getValueAndSource(final CompilerOptionInfo info) {
    assert !info.isGroup() : info.DISPLAY_NAME;

    final String bcLevelValue = myBC.getCompilerOptions().getOption(info.ID);
    if (bcLevelValue != null) return Pair.create(bcLevelValue, ValueSource.BC);

    final String moduleLevelValue = myModuleLevelCompilerOptions.getOption(info.ID);
    if (moduleLevelValue != null) return Pair.create(moduleLevelValue, ValueSource.ModuleDefault);

    final String projectLevelValue = myProjectLevelCompilerOptions.getOption(info.ID);
    if (projectLevelValue != null)
      return Pair.create(projectLevelValue, ValueSource.ProjectDefault);

    return Pair.create(
        info.getDefaultValue(
            mySdk.getVersionString(), myBC.getNature(), myBC.getDependencies().getComponentSet()),
        ValueSource.GlobalDefault);
  }
 private CompilerConfigGeneratorRt(
     final @NotNull JpsFlexBuildConfiguration bc,
     final @NotNull JpsFlexModuleOrProjectCompilerOptions moduleLevelCompilerOptions,
     final @NotNull JpsFlexModuleOrProjectCompilerOptions projectLevelCompilerOptions,
     final @NotNull ProjectDescriptor projectDescriptor)
     throws IOException {
   myProjectDescriptor = projectDescriptor;
   myModule = bc.getModule();
   myBC = bc;
   myFlexUnit = FlexCommonUtils.isFlexUnitBC(myBC);
   myCSS = FlexCommonUtils.isRuntimeStyleSheetBC(bc);
   mySdk = bc.getSdk();
   if (mySdk == null) {
     throw new IOException(
         FlexCommonBundle.message(
             "sdk.not.set.for.bc.0.of.module.1", bc.getName(), bc.getModule().getName()));
   }
   myFlexmojos = mySdk.getSdkType() == JpsFlexmojosSdkType.INSTANCE;
   myModuleLevelCompilerOptions = moduleLevelCompilerOptions;
   myProjectLevelCompilerOptions = projectLevelCompilerOptions;
 }
  private void addOption(
      final Element rootElement, final CompilerOptionInfo info, final String rawValue) {
    if (!info.isApplicable(mySdk.getVersionString(), myBC.getNature())) {
      return;
    }

    final String value =
        FlexCommonUtils.replacePathMacros(
            rawValue, myModule, myFlexmojos ? "" : mySdk.getHomePath());

    final String pathInFlexConfig =
        info.ID.startsWith("compiler.debug") ? "compiler.debug" : info.ID;
    final List<String> elementNames = StringUtil.split(pathInFlexConfig, ".");
    Element parentElement = rootElement;

    for (int i1 = 0; i1 < elementNames.size() - 1; i1++) {
      parentElement = getOrCreateElement(parentElement, elementNames.get(i1));
    }

    final String elementName = elementNames.get(elementNames.size() - 1);

    switch (info.TYPE) {
      case Boolean:
      case String:
      case Int:
      case File:
        final Element simpleElement = new Element(elementName, parentElement.getNamespace());
        simpleElement.setText(value);
        parentElement.addContent(simpleElement);
        break;
      case List:
        if (info.LIST_ELEMENTS.length == 1) {
          final Element listHolderElement = getOrCreateElement(parentElement, elementName);
          for (final String listElementValue :
              StringUtil.split(value, CompilerOptionInfo.LIST_ENTRIES_SEPARATOR)) {
            final Element child =
                new Element(info.LIST_ELEMENTS[0].NAME, listHolderElement.getNamespace());
            child.setText(listElementValue);
            listHolderElement.addContent(child);
          }
        } else {
          for (final String listEntry :
              StringUtil.split(value, String.valueOf(CompilerOptionInfo.LIST_ENTRIES_SEPARATOR))) {
            final Element repeatableListHolderElement =
                new Element(elementName, parentElement.getNamespace());

            final List<String> values =
                StringUtil.split(
                    listEntry, CompilerOptionInfo.LIST_ENTRY_PARTS_SEPARATOR, true, false);
            assert info.LIST_ELEMENTS.length == values.size() : info.ID + "=" + value;

            for (int i = 0; i < info.LIST_ELEMENTS.length; i++) {
              final Element child =
                  new Element(
                      info.LIST_ELEMENTS[i].NAME, repeatableListHolderElement.getNamespace());
              child.setText(values.get(i));
              repeatableListHolderElement.addContent(child);
            }

            parentElement.addContent(repeatableListHolderElement);
          }
        }
        break;
      default:
        assert false : info.DISPLAY_NAME;
    }
  }
  private void addRootsFromSdk(final Element rootElement) {
    final CompilerOptionInfo localeInfo = CompilerOptionInfo.getOptionInfo("compiler.locale");
    if (!getValueAndSource(localeInfo).first.isEmpty()) {
      addOption(
          rootElement,
          CompilerOptionInfo.LIBRARY_PATH_INFO,
          mySdk.getHomePath() + "/frameworks/locale/{locale}");
    }

    final Map<String, String> libNameToRslInfo = new THashMap<String, String>();

    for (final String swcUrl : mySdk.getParent().getRootUrls(JpsOrderRootType.COMPILED)) {
      final String swcPath = JpsPathUtil.urlToPath(swcUrl);
      if (!swcPath.toLowerCase().endsWith(".swc")) {
        Logger.getInstance(CompilerConfigGeneratorRt.class.getName())
            .warn("Unexpected URL in Flex SDK classes: " + swcUrl);
        continue;
      }

      LinkageType linkageType = FlexCommonUtils.getSdkEntryLinkageType(swcPath, myBC);

      // check applicability
      if (linkageType == null) continue;
      // resolve default
      if (linkageType == LinkageType.Default)
        linkageType = myBC.getDependencies().getFrameworkLinkage();
      if (linkageType == LinkageType.Default) {
        linkageType =
            FlexCommonUtils.getDefaultFrameworkLinkage(mySdk.getVersionString(), myBC.getNature());
      }
      if (myCSS && linkageType == LinkageType.Include) linkageType = LinkageType.Merged;

      final CompilerOptionInfo info =
          linkageType == LinkageType.Merged
              ? CompilerOptionInfo.LIBRARY_PATH_INFO
              : linkageType == LinkageType.RSL
                  ? CompilerOptionInfo.LIBRARY_PATH_INFO
                  : linkageType == LinkageType.External
                      ? CompilerOptionInfo.EXTERNAL_LIBRARY_INFO
                      : linkageType == LinkageType.Include
                          ? CompilerOptionInfo.INCLUDE_LIBRARY_INFO
                          : null;

      assert info != null : swcPath + ": " + linkageType.getShortText();

      addOption(rootElement, info, swcPath);

      if (linkageType == LinkageType.RSL) {
        final List<String> rslUrls = RslUtil.getRslUrls(mySdk.getHomePath(), swcPath);
        if (rslUrls.isEmpty()) continue;

        final StringBuilder rslBuilder = new StringBuilder();
        final String firstUrl = rslUrls.get(0);
        rslBuilder
            .append(swcPath)
            .append(CompilerOptionInfo.LIST_ENTRY_PARTS_SEPARATOR)
            .append(firstUrl)
            .append(CompilerOptionInfo.LIST_ENTRY_PARTS_SEPARATOR);
        if (firstUrl.startsWith("http://")) {
          rslBuilder.append("http://fpdownload.adobe.com/pub/swz/crossdomain.xml");
        }

        if (rslUrls.size() > 1) {
          final String secondUrl = rslUrls.get(1);
          rslBuilder
              .append(CompilerOptionInfo.LIST_ENTRY_PARTS_SEPARATOR)
              .append(secondUrl)
              .append(CompilerOptionInfo.LIST_ENTRY_PARTS_SEPARATOR);
          if (secondUrl.startsWith("http://")) {
            rslBuilder.append("http://fpdownload.adobe.com/pub/swz/crossdomain.xml");
          }
        }

        final String swcName = PathUtilRt.getFileName(swcPath);
        final String libName = swcName.substring(0, swcName.length() - ".swc".length());
        libNameToRslInfo.put(libName, rslBuilder.toString());
      }
    }

    if (myBC.getNature().isLib()) {
      final String theme =
          getValueAndSource(CompilerOptionInfo.getOptionInfo("compiler.theme")).first;
      if (theme != null && theme.toLowerCase().endsWith(".swc")) {
        addOption(rootElement, CompilerOptionInfo.LIBRARY_PATH_INFO, theme);
      }
    }

    addRslInfo(rootElement, libNameToRslInfo);
  }
  private void addMandatoryOptions(final Element rootElement) {
    if (!FlexCommonUtils.isRLMTemporaryBC(myBC)
        && !FlexCommonUtils.isRuntimeStyleSheetBC(myBC)
        && FlexCommonUtils.canHaveRLMsAndRuntimeStylesheets(myBC)
        && myBC.getRLMs().size() > 0) {
      addOption(rootElement, CompilerOptionInfo.LINK_REPORT_INFO, getLinkReportFilePath(myBC));
    }

    if (FlexCommonUtils.isRLMTemporaryBC(myBC) && !myBC.getOptimizeFor().isEmpty()) {
      final String customLinkReportPath = getCustomLinkReportPath(myBC);
      final String linkReportPath =
          StringUtil.notNullize(customLinkReportPath, getLinkReportFilePath(myBC));
      addOption(rootElement, CompilerOptionInfo.LOAD_EXTERNS_INFO, linkReportPath);
    }

    addOption(rootElement, CompilerOptionInfo.WARN_NO_CONSTRUCTOR_INFO, "false");
    if (myFlexmojos) return;

    final BuildConfigurationNature nature = myBC.getNature();
    final String targetPlayer =
        nature.isWebPlatform()
            ? myBC.getDependencies().getTargetPlayer()
            : FlexCommonUtils.getMaximumTargetPlayer(mySdk.getHomePath());
    addOption(rootElement, CompilerOptionInfo.TARGET_PLAYER_INFO, targetPlayer);

    if (FlexCommonUtils.isAirSdkWithoutFlex(mySdk)
        || StringUtil.compareVersionNumbers(mySdk.getVersionString(), "4.5") >= 0) {
      final String swfVersion;
      if (nature.isWebPlatform()) {
        swfVersion = FlexCommonUtils.getSwfVersionForTargetPlayer(targetPlayer);
      } else {
        String airVersion = getAirVersionIfCustomDescriptor(myBC);
        if (airVersion == null) {
          airVersion = FlexCommonUtils.getAirVersion(mySdk.getHomePath(), mySdk.getVersionString());
        }
        swfVersion =
            airVersion != null
                ? FlexCommonUtils.getSwfVersionForAirVersion(airVersion)
                : FlexCommonUtils.getSwfVersionForSdk_THE_WORST_WAY(mySdk.getVersionString());
      }

      addOption(rootElement, CompilerOptionInfo.SWF_VERSION_INFO, swfVersion);
    }

    if (nature.isMobilePlatform()) {
      addOption(rootElement, CompilerOptionInfo.MOBILE_INFO, "true");
      addOption(rootElement, CompilerOptionInfo.PRELOADER_INFO, "spark.preloaders.SplashScreen");
    }

    if (!FlexCommonUtils.isAirSdkWithoutFlex(mySdk)) {
      final String accessible =
          nature.isMobilePlatform()
              ? "false"
              : StringUtil.compareVersionNumbers(mySdk.getVersionString(), "4") >= 0
                  ? "true"
                  : "false";
      addOption(rootElement, CompilerOptionInfo.ACCESSIBLE_INFO, accessible);

      final String fontManagers =
          StringUtil.compareVersionNumbers(mySdk.getVersionString(), "4") >= 0
              ? "flash.fonts.JREFontManager"
                  + CompilerOptionInfo.LIST_ENTRIES_SEPARATOR
                  + "flash.fonts.BatikFontManager"
                  + CompilerOptionInfo.LIST_ENTRIES_SEPARATOR
                  + "flash.fonts.AFEFontManager"
                  + CompilerOptionInfo.LIST_ENTRIES_SEPARATOR
                  + "flash.fonts.CFFFontManager"
              : "flash.fonts.JREFontManager"
                  + CompilerOptionInfo.LIST_ENTRIES_SEPARATOR
                  + "flash.fonts.AFEFontManager"
                  + CompilerOptionInfo.LIST_ENTRIES_SEPARATOR
                  + "flash.fonts.BatikFontManager";
      addOption(rootElement, CompilerOptionInfo.FONT_MANAGERS_INFO, fontManagers);

      addOption(rootElement, CompilerOptionInfo.STATIC_RSLS_INFO, "false");
    }
  }
  @NotNull
  private GroovycOutputParser runGroovycOrContinuation(
      CompileContext context,
      ModuleChunk chunk,
      JpsGroovySettings settings,
      Map<ModuleBuildTarget, String> finalOutputs,
      String compilerOutput,
      List<File> toCompile,
      boolean hasStubExcludes)
      throws Exception {
    GroovycContinuation continuation = takeContinuation(context, chunk);
    if (continuation != null) {
      if (Utils.IS_TEST_MODE || LOG.isDebugEnabled()) {
        LOG.info("using continuation for " + chunk);
      }
      return continuation.continueCompilation();
    }

    final Set<String> toCompilePaths = getPathsToCompile(toCompile);

    JpsSdk<JpsDummyElement> jdk = getJdk(chunk);
    String version = jdk == null ? SystemInfo.JAVA_RUNTIME_VERSION : jdk.getVersionString();
    boolean inProcess = "true".equals(System.getProperty("groovyc.in.process", "true"));
    boolean mayDependOnUtilJar =
        version != null && StringUtil.compareVersionNumbers(version, "1.6") >= 0;
    boolean optimizeClassLoading =
        !inProcess
            && mayDependOnUtilJar
            && ourOptimizeThreshold != 0
            && toCompilePaths.size() >= ourOptimizeThreshold;

    Map<String, String> class2Src =
        buildClassToSourceMap(chunk, context, toCompilePaths, finalOutputs);

    final String encoding =
        context
            .getProjectDescriptor()
            .getEncodingConfiguration()
            .getPreferredModuleChunkEncoding(chunk);
    List<String> patchers = new ArrayList<String>();

    for (GroovyBuilderExtension extension :
        JpsServiceManager.getInstance().getExtensions(GroovyBuilderExtension.class)) {
      patchers.addAll(extension.getCompilationUnitPatchers(context, chunk));
    }

    Collection<String> classpath = generateClasspath(context, chunk);
    if (LOG.isDebugEnabled()) {
      LOG.debug("Optimized class loading: " + optimizeClassLoading);
      LOG.debug("Groovyc classpath: " + classpath);
    }

    final File tempFile =
        GroovycOutputParser.fillFileWithGroovycParameters(
            compilerOutput,
            toCompilePaths,
            finalOutputs.values(),
            class2Src,
            encoding,
            patchers,
            optimizeClassLoading ? StringUtil.join(classpath, File.pathSeparator) : "");
    GroovycFlavor groovyc =
        inProcess
            ? new InProcessGroovyc(finalOutputs.values(), hasStubExcludes)
            : new ForkedGroovyc(optimizeClassLoading, chunk);

    GroovycOutputParser parser = new GroovycOutputParser(chunk, context);

    continuation = groovyc.runGroovyc(classpath, myForStubs, settings, tempFile, parser);
    setContinuation(context, chunk, continuation);
    return parser;
  }
  @Override
  public void build(
      @NotNull ErlangTarget target,
      @NotNull DirtyFilesHolder<ErlangSourceRootDescriptor, ErlangTarget> holder,
      @NotNull BuildOutputConsumer outputConsumer,
      @NotNull final CompileContext context)
      throws ProjectBuildException, IOException {
    LOG.debug(target.getPresentableName());
    final Ref<Boolean> hasDirtyFiles = Ref.create(false);
    holder.processDirtyFiles(
        new FileProcessor<ErlangSourceRootDescriptor, ErlangTarget>() {
          @Override
          public boolean apply(ErlangTarget target, File file, ErlangSourceRootDescriptor root)
              throws IOException {
            hasDirtyFiles.set(true);
            return true;
          }
        });
    if (!hasDirtyFiles.get() && !holder.hasRemovedFiles()) {
      return;
    }

    JpsModule module = target.getModule();
    JpsJavaExtensionService instance = JpsJavaExtensionService.getInstance();

    File outputDirectory = instance.getOutputDirectory(module, target.isTests());
    if (outputDirectory == null) {
      context.processMessage(
          new CompilerMessage(
              NAME, BuildMessage.Kind.ERROR, "No output dir for module " + module.getName()));
      throw new ProjectBuildException();
    }

    if (!outputDirectory.exists()) FileUtil.createDirectory(outputDirectory);

    JpsSdk<JpsDummyElement> sdk = module.getSdk(JpsErlangSdkType.INSTANCE);
    if (sdk == null) {
      context.processMessage(
          new CompilerMessage(
              NAME, BuildMessage.Kind.ERROR, "No SDK for module " + module.getName()));
      throw new ProjectBuildException();
    }

    File executable = JpsErlangSdkType.getByteCodeCompilerExecutable(sdk.getHomePath());

    List<String> commandList = new ArrayList<String>();
    commandList.add(executable.getAbsolutePath());

    CommonProcessors.CollectProcessor<File> processor =
        new CommonProcessors.CollectProcessor<File>() {
          @Override
          protected boolean accept(File file) {
            return !file.isDirectory() && FileUtilRt.extensionEquals(file.getName(), "erl");
          }
        };
    for (JpsModuleSourceRoot root : module.getSourceRoots()) {
      commandList.add("-I");
      commandList.add(root.getFile().getAbsolutePath());
      FileUtil.processFilesRecursively(root.getFile(), processor);
    }

    for (File f : processor.getResults()) {
      commandList.add(f.getAbsolutePath());
    }

    LOG.debug(StringUtil.join(commandList, " "));
    Process process = new ProcessBuilder(commandList).directory(outputDirectory).start();
    BaseOSProcessHandler handler =
        new BaseOSProcessHandler(process, null, Charset.defaultCharset());
    ProcessAdapter adapter =
        new ProcessAdapter() {
          @Override
          public void onTextAvailable(ProcessEvent event, Key outputType) {
            ErlangCompilerError error = ErlangCompilerError.create("", event.getText());
            if (error != null) {

              boolean isError = error.getCategory() == CompilerMessageCategory.ERROR;
              BuildMessage.Kind kind =
                  isError ? BuildMessage.Kind.ERROR : BuildMessage.Kind.WARNING;
              CompilerMessage msg =
                  new CompilerMessage(
                      NAME,
                      kind,
                      error.getErrorMessage(),
                      VirtualFileManager.extractPath(error.getUrl()),
                      -1,
                      -1,
                      -1,
                      error.getLine(),
                      -1);
              context.processMessage(msg);
            }
          }
        };
    handler.addProcessListener(adapter);
    handler.startNotify();
    handler.waitFor();
  }
  public static void addCompilationOptions(
      List<String> options,
      CompileContext context,
      ModuleChunk chunk,
      @Nullable ProcessorConfigProfile profile) {
    if (!isEncodingSet(options)) {
      final CompilerEncodingConfiguration config =
          context.getProjectDescriptor().getEncodingConfiguration();
      final String encoding = config.getPreferredModuleChunkEncoding(chunk);
      if (config.getAllModuleChunkEncodings(chunk).size() > 1) {
        final StringBuilder msgBuilder = new StringBuilder();
        msgBuilder.append("Multiple encodings set for module chunk ").append(chunk.getName());
        if (encoding != null) {
          msgBuilder.append("\n\"").append(encoding).append("\" will be used by compiler");
        }
        context.processMessage(
            new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.INFO, msgBuilder.toString()));
      }
      if (!StringUtil.isEmpty(encoding)) {
        options.add("-encoding");
        options.add(encoding);
      }
    }

    final String langLevel = getLanguageLevel(chunk.getModules().iterator().next());
    if (!StringUtil.isEmpty(langLevel)) {
      options.add("-source");
      options.add(langLevel);
    }

    JpsJavaCompilerConfiguration compilerConfiguration =
        JpsJavaExtensionService.getInstance()
            .getOrCreateCompilerConfiguration(context.getProjectDescriptor().getProject());
    String bytecodeTarget = null;
    int chunkSdkVersion = -1;
    for (JpsModule module : chunk.getModules()) {
      final JpsSdk<JpsDummyElement> sdk = module.getSdk(JpsJavaSdkType.INSTANCE);
      if (sdk != null) {
        final int moduleSdkVersion = convertToNumber(sdk.getVersionString());
        if (moduleSdkVersion != 0 /*could determine the version*/
            && (chunkSdkVersion < 0 || chunkSdkVersion > moduleSdkVersion)) {
          chunkSdkVersion = moduleSdkVersion;
        }
      }

      final String moduleTarget = compilerConfiguration.getByteCodeTargetLevel(module.getName());
      if (moduleTarget == null) {
        continue;
      }
      if (bytecodeTarget == null) {
        bytecodeTarget = moduleTarget;
      } else {
        if (moduleTarget.compareTo(bytecodeTarget) < 0) {
          bytecodeTarget =
              moduleTarget; // use the lower possible target among modules that form the chunk
        }
      }
    }
    if (bytecodeTarget != null) {
      options.add("-target");
      options.add(bytecodeTarget);
    } else {
      if (chunkSdkVersion > 0 && getCompilerSdkVersion(context) > chunkSdkVersion) {
        // force lower bytecode target level to match the version of sdk assigned to this chunk
        options.add("-target");
        options.add("1." + chunkSdkVersion);
      }
    }

    if (profile != null && profile.isEnabled()) {
      // configuring annotation processing
      if (!profile.isObtainProcessorsFromClasspath()) {
        final String processorsPath = profile.getProcessorPath();
        options.add("-processorpath");
        options.add(
            processorsPath == null ? "" : FileUtil.toSystemDependentName(processorsPath.trim()));
      }

      final Set<String> processors = profile.getProcessors();
      if (!processors.isEmpty()) {
        options.add("-processor");
        options.add(StringUtil.join(processors, ","));
      }

      for (Map.Entry<String, String> optionEntry : profile.getProcessorOptions().entrySet()) {
        options.add("-A" + optionEntry.getKey() + "=" + optionEntry.getValue());
      }

      final File srcOutput =
          ProjectPaths.getAnnotationProcessorGeneratedSourcesOutputDir(
              chunk.getModules().iterator().next(), chunk.containsTests(), profile);
      if (srcOutput != null) {
        srcOutput.mkdirs();
        options.add("-s");
        options.add(srcOutput.getPath());
      }
    } else {
      options.add("-proc:none");
    }
  }