From 117b3dbedca758fa08dd37d4a36cf4a2320fae03 Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Thu, 17 Apr 2014 14:29:46 +0400 Subject: [PATCH] IDEA-123994 Java 8 compact profiles support --- .../jps/incremental/java/JavaBuilder.java | 70 ++++++++++++++++++- .../org/jetbrains/jps/javac/JavacMain.java | 2 +- 2 files changed, 68 insertions(+), 4 deletions(-) diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java index db1700c47cbd..52e8b280c61b 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java @@ -37,6 +37,7 @@ import org.jetbrains.jps.api.RequestFuture; import org.jetbrains.jps.builders.BuildRootIndex; import org.jetbrains.jps.builders.DirtyFilesHolder; import org.jetbrains.jps.builders.FileProcessor; +import org.jetbrains.jps.builders.impl.java.JavacCompilerTool; import org.jetbrains.jps.builders.java.JavaBuilderExtension; import org.jetbrains.jps.builders.java.JavaBuilderUtil; import org.jetbrains.jps.builders.java.JavaCompilingTool; @@ -62,7 +63,8 @@ import org.jetbrains.jps.model.module.JpsModule; import org.jetbrains.jps.model.module.JpsModuleType; import org.jetbrains.jps.service.JpsServiceManager; -import javax.tools.*; +import javax.tools.Diagnostic; +import javax.tools.JavaFileObject; import java.io.*; import java.net.ServerSocket; import java.util.*; @@ -104,15 +106,35 @@ public class JavaBuilder extends ModuleLevelBuilder { return StringUtil.endsWithIgnoreCase(file.getPath(), DOT_JAVA_EXTENSION); } }; + private static final String RT_JAR_PATH_SUFFIX = File.separator + "rt.jar"; private final Executor myTaskRunner; private static final List ourClassProcessors = new ArrayList(); private static final Set> ourCompilableModuleTypes; + @Nullable + private static final File ourDefaultRtJar; static { ourCompilableModuleTypes = new HashSet>(); for (JavaBuilderExtension extension : JpsServiceManager.getInstance().getExtensions(JavaBuilderExtension.class)) { ourCompilableModuleTypes.addAll(extension.getCompilableModuleTypes()); } + File rtJar = null; + StringTokenizer tokenizer = new StringTokenizer(System.getProperty("sun.boot.class.path", ""), File.pathSeparator, false); + while (tokenizer.hasMoreTokens()) { + final String path = tokenizer.nextToken(); + if (isRtJarPath(path)) { + rtJar = new File(path); + break; + } + } + ourDefaultRtJar = rtJar; + } + + private static boolean isRtJarPath(String path) { + if (StringUtil.endsWithIgnoreCase(path, RT_JAR_PATH_SUFFIX)) { + return true; + } + return RT_JAR_PATH_SUFFIX.charAt(0) != '/' && StringUtil.endsWithIgnoreCase(path, "/rt.jar"); } public static void registerClassPostProcessor(ClassPostProcessor processor) { @@ -375,8 +397,16 @@ public class JavaBuilder extends ModuleLevelBuilder { try { final boolean rc; if (USE_EMBEDDED_JAVAC) { - rc = JavacMain.compile(options, files, classpath, platformCp, sourcePath, outs, diagnosticSink, classesConsumer, - context.getCancelStatus(), compilingTool); + final Collection _platformCp = calcEffectivePlatformCp(platformCp, options, compilingTool); + if (_platformCp == null) { + diagnosticSink.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, + "Compact compilation profile was requested, but target platform for module \"" + chunk.getName() + "\" differs from javac's platform (" + System.getProperty("java.version") + ")\nCompilation profiles are not supported for such configuration" + )); + return true; + } + rc = JavacMain.compile( + options, files, classpath, _platformCp, sourcePath, outs, diagnosticSink, classesConsumer, context.getCancelStatus(), compilingTool + ); } else { final JavacServerClient client = ensureJavacServerLaunched(context, compilingTool); @@ -397,6 +427,40 @@ public class JavaBuilder extends ModuleLevelBuilder { } } + // If platformCp of the build process is the same as the target plafform, do not specify platformCp explicitly + // this will allow javac to resolve against ct.sym file, which is required for the "compilation profiles" feature + @Nullable + private static Collection calcEffectivePlatformCp(Collection platformCp, List options, JavaCompilingTool compilingTool) { + if (ourDefaultRtJar == null || !(compilingTool instanceof JavacCompilerTool)) { + return platformCp; + } + boolean profileFeatureRequested = false; + for (String option : options) { + if ("-profile".equalsIgnoreCase(option)) { + profileFeatureRequested = true; + break; + } + } + if (!profileFeatureRequested) { + return platformCp; + } + boolean isTargetPlatformSameAsBuildRuntime = false; + for (File file : platformCp) { + if (FileUtil.filesEqual(file, ourDefaultRtJar)) { + isTargetPlatformSameAsBuildRuntime = true; + break; + } + } + if (!isTargetPlatformSameAsBuildRuntime) { + // compact profile was requested, but we have to use alternative platform classpath to meet project settings + // consider this a compile error and let user re-configure the project + return null; + } + // returning empty list will force default behaviour for platform classpath calculation + // javac will resolve against its own bootclasspath and use ct.sym file when available + return Collections.emptyList(); + } + private void submitAsyncTask(final CompileContext context, final Runnable taskRunnable) { final TasksCounter counter = COUNTER_KEY.get(context); diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacMain.java b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacMain.java index 1e238b0cdb16..d97e1c11e1d7 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacMain.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacMain.java @@ -77,7 +77,6 @@ public class JavacMain { final boolean usingJavac = compilingTool instanceof JavacCompilerTool; final JavacFileManager fileManager = new JavacFileManager(new ContextImpl(compiler, diagnosticConsumer, outputSink, canceledStatus, usingJavac), transformers); - fileManager.handleOption("-bootclasspath", Collections.singleton("").iterator()); // this will clear cached stuff fileManager.handleOption("-extdirs", Collections.singleton("").iterator()); // this will clear cached stuff fileManager.handleOption("-endorseddirs", Collections.singleton("").iterator()); // this will clear cached stuff final Collection _options = prepareOptions(options, compilingTool); @@ -115,6 +114,7 @@ public class JavacMain { if (!platformClasspath.isEmpty()) { try { + fileManager.handleOption("-bootclasspath", Collections.singleton("").iterator()); // this will clear cached stuff fileManager.setLocation(StandardLocation.PLATFORM_CLASS_PATH, buildPlatformClasspath(platformClasspath, _options)); } catch (IOException e) {