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 boolean compileJava( final CompileContext context, ModuleChunk chunk, Collection<File> files, Collection<File> classpath, Collection<File> platformCp, Collection<File> sourcePath, DiagnosticOutputConsumer diagnosticSink, final OutputFileConsumer outputSink) throws Exception { final TasksCounter counter = new TasksCounter(); COUNTER_KEY.set(context, counter); final JpsJavaExtensionService javaExt = JpsJavaExtensionService.getInstance(); final JpsJavaCompilerConfiguration compilerConfig = javaExt.getCompilerConfiguration(context.getProjectDescriptor().getProject()); assert compilerConfig != null; final Set<JpsModule> modules = chunk.getModules(); ProcessorConfigProfile profile = null; if (modules.size() == 1) { final JpsModule module = modules.iterator().next(); profile = compilerConfig.getAnnotationProcessingProfile(module); } else { // perform cycle-related validations Pair<String, LanguageLevel> pair = null; for (JpsModule module : modules) { final LanguageLevel moduleLevel = javaExt.getLanguageLevel(module); if (pair == null) { pair = Pair.create(module.getName(), moduleLevel); // first value } else { if (!Comparing.equal(pair.getSecond(), moduleLevel)) { final String message = "Modules " + pair.getFirst() + " and " + module.getName() + " must have the same language level because of cyclic dependencies between them"; diagnosticSink.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, message)); return true; } } } // check that all chunk modules are excluded from annotation processing for (JpsModule module : modules) { final ProcessorConfigProfile prof = compilerConfig.getAnnotationProcessingProfile(module); if (prof.isEnabled()) { final String message = "Annotation processing is not supported for module cycles. Please ensure that all modules from cycle [" + chunk.getName() + "] are excluded from annotation processing"; diagnosticSink.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, message)); return true; } } } final Map<File, Set<File>> outs = buildOutputDirectoriesMap(context, chunk); final List<String> options = getCompilationOptions(context, chunk, profile); final ClassProcessingConsumer classesConsumer = new ClassProcessingConsumer(context, outputSink); if (LOG.isDebugEnabled()) { LOG.debug( "Compiling chunk [" + chunk.getName() + "] with options: \"" + StringUtil.join(options, " ") + "\""); } try { final boolean rc; if (USE_EMBEDDED_JAVAC) { final boolean useEclipse = useEclipseCompiler(context); rc = JavacMain.compile( options, files, classpath, platformCp, sourcePath, outs, diagnosticSink, classesConsumer, context.getCancelStatus(), useEclipse); } else { final JavacServerClient client = ensureJavacServerLaunched(context); final RequestFuture<JavacServerResponseHandler> future = client.sendCompileRequest( options, files, classpath, platformCp, sourcePath, outs, diagnosticSink, classesConsumer); while (!future.waitFor(100L, TimeUnit.MILLISECONDS)) { if (context.getCancelStatus().isCanceled()) { future.cancel(false); } } rc = future.getMessageHandler().isTerminatedSuccessfully(); } return rc; } finally { counter.await(); } }