You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2019/11/22 02:23:37 UTC

[groovy] branch GROOVY_2_5_X updated: GROOVY-8775, GROOVY-9197: Ant: separate JVM and compilation classpaths

This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a commit to branch GROOVY_2_5_X
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/GROOVY_2_5_X by this push:
     new 4ba8777  GROOVY-8775, GROOVY-9197: Ant: separate JVM and compilation classpaths
4ba8777 is described below

commit 4ba877777610001da45a96c6e46570f25039b71d
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Fri Nov 15 10:23:46 2019 -0600

    GROOVY-8775, GROOVY-9197: Ant: separate JVM and compilation classpaths
---
 .../codehaus/groovy/tools/FileSystemCompiler.java  | 242 +++++++------
 src/spec/doc/tools-groovyc.adoc                    |  70 ++--
 .../main/java/org/codehaus/groovy/ant/Groovyc.java | 393 ++++++++++++---------
 3 files changed, 393 insertions(+), 312 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/tools/FileSystemCompiler.java b/src/main/java/org/codehaus/groovy/tools/FileSystemCompiler.java
index 9a0d042..8c80956 100644
--- a/src/main/java/org/codehaus/groovy/tools/FileSystemCompiler.java
+++ b/src/main/java/org/codehaus/groovy/tools/FileSystemCompiler.java
@@ -41,7 +41,6 @@ import java.io.File;
 import java.io.FileReader;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -54,6 +53,8 @@ import static groovy.ui.GroovyMain.processConfigScripts;
  * Command-line compiler (aka. <tt>groovyc</tt>).
  */
 public class FileSystemCompiler {
+
+    private static boolean displayStackTraceOnError;
     private final CompilationUnit unit;
 
     public FileSystemCompiler(CompilerConfiguration configuration) throws ConfigurationException {
@@ -70,38 +71,40 @@ public class FileSystemCompiler {
         }
     }
 
-    public void compile(String[] paths) throws Exception {
-        unit.addSources(paths);
-        unit.compile();
-    }
-
-    public void compile(File[] files) throws Exception {
-        unit.addSources(files);
-        unit.compile();
-    }
-
-    /** Prints the usage help message for {@link CompilationOptions} to stderr.
+    /**
+     * Prints the usage help message for {@link CompilationOptions} to stderr.
+     *
      * @see #displayHelp(PrintWriter)
-     * @since 2.5 */
+     * @since 2.5
+     */
     public static void displayHelp() {
         displayHelp(new PrintWriter(System.err, true));
     }
 
-    /** Prints the usage help message for the {@link CompilationOptions} to the specified PrintWriter.
-     * @since 2.5 */
-    public static void displayHelp(final PrintWriter writer) {
+    /**
+     * Prints the usage help message for the {@link CompilationOptions} to the specified PrintWriter.
+     *
+     * @since 2.5
+     */
+    public static void displayHelp(PrintWriter writer) {
         configureParser(new CompilationOptions()).usage(writer);
     }
 
-    /** Prints version information to stderr.
-     * @see #displayVersion(PrintWriter) */
+    /**
+     * Prints version information to stderr.
+     *
+     * @see #displayVersion(PrintWriter)
+     */
     public static void displayVersion() {
         displayVersion(new PrintWriter(System.err, true));
     }
 
-    /** Prints version information to the specified PrintWriter.
-     * @since 2.5 */
-    public static void displayVersion(final PrintWriter writer) {
+    /**
+     * Prints version information to the specified PrintWriter.
+     *
+     * @since 2.5
+     */
+    public static void displayVersion(PrintWriter writer) {
         for (String line : new VersionProvider().getVersion()) {
             writer.println(line);
         }
@@ -114,10 +117,10 @@ public class FileSystemCompiler {
             File file = new File(filename);
             if (!file.exists()) {
                 System.err.println("error: file not found: " + file);
-                ++errors;
+                errors += 1;
             } else if (!file.canRead()) {
                 System.err.println("error: file not readable: " + file);
-                ++errors;
+                errors += 1;
             }
         }
 
@@ -128,8 +131,6 @@ public class FileSystemCompiler {
         return checkFiles(filenames) == 0;
     }
 
-    private static boolean displayStackTraceOnError = false;
-
     /**
      * Same as main(args) except that exceptions are thrown out instead of causing
      * the VM to exit.
@@ -152,18 +153,18 @@ public class FileSystemCompiler {
         displayStackTraceOnError = options.printStack;
         CompilerConfiguration configuration = options.toCompilerConfiguration();
 
-        // Load the file name list
-        String[] filenames = options.generateFileNames();
-        boolean fileNameErrors = filenames == null;
-        if (!fileNameErrors && (filenames.length == 0)) {
+        // load the file name list
+        String[] fileNames = options.generateFileNames();
+        boolean fileNameErrors = fileNames == null;
+        if (!fileNameErrors && (fileNames.length == 0)) {
             parser.usage(System.err);
             return;
         }
 
-        fileNameErrors = fileNameErrors && !validateFiles(filenames);
+        fileNameErrors = fileNameErrors && !validateFiles(fileNames);
 
         if (!fileNameErrors) {
-            doCompilation(configuration, null, filenames, lookupUnnamedFiles);
+            doCompilation(configuration, null, fileNames, lookupUnnamedFiles);
         }
     }
 
@@ -219,8 +220,7 @@ public class FileSystemCompiler {
         // if there are any joint compilation options set stubDir if not set
         try {
             if ((configuration.getJointCompilationOptions() != null)
-                && !configuration.getJointCompilationOptions().containsKey("stubDir"))
-            {
+                    && !configuration.getJointCompilationOptions().containsKey("stubDir")) {
                 tmpDir = DefaultGroovyStaticMethods.createTempDir(null, "groovy-generated-", "-java-source");
                 configuration.getJointCompilationOptions().put("stubDir", tmpDir);
             }
@@ -235,7 +235,8 @@ public class FileSystemCompiler {
                 }
             } else {
                 compiler.unit.getClassLoader().setResourceLoader(new GroovyResourceLoader() {
-                    public URL loadGroovySource(String filename) throws MalformedURLException {
+                    @Override
+                    public URL loadGroovySource(String filename) {
                         return null;
                     }
                 });
@@ -254,7 +255,7 @@ public class FileSystemCompiler {
         if (filenames == null) {
             return new String[0];
         }
-        List<String> fileList = new ArrayList<String>(filenames.size());
+        List<String> fileList = new ArrayList<>(filenames.size());
         boolean errors = false;
         for (String filename : filenames) {
             if (filename.startsWith("@")) {
@@ -289,12 +290,72 @@ public class FileSystemCompiler {
         }
     }
 
+    public static void deleteRecursive(File file) {
+        if (!file.exists()) {
+            return;
+        }
+        if (file.isDirectory()) {
+            for (File f : file.listFiles()) {
+                deleteRecursive(f);
+            }
+        }
+        file.delete();
+    }
+
+    public void compile(String[] paths) throws Exception {
+        unit.addSources(paths);
+        unit.compile();
+    }
+
+    public void compile(File[] files) throws Exception {
+        unit.addSources(files);
+        unit.compile();
+    }
+
     /**
-     * @since 2.5 */
+     * @deprecated use {@link #displayHelp(PrintWriter)} instead
+     */
+    @Deprecated
+    public static void displayHelp(Options options) {
+        final HelpFormatter formatter = new HelpFormatter();
+        formatter.printHelp(80, "groovyc [options] <source-files>", "options:", options, "");
+    }
+
+    // some methods to avoid binary incompatibility - don't gain us a lot but gives the user
+    // something slightly less cryptic than a NoSuchMethodError or an IncompatibleClassChangeError
+    @Deprecated
+    public static CompilerConfiguration generateCompilerConfigurationFromOptions(org.apache.commons.cli.CommandLine cli) {
+        throw new DeprecationException("This method is not supported for Groovy 2.5+. Consider instead using the FileSystemCompiler.CompilationOptions class.");
+    }
+
+    @Deprecated
+    public static String[] generateFileNamesFromOptions(org.apache.commons.cli.CommandLine cli) {
+        throw new DeprecationException("This method is not supported for Groovy 2.5+. Consider instead using the FileSystemCompiler.CompilationOptions class.");
+    }
+
+    @Deprecated
+    public static Options createCompilationOptions() {
+        throw new DeprecationException("This method is not supported for Groovy 2.5+. Consider instead using the FileSystemCompiler.CompilationOptions class.");
+    }
+
+    /**
+     * Creates a temporary directory in the default temporary directory (as specified by the system
+     * property <i>java.io.tmpdir</i>.
+     *
+     * @deprecated Use {@link DefaultGroovyStaticMethods#createTempDir(java.io.File, String, String)} instead.
+     */
+    @Deprecated
+    public static File createTempDir() throws IOException {
+        return DefaultGroovyStaticMethods.createTempDir(null);
+    }
+
+    /**
+     * @since 2.5
+     */
     static class VersionProvider implements IVersionProvider {
         @Override
         public String[] getVersion() {
-            return new String[] {
+            return new String[]{
                     "Groovy compiler version " + GroovySystem.getVersion(),
                     "Copyright 2003-2019 The Apache Software Foundation. http://groovy-lang.org/",
                     "",
@@ -303,11 +364,9 @@ public class FileSystemCompiler {
     }
 
     /**
-     * @since 2.5 */
-    @Command(name = "groovyc",
-            customSynopsis = "groovyc [options] <source-files>",
-            sortOptions = false,
-            versionProvider = VersionProvider.class)
+     * @since 2.5
+     */
+    @Command(name = "groovyc", customSynopsis = "groovyc [options] <source-files>", sortOptions = false, versionProvider = VersionProvider.class)
     public static class CompilationOptions {
         // IMPLEMENTATION NOTE:
         // classpath must be the first argument, so that the `startGroovy(.bat)` script
@@ -361,43 +420,41 @@ public class FileSystemCompiler {
         @Option(names = {"-v", "--version"}, versionHelp = true, description = "Print version information and exit")
         private boolean versionRequested;
 
-        @Parameters(description = "The groovy source files to compile, or @-files containing a list of source files to compile",
-                    paramLabel = "<source-files>")
+        @Parameters(description = "The groovy source files to compile, or @-files containing a list of source files to compile", paramLabel = "<source-files>")
         private List<String> files;
 
         public CompilerConfiguration toCompilerConfiguration() throws IOException {
-            // Setup the configuration data
             CompilerConfiguration configuration = new CompilerConfiguration();
 
             if (classpath != null) {
                 configuration.setClasspath(classpath);
             }
 
-            if (targetDir != null && targetDir.getName().length() > 0) {
+            if (targetDir != null && !targetDir.getName().isEmpty()) {
                 configuration.setTargetDirectory(targetDir);
             }
 
             configuration.setParameters(parameterMetadata);
             configuration.setPreviewFeatures(previewFeatures);
-            configuration.setSourceEncoding(encoding);
             configuration.setScriptBaseClass(scriptBaseClass);
+            configuration.setSourceEncoding(encoding);
 
             // joint compilation parameters
             if (jointCompilation) {
-                Map<String, Object> compilerOptions = new HashMap<String, Object>();
-                compilerOptions.put("namedValues", javacOptionsList());
-                compilerOptions.put("flags", flagsWithParameterMetaData());
+                Map<String, Object> compilerOptions = new HashMap<>();
+                compilerOptions.put("flags", javacFlags());
+                compilerOptions.put("namedValues", javacNamedValues());
                 configuration.setJointCompilationOptions(compilerOptions);
             }
 
             if (indy) {
-                configuration.getOptimizationOptions().put("int", false);
-                configuration.getOptimizationOptions().put("indy", true);
+                configuration.getOptimizationOptions().put("int", Boolean.FALSE);
+                configuration.getOptimizationOptions().put("indy", Boolean.TRUE);
             }
 
             String configScripts = System.getProperty("groovy.starter.configscripts", null);
             if (configScript != null || (configScripts != null && !configScripts.isEmpty())) {
-                List<String> scripts = new ArrayList<String>();
+                List<String> scripts = new ArrayList<>();
                 if (configScript != null) {
                     scripts.add(configScript);
                 }
@@ -414,76 +471,29 @@ public class FileSystemCompiler {
             return generateFileNamesFromOptions(files);
         }
 
-        String[] javacOptionsList() {
-            if (javacOptionsMap == null) {
-                return null;
-            }
-            List<String> result = new ArrayList<String>();
-            for (Map.Entry<String, String> entry : javacOptionsMap.entrySet()) {
-                result.add(entry.getKey());
-                result.add(entry.getValue());
+        private String[] javacNamedValues() {
+            List<String> result = new ArrayList<>();
+            if (javacOptionsMap != null) {
+                for (Map.Entry<String, String> entry : javacOptionsMap.entrySet()) {
+                    result.add(entry.getKey());
+                    result.add(entry.getValue());
+                }
             }
-            return result.toArray(new String[0]);
+            return result.isEmpty() ? null : result.toArray(new String[0]);
         }
 
-        String[] flagsWithParameterMetaData() {
-            if (flags == null) {
-                return null;
+        private String[] javacFlags() {
+            List<String> result = new ArrayList<>();
+            if (flags != null) {
+                result.addAll(flags);
             }
             if (parameterMetadata) {
-                flags.add("parameters");
+                result.add("parameters");
             }
-            return flags.toArray(new String[0]);
-        }
-    }
-
-    /** @deprecated use {@link #displayHelp(PrintWriter)} instead */
-    @Deprecated
-    public static void displayHelp(final Options options) {
-        final HelpFormatter formatter = new HelpFormatter();
-        formatter.printHelp(80, "groovyc [options] <source-files>", "options:", options, "");
-    }
-
-    // some methods to avoid binary incompatibility - don't gain us a lot but gives the user
-    // something slightly less cryptic than a NoSuchMethodError or an IncompatibleClassChangeError
-    @Deprecated
-    public static CompilerConfiguration generateCompilerConfigurationFromOptions(org.apache.commons.cli.CommandLine cli) throws IOException {
-        throw new DeprecationException("This method is not supported for Groovy 2.5+. Consider instead using the FileSystemCompiler.CompilationOptions class.");
-    }
-
-    @Deprecated
-    public static String[] generateFileNamesFromOptions(org.apache.commons.cli.CommandLine cli) {
-        throw new DeprecationException("This method is not supported for Groovy 2.5+. Consider instead using the FileSystemCompiler.CompilationOptions class.");
-    }
-
-    @Deprecated
-    public static Options createCompilationOptions() {
-        throw new DeprecationException("This method is not supported for Groovy 2.5+. Consider instead using the FileSystemCompiler.CompilationOptions class.");
-    }
-
-    /**
-     * Creates a temporary directory in the default temporary directory (as specified by the system
-     * property <i>java.io.tmpdir</i>.
-     *
-     * @deprecated Use {@link DefaultGroovyStaticMethods#createTempDir(java.io.File, String, String)} instead.
-     */
-    @Deprecated
-    public static File createTempDir() throws IOException {
-        return DefaultGroovyStaticMethods.createTempDir(null);
-    }
-
-    public static void deleteRecursive(File file) {
-        if (!file.exists()) {
-            return;
-        }
-        if (file.isFile()) {
-            file.delete();
-        } else if (file.isDirectory()) {
-            File[] files = file.listFiles();
-            for (int i = 0; i < files.length; i++) {
-                deleteRecursive(files[i]);
+            if (previewFeatures) {
+                result.add("-enable-preview");
             }
-            file.delete();
+            return result.isEmpty() ? null : result.toArray(new String[0]);
         }
     }
 }
diff --git a/src/spec/doc/tools-groovyc.adoc b/src/spec/doc/tools-groovyc.adoc
index 7871561..6d81049 100644
--- a/src/spec/doc/tools-groovyc.adoc
+++ b/src/spec/doc/tools-groovyc.adoc
@@ -75,16 +75,18 @@ Compiles Groovy source files and, if joint compilation option is used, Java sour
 Required taskdef
 ^^^^^^^^^^^^^^^^
 
-Assuming all the groovy jars you need are in _my.classpath_ (this will be `groovy-VERSION.jar`,
-`groovy-ant-VERSION.jar` plus any modules and transitive dependencies you might be using)
-you will need to declare this task at some point in the `build.xml` prior to the `groovyc` task being invoked.
+Assuming the groovy jars are in _groovy.libs_, you will need to declare this task
+at some point in the `build.xml` prior to the `groovyc` task being invoked.
 
 [source,xml]
-----------------------------------------------------
-<taskdef name="groovyc"
-         classname="org.codehaus.groovy.ant.Groovyc"
-         classpathref="my.classpath"/>
-----------------------------------------------------
+-----------------------------------------------------------------------
+<taskdef name="groovyc" classname="org.codehaus.groovy.ant.Groovyc">
+  <classpath>
+    <fileset file="${groovy.libs}/groovy-ant-VERSION.jar"/>
+    <fileset file="${groovy.libs}/groovy-VERSION.jar"/>
+  </classpath>
+</taskdef>
+-----------------------------------------------------------------------
 
 [[ThegroovycAntTask-groovycAttributes]]
 <groovyc> Attributes
@@ -166,6 +168,9 @@ you need to set this flag to true. Defaults to false. |No
 |parameters |Generates metadata for reflection on method parameter names on JDK 8 and above.
 Defaults to false. |No
 
+|previewFeatures |Enables the JEP preview features on JDK 12 and above.
+Defaults to false. |No
+
 |targetBytecode |Sets the bytecode compatibility level. |No
 
 |javahome |Sets the `java.home` value to use, default is the current JDK's home. |No
@@ -187,10 +192,14 @@ the compilation fails. |No
 *Example:*
 
 [source,xml]
-----
-<groovyc srcdir="src" destdir="target/classes">
-</groovyc>
-----
+-----------------------------------------------------------------------
+<path id="classpath.main">
+  <fileset dir="${groovy.libs}" includes="*.jar" excludes="groovy-ant-*.jar"/>
+  ...
+</path>
+<groovyc srcdir="${dir.sources}" destdir="${dir.classes}" classpathref="classpath.main"
+         fork="true" includeantruntime="false" configscript="config.groovy" targetBytecode="1.8"/>
+-----------------------------------------------------------------------
 
 
 [[ThegroovycAntTask-groovycNestedElements]]
@@ -201,48 +210,41 @@ the compilation fails. |No
 |==========================================================
 |element |kind |Required |Replaces Attribute
 |src |a path structure |Yes (unless srcdir is used) |srcdir
-|classpath |a path structure |No |classpath
-|javac |javac task |No |jointCompilationOptions
+|classpath |a path structure |No |classpath or classpathref
+|javac |javac task |No |N/A
 |==========================================================
 
 *Notes:*
 
 * For path structures see for example
 http://ant.apache.org/manual/using.html#path
-* For usages of the javac task see
+* For usages of the `javac` task see
 https://ant.apache.org/manual/Tasks/javac.html
-* The nested javac task behaves more or less as documented for the
-top-level `javac` task. `srcdir`, `destdir`, `classpath`, `encoding` for the
-nested `javac` task are taken from the enclosing `groovyc` task. If these
-attributes are specified then they are added, they do not replace. In
-fact, you should not attempt to overwrite the destination. Other
-attributes and nested elements are unaffected, for example `fork`,
-`memoryMaximumSize`, etc. may be used freely.
+* The nested `javac` task behaves more or less as documented for the top-level
+`javac` task. `srcdir`, `destdir`, `classpath`, `encoding` and `parameters`
+for the nested `javac` task are taken from the enclosing `groovyc` task. If
+these attributes are specified then they are added, they do not replace. In fact,
+you should not attempt to overwrite the destination. Other attributes and nested
+elements are unaffected, for example `fork`, `memoryMaximumSize`, etc. may be
+used freely.
 
 [[ThegroovycAntTask-JointCompilation]]
 Joint Compilation
 ^^^^^^^^^^^^^^^^^
 
-Joint compilation is enabled by using an embedded `javac` element, as shown in
-the following example:
+Joint compilation is enabled by using an embedded `javac` element, as shown in the following example:
 
 [source,xml]
-----
-<groovyc srcdir="${testSourceDirectory}" destdir="${testClassesDirectory}">
+-----------------------------------------------------------------------
+<groovyc srcdir="${testSourceDirectory}" destdir="${testClassesDirectory}" targetBytecode="1.8">
   <classpath>
     <pathelement path="${mainClassesDirectory}"/>
     <pathelement path="${testClassesDirectory}"/>
     <path refid="testPath"/>
   </classpath>
-  <javac source="1.7" target="1.7" debug="on" />
+  <javac debug="true" source="1.8" target="1.8" />
 </groovyc>
-----
-
-It is rare to specify `srcdir` and `destdir`, the nested `javac` task is provided with the `srcdir`
-and `destdir` values from the enclosing `groovyc` task, and it is invariable
-the right thing to do just to leave this as is.
-To restate: the `javac` task gets the `srcdir`, `destdir` and `classpath` from
-the enclosing `groovyc` task.
+-----------------------------------------------------------------------
 
 More details about joint compilation can be found in the <<section-jointcompilation,joint compilation>> section.
 
diff --git a/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/Groovyc.java b/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/Groovyc.java
index 899536d..dd9b054 100644
--- a/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/Groovyc.java
+++ b/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/Groovyc.java
@@ -32,6 +32,7 @@ import org.apache.tools.ant.types.Path;
 import org.apache.tools.ant.types.Reference;
 import org.apache.tools.ant.util.GlobPatternMapper;
 import org.apache.tools.ant.util.SourceFileScanner;
+import org.codehaus.groovy.GroovyBugError;
 import org.codehaus.groovy.control.CompilationUnit;
 import org.codehaus.groovy.control.CompilerConfiguration;
 import org.codehaus.groovy.control.SourceExtensionHandler;
@@ -39,8 +40,8 @@ import org.codehaus.groovy.runtime.DefaultGroovyMethods;
 import org.codehaus.groovy.runtime.DefaultGroovyStaticMethods;
 import org.codehaus.groovy.tools.ErrorReporter;
 import org.codehaus.groovy.tools.FileSystemCompiler;
-import org.codehaus.groovy.tools.RootLoader;
 import org.codehaus.groovy.tools.javac.JavaAwareCompilationUnit;
+import org.objectweb.asm.ClassVisitor;
 import picocli.CommandLine;
 
 import java.io.File;
@@ -48,13 +49,14 @@ import java.io.FileWriter;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.Writer;
-import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.net.URL;
 import java.nio.charset.Charset;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.ArrayList;
-import java.util.Enumeration;
+import java.util.Collections;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
@@ -68,17 +70,22 @@ import java.util.StringTokenizer;
  * <pre>
  * &lt;?xml version="1.0"?&gt;
  * &lt;project name="MyGroovyBuild" default="compile"&gt;
- *   &lt;property name="groovy.home" value="/Path/To/Groovy"/&gt;
+ *   &lt;property name="groovy.home" location="/Path/To/Groovy"/&gt;
  *   &lt;property name="groovy.version" value="X.Y.Z"/&gt;
- *   &lt;path id="groovy.classpath"&gt;
- *     &lt;fileset dir="${groovy.home}/lib"&gt;
- *       &lt;include name="groovy-*${groovy.version}.jar" /&gt;
- *     &lt;/fileset&gt;
- *   &lt;/path&gt;
- *   &lt;taskdef name="groovyc" classname="org.codehaus.groovy.ant.Groovyc" classpathref="groovy.classpath"/&gt;
+ *
+ *   &lt;taskdef name="groovyc" classname="org.codehaus.groovy.ant.Groovyc"&gt;
+ *     &lt;classpath&gt;
+ *       &lt;fileset file="${groovy.home}/lib/groovy-${groovy.version}.jar"/&gt;
+ *       &lt;fileset file="${groovy.home}/lib/groovy-ant-${groovy.version}.jar"/&gt;
+ *     &lt;/classpath&gt;
+ *   &lt;/taskdef&gt;
  *
  *   &lt;target name="compile" description="compile groovy sources"&gt;
- *     &lt;groovyc srcdir="src" listfiles="true" classpathref="groovy.classpath"/&gt;
+ *     &lt;groovyc srcdir="src" destdir="bin" fork="true" listfiles="true" includeantruntime="false"/&gt;
+ *       &lt;classpath&gt;
+ *         &lt;fileset dir="${groovy.home}/lib" includes="groovy-*${groovy.version}.jar" excludes="groovy-ant-${groovy.version}.jar"/&gt;
+ *       &lt;/classpath&gt;
+ *     &lt;/groovyc&gt;
  *   &lt;/target&gt;
  * &lt;/project&gt;
  * </pre>
@@ -86,13 +93,13 @@ import java.util.StringTokenizer;
  * This task can take the following arguments:
  * <ul>
  * <li>srcdir</li>
- * <li>scriptExtension</li>
- * <li>targetBytecode</li>
  * <li>destdir</li>
  * <li>sourcepath</li>
  * <li>sourcepathRef</li>
  * <li>classpath</li>
  * <li>classpathRef</li>
+ * <li>scriptExtension</li>
+ * <li>targetBytecode</li>
  * <li>listfiles</li>
  * <li>failonerror</li>
  * <li>proceed</li>
@@ -124,39 +131,42 @@ import java.util.StringTokenizer;
  * </ul>
  * Of these arguments, the <b>srcdir</b> and <b>destdir</b> are required.
  * <p>
- * <p>When this task executes, it will recursively scan srcdir and destdir looking for Groovy source files
- * to compile. This task makes its compile decision based on timestamp.
+ * When this task executes, it will recursively scan srcdir and destdir looking
+ * for Groovy source files to compile. This task makes its compile decision based
+ * on timestamp.
  * <p>
  * A more elaborate build file showing joint compilation:
  * <pre>
  * &lt;?xml version="1.0"?&gt;
  * &lt;project name="MyJointBuild" default="compile"&gt;
- *   &lt;property name="groovy.home" value="/Path/To/Groovy"/&gt;
+ *   &lt;property name="groovy.home" location="/Path/To/Groovy"/&gt;
  *   &lt;property name="groovy.version" value="X.Y.Z"/&gt;
  *
- *   &lt;path id="groovy.classpath"&gt;
+ *   &lt;path id="classpath.main"&gt;
  *     &lt;fileset dir="${groovy.home}/lib"&gt;
- *       &lt;include name="groovy-*${groovy.version}.jar" /&gt;
+ *       &lt;include name="groovy-*${groovy.version}.jar"/&gt;
+ *       &lt;exclude name="groovy-ant-${groovy.version}.jar"/&gt;
  *     &lt;/fileset&gt;
  *   &lt;/path&gt;
  *
- *   &lt;target name="clean" description="remove all built files"&gt;
- *     &lt;delete dir="classes" /&gt;
- *   &lt;/target&gt;
+ *   &lt;taskdef name="groovyc" classname="org.codehaus.groovy.ant.Groovyc"&gt;
+ *     &lt;classpath&gt;
+ *       &lt;fileset file="${groovy.home}/lib/groovy-${groovy.version}.jar"/&gt;
+ *       &lt;fileset file="${groovy.home}/lib/groovy-ant-${groovy.version}.jar"/&gt;
+ *     &lt;/classpath&gt;
+ *   &lt;/taskdef&gt;
  *
- *   &lt;target name="compile" depends="init" description="compile java and groovy sources"&gt;
- *     &lt;mkdir dir="classes" /&gt;
- *     &lt;groovyc destdir="classes" srcdir="src" listfiles="true" keepStubs="true" stubdir="stubs"&gt;
- *       &lt;javac debug="on" deprecation="true"/&gt;
- *       &lt;classpath&gt;
- *         &lt;fileset dir="classes"/&gt;
- *         &lt;path refid="groovy.classpath"/&gt;
- *       &lt;/classpath&gt;
- *     &lt;/groovyc&gt;
+ *   &lt;target name="clean"&gt;
+ *     &lt;delete dir="bin" failonerror="false"/&gt;
  *   &lt;/target&gt;
  *
- *   &lt;target name="init"&gt;
- *     &lt;taskdef name="groovyc" classname="org.codehaus.groovy.ant.Groovyc" classpathref="groovy.classpath"/&gt;
+ *   &lt;target name="compile" depends="clean" description="compile java and groovy sources"&gt;
+ *     &lt;mkdir dir="bin"/&gt;
+ *
+ *     &lt;groovyc srcdir="src" destdir="bin" stubdir="stubs" keepStubs="true"
+ *      fork="true" includeantruntime="false" classpathref="classpath.main"&gt;
+ *       &lt;javac debug="true" source="1.8" target="1.8"/&gt;
+ *     &lt;/groovyc&gt;
  *   &lt;/target&gt;
  * &lt;/project&gt;
  * </pre>
@@ -166,9 +176,10 @@ import java.util.StringTokenizer;
  * Can also be used from {@link groovy.util.AntBuilder} to allow the build file to be scripted in Groovy.
  */
 public class Groovyc extends MatchingTask {
-    private static final URL[] EMPTY_URL_ARRAY = new URL[0];
+
     private static final File[] EMPTY_FILE_ARRAY = new File[0];
     private static final String[] EMPTY_STRING_ARRAY = new String[0];
+
     private final LoggingHelper log = new LoggingHelper(this);
 
     private Path src;
@@ -176,20 +187,20 @@ public class Groovyc extends MatchingTask {
     private Path compileClasspath;
     private Path compileSourcepath;
     private String encoding;
-    private boolean stacktrace = false;
-    private boolean verbose = false;
+    private boolean stacktrace;
+    private boolean verbose;
     private boolean includeAntRuntime = true;
-    private boolean includeJavaRuntime = false;
-    private boolean fork = false;
+    private boolean includeJavaRuntime;
+    private boolean fork;
     private File forkJavaHome;
-    private String forkedExecutable = null;
+    private String forkedExecutable;
     private String memoryInitialSize;
     private String memoryMaximumSize;
     private String scriptExtension = "*.groovy";
-    private String targetBytecode = null;
+    private String targetBytecode;
 
     protected boolean failOnError = true;
-    protected boolean listFiles = false;
+    protected boolean listFiles;
     protected File[] compileList = EMPTY_FILE_ARRAY;
 
     private String updatedProperty;
@@ -201,7 +212,7 @@ public class Groovyc extends MatchingTask {
     private Javac javac;
     private boolean jointCompilation;
 
-    private final List<File> temporaryFiles = new ArrayList<File>(2);
+    private final List<File> temporaryFiles = new ArrayList<>(2);
     private File stubDir;
     private boolean keepStubs;
     private boolean forceLookupUnnamedFiles;
@@ -209,17 +220,17 @@ public class Groovyc extends MatchingTask {
     private String scriptBaseClass;
     private String configscript;
 
-    private Set<String> scriptExtensions = new LinkedHashSet<String>();
+    private Set<String> scriptExtensions = new LinkedHashSet<>();
 
     /**
      * If true, generates metadata for reflection on method parameter names (jdk8+ only).  Defaults to false.
      */
-    private boolean parameters = false;
+    private boolean parameters;
 
     /**
      * If true, enable preview Java features (JEP 12) (jdk12+ only). Defaults to false.
      */
-    private boolean previewFeatures = false;
+    private boolean previewFeatures;
 
     /**
      * Adds a path for source compilation.
@@ -297,7 +308,6 @@ public class Groovyc extends MatchingTask {
      * @param version the bytecode compatibility level
      */
     public void setTargetBytecode(String version) {
-
         for (String allowedJdk : CompilerConfiguration.ALLOWED_JDKS) {
             if (allowedJdk.equals(version)) {
                 this.targetBytecode = version;
@@ -884,7 +894,7 @@ public class Groovyc extends MatchingTask {
      */
     protected void resetFileLists() {
         compileList = EMPTY_FILE_ARRAY;
-        scriptExtensions = new LinkedHashSet<String>();
+        scriptExtensions = new LinkedHashSet<>();
     }
 
     /**
@@ -960,64 +970,109 @@ public class Groovyc extends MatchingTask {
         }
     }
 
+    /**
+     * If {@code groovyc} task includes a nested {@code javac} task, check for
+     * shareable configuration.  {@code FileSystemCompiler} supports several
+     * command-line arguments for configuring joint compilation:
+     * <ul>
+     * <li><tt>-j</tt> enables joint compile
+     * <li><tt>-F</tt> is used to pass flags
+     * <li><tt>-J</tt> is used to pass name=value pairs
+     * </ul>
+     * Joint compilation options are transferred from {@link FileSystemCompiler}
+     * to {@link CompilerConfiguration}'s jointCompileOptions property.  Flags
+     * are saved to key "flags" (with the inclusion of "parameters" if enabled
+     * on groovyc), pairs are saved to key "namedValues" and the key "memStub"
+     * may also be set to {@link Boolean#TRUE} to influence joint compilation.
+     *
+     * @see org.codehaus.groovy.tools.javac.JavacJavaCompiler
+     * @see javax.tools.JavaCompiler
+     */
     private List<String> extractJointOptions(Path classpath) {
-        List<String> jointOptions = new ArrayList<String>();
+        List<String> jointOptions = new ArrayList<>();
         if (!jointCompilation) return jointOptions;
 
-        // extract joint options, some get pushed up...
+        // map "debug" and "debuglevel" to "-Fg"
+        if (javac.getDebug()) {
+            String level = javac.getDebugLevel();
+            jointOptions.add("-Fg" + (level == null ? "" : ":" + level));
+        } else {
+            jointOptions.add("-Fg:none");
+        }
+
+        // map "deprecation" to "-Fdeprecation"
+        if (javac.getDeprecation()) {
+            jointOptions.add("-Fdeprecation");
+        }
+
+        // map "nowarn" to "-Fnowarn"
+        if (javac.getNowarn()) {
+            jointOptions.add("-Fnowarn");
+        }
+
+        // map "verbose" to "-Fverbose"
+        if (javac.getVerbose()) {
+            jointOptions.add("-Fverbose");
+        }
+
         RuntimeConfigurable rc = javac.getRuntimeConfigurableWrapper();
-        for (Object o1 : rc.getAttributeMap().entrySet()) {
-            final Map.Entry e = (Map.Entry) o1;
-            final String key = e.getKey().toString();
-            final String value = getProject().replaceProperties(e.getValue().toString());
-            if (key.contains("debug")) {
-                String level = "";
-                if (javac.getDebugLevel() != null) {
-                    level = ":" + javac.getDebugLevel();
+
+        for (Map.Entry<String, Object> e : rc.getAttributeMap().entrySet()) {
+            String key = e.getKey();
+            if (key.equals("depend")
+                    || key.equals("encoding")
+                    || key.equals("extdirs")
+                    || key.equals("nativeheaderdir")
+                    || key.equals("release")
+                    || key.equals("source")
+                    || key.equals("target")) {
+                switch (key) {
+                case "nativeheaderdir":
+                    key = "h"; break;
+                case "release":
+                    key = "-" + key; // to get "--" when passed to javac
                 }
-                jointOptions.add("-Fg" + level);
-            } else if (key.contains("debugLevel")) {
-                // ignore, taken care of in debug
-            } else if ((key.contains("nowarn"))
-                    || (key.contains("verbose"))
-                    || (key.contains("deprecation"))) {
-                // false is default, so something to do only in true case
-                if ("on".equalsIgnoreCase(value) || "true".equalsIgnoreCase(value) || "yes".equalsIgnoreCase(value))
-                    jointOptions.add("-F" + key);
+                // map "depend", "encoding", etc. to "-Jkey=val"
+                jointOptions.add("-J" + key + "=" + getProject().replaceProperties(e.getValue().toString()));
+
             } else if (key.contains("classpath")) {
-                classpath.add(javac.getClasspath());
-            } else if ((key.contains("depend"))
-                    || (key.contains("extdirs"))
-                    || (key.contains("encoding"))
-                    || (key.contains("source"))
-                    || (key.contains("target"))
-                    || (key.contains("verbose"))) { // already handling verbose but pass on too
-                jointOptions.add("-J" + key + "=" + value);
-            } else {
-                log.warn("The option " + key + " cannot be set on the contained <javac> element. The option will be ignored");
+                if (key.startsWith("boot")) {
+                    // map "bootclasspath" or "bootclasspathref" to "-Jbootclasspath="
+                    jointOptions.add("-Jbootclasspath=" + javac.getBootclasspath());
+                } else {
+                    // map "classpath" or "classpathref" to "--classpath"
+                    classpath.add(javac.getClasspath());
+                }
+            } else if (key.contains("module") && key.contains("path")) {
+                if (key.startsWith("upgrade")) {
+                    // map "upgrademodulepath" or "upgrademodulepathref" to "-J-upgrade-module-path="
+                    jointOptions.add("-J-upgrade-module-path=" + javac.getUpgrademodulepath());
+                } else if (key.contains("source")) {
+                    // map "modulesourcepath" or "modulesourcepathref" to "-J-module-source-path="
+                    jointOptions.add("-J-module-source-path=" + javac.getModulesourcepath());
+                } else {
+                    // map "modulepath" or "modulepathref" to "-J-module-path="
+                    jointOptions.add("-J-module-path=" + javac.getModulepath());
+                }
+            } else if (!key.contains("debug") && !key.equals("deprecation") && !key.equals("nowarn") && !key.equals("verbose")) {
+                log.warn("The option " + key + " cannot be set on the contained <javac> element. The option will be ignored.");
             }
-            // TODO includes? excludes?
+            // TODO: defaultexcludes, excludes(file)?, includes(file)?, includeDestClasses, tempdir
         }
 
-        // ant's <javac> supports nested <compilerarg value=""> elements (there can be multiple of them)
-        // for additional options to be passed to javac.
-        Enumeration children = rc.getChildren();
-        while (children.hasMoreElements()) {
-            RuntimeConfigurable childrc = (RuntimeConfigurable) children.nextElement();
+        // Ant's <javac> supports nested <compilerarg value=""> elements (there
+        // can be multiple of them) for additional options to be passed to javac.
+        for (RuntimeConfigurable childrc : Collections.list(rc.getChildren())) {
             if (childrc.getElementTag().equals("compilerarg")) {
-                for (Object o : childrc.getAttributeMap().entrySet()) {
-                    final Map.Entry e = (Map.Entry) o;
-                    final String key = e.getKey().toString();
+                for (Map.Entry<String, Object> e : childrc.getAttributeMap().entrySet()) {
+                    String key = e.getKey();
                     if (key.equals("value")) {
-                        final String value = getProject().replaceProperties(e.getValue().toString());
+                        String value = getProject().replaceProperties(e.getValue().toString());
                         StringTokenizer st = new StringTokenizer(value, " ");
                         while (st.hasMoreTokens()) {
-                            String optionStr = st.nextToken();
-                            String replaced = optionStr.replace("-X", "-FX");
-                            if (optionStr.equals(replaced)) {
-                                replaced = optionStr.replace("-W", "-FW"); // GROOVY-5063
-                            }
-                            jointOptions.add(replaced);
+                            String option = st.nextToken();
+                            // GROOVY-5063: map "-Werror", etc. to "-FWerror"
+                            jointOptions.add(option.replaceFirst("^-(W|X|proc:)", "-F$1"));
                         }
                     }
                 }
@@ -1028,16 +1083,7 @@ public class Groovyc extends MatchingTask {
     }
 
     private void doForkCommandLineList(List<String> commandLineList, Path classpath, String separator) {
-        if (!fork) return;
-
-        if (includeAntRuntime) {
-            classpath.addExisting((new Path(getProject())).concatSystemClasspath("last"));
-        }
-        if (includeJavaRuntime) {
-            classpath.addJavaRuntime();
-        }
-
-        if (forkedExecutable != null && !forkedExecutable.equals("")) {
+        if (forkedExecutable != null && !forkedExecutable.isEmpty()) {
             commandLineList.add(forkedExecutable);
         } else {
             String javaHome;
@@ -1048,39 +1094,64 @@ public class Groovyc extends MatchingTask {
             }
             commandLineList.add(javaHome + separator + "bin" + separator + "java");
         }
-        commandLineList.add("-classpath");
-        commandLineList.add(getClasspathRelative(classpath));
 
-        final String fileEncodingProp = System.getProperty("file.encoding");
-        if ((fileEncodingProp != null) && !fileEncodingProp.equals("")) {
-            commandLineList.add("-Dfile.encoding=" + fileEncodingProp);
+        String[] bootstrapClasspath;
+        ClassLoader loader = getClass().getClassLoader();
+        if (loader instanceof AntClassLoader) {
+            bootstrapClasspath = ((AntClassLoader) loader).getClasspath().split(File.pathSeparator);
+        } else {
+            Class<?>[] bootstrapClasses = {
+                FileSystemCompilerFacade.class,
+                FileSystemCompiler.class,
+                antlr.Parser.class,
+                ClassVisitor.class,
+                CommandLine.class,
+            };
+            Set<String> locations = new LinkedHashSet<>();
+            for (Class<?> clazz : bootstrapClasses) {
+                locations.add(new File(getLocation(clazz)).getAbsolutePath());
+            }
+            bootstrapClasspath = locations.toArray(new String[locations.size()]);
         }
-        if (targetBytecode != null) {
-            commandLineList.add("-Dgroovy.target.bytecode=" + targetBytecode);
+        if (bootstrapClasspath.length > 0) {
+            commandLineList.add("-classpath");
+            commandLineList.add(getClasspathRelative(bootstrapClasspath));
         }
 
-        if ((memoryInitialSize != null) && !memoryInitialSize.equals("")) {
+        if (memoryInitialSize != null && !memoryInitialSize.isEmpty()) {
             commandLineList.add("-Xms" + memoryInitialSize);
         }
-        if ((memoryMaximumSize != null) && !memoryMaximumSize.equals("")) {
+        if (memoryMaximumSize != null && !memoryMaximumSize.isEmpty()) {
             commandLineList.add("-Xmx" + memoryMaximumSize);
         }
+        if (targetBytecode != null) {
+            commandLineList.add("-Dgroovy.target.bytecode=" + targetBytecode);
+        }
         if (!"*.groovy".equals(getScriptExtension())) {
             String tmpExtension = getScriptExtension();
             if (tmpExtension.startsWith("*."))
                 tmpExtension = tmpExtension.substring(1);
             commandLineList.add("-Dgroovy.default.scriptExtension=" + tmpExtension);
         }
+
         commandLineList.add(FileSystemCompilerFacade.class.getName());
+        commandLineList.add("--classpath");
+        if (includeAntRuntime) {
+            classpath.addExisting(new Path(getProject()).concatSystemClasspath("last"));
+        }
+        if (includeJavaRuntime) {
+            classpath.addJavaRuntime();
+        }
+        commandLineList.add(getClasspathRelative(classpath.list()));
         if (forceLookupUnnamedFiles) {
             commandLineList.add("--forceLookupUnnamedFiles");
         }
     }
 
-    private String getClasspathRelative(Path classpath) {
+    private String getClasspathRelative(String[] classpath) {
         String baseDir = getProject().getBaseDir().getAbsolutePath();
         StringBuilder sb = new StringBuilder();
-        for (String next : classpath.list()) {
+        for (String next : classpath) {
             if (sb.length() > 0) {
                 sb.append(File.pathSeparatorChar);
             }
@@ -1093,6 +1164,14 @@ public class Groovyc extends MatchingTask {
         return sb.toString();
     }
 
+    private static URI getLocation(Class<?> clazz) {
+        try {
+            return clazz.getProtectionDomain().getCodeSource().getLocation().toURI();
+        } catch (URISyntaxException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
     /**
      * Add "groovyc" parameters to the commandLineList, based on the ant configuration.
      *
@@ -1174,12 +1253,12 @@ public class Groovyc extends MatchingTask {
     }
 
     private String[] makeCommandLine(List<String> commandLineList) {
-        log.verbose("Compilation arguments:\n" + DefaultGroovyMethods.join((Iterable)commandLineList, "\n"));
+        log.verbose("Compilation arguments:\n" + DefaultGroovyMethods.join((Iterable<String>) commandLineList, "\n"));
         return commandLineList.toArray(EMPTY_STRING_ARRAY);
     }
 
     private void runForked(String[] commandLine) {
-        final Execute executor = new Execute();
+        Execute executor = new Execute();
         executor.setAntRun(getProject());
         executor.setWorkingDirectory(getProject().getBaseDir());
         executor.setCommandline(commandLine);
@@ -1188,7 +1267,7 @@ public class Groovyc extends MatchingTask {
         } catch (final IOException ioe) {
             throw new BuildException("Error running forked groovyc.", ioe);
         }
-        final int returnCode = executor.getExitValue();
+        int returnCode = executor.getExitValue();
         if (returnCode != 0) {
             taskSuccess = false;
             if (errorProperty != null) {
@@ -1214,28 +1293,23 @@ public class Groovyc extends MatchingTask {
             if (tmpExtension.startsWith("*."))
                 tmpExtension = tmpExtension.substring(1);
             configuration.setDefaultScriptExtension(tmpExtension);
-
-            // Load the file name list
-            String[] filenames = options.generateFileNames();
-            boolean fileNameErrors = filenames == null;
-
-            fileNameErrors = fileNameErrors || !FileSystemCompiler.validateFiles(filenames);
-
             if (targetBytecode != null) {
                 configuration.setTargetBytecode(targetBytecode);
             }
 
+            // Load the file name list
+            String[] fileNames = options.generateFileNames();
+            boolean fileNameErrors = (fileNames == null || !FileSystemCompiler.validateFiles(fileNames));
             if (!fileNameErrors) {
                 try (GroovyClassLoader loader = buildClassLoaderFor()) {
-                    FileSystemCompiler.doCompilation(configuration, makeCompileUnit(loader), filenames, forceLookupUnnamedFiles);
+                    FileSystemCompiler.doCompilation(configuration, makeCompileUnit(loader), fileNames, forceLookupUnnamedFiles);
                 }
             }
-
-        } catch (Exception re) {
-            Throwable t = re;
-            if ((re.getClass() == RuntimeException.class) && (re.getCause() != null)) {
+        } catch (Exception e) {
+            Throwable t = e;
+            if (e.getClass() == RuntimeException.class && e.getCause() != null) {
                 // unwrap to the real exception
-                t = re.getCause();
+                t = e.getCause();
             }
             Writer writer = new StringBuilderWriter();
             new ErrorReporter(t, false).write(new PrintWriter(writer));
@@ -1264,13 +1338,14 @@ public class Groovyc extends MatchingTask {
                     + (destDir != null ? " to " + destDir : ""));
 
             listFiles();
-            Path classpath = getClasspath() != null ? getClasspath() : new Path(getProject());
-            List<String> jointOptions = extractJointOptions(classpath);
 
-            String separator = System.getProperty("file.separator");
-            List<String> commandLineList = new ArrayList<String>();
+            Path classpath = getClasspath();
+            if (classpath == null)
+                classpath = new Path(getProject());
+            List<String> jointOptions = extractJointOptions(classpath);
+            List<String> commandLineList = new ArrayList<>();
 
-            doForkCommandLineList(commandLineList, classpath, separator);
+            if (fork) doForkCommandLineList(commandLineList, classpath, File.separator);
             doNormalCommandLineList(commandLineList, jointOptions, classpath);
             addSourceFiles(commandLineList);
 
@@ -1324,22 +1399,17 @@ public class Groovyc extends MatchingTask {
     }
 
     protected GroovyClassLoader buildClassLoaderFor() {
+        if (fork) {
+            throw new GroovyBugError("Cannot use Groovyc#buildClassLoaderFor() for forked compilation");
+        }
         // GROOVY-5044
-        if (!fork && !getIncludeantruntime()) {
+        if (!getIncludeantruntime()) {
             throw new IllegalArgumentException("The includeAntRuntime=false option is not compatible with fork=false");
         }
-        final ClassLoader parent =
-                AccessController.doPrivileged(
-                        new PrivilegedAction<ClassLoader>() {
-                            @Override
-                            public ClassLoader run() {
-                                return getIncludeantruntime()
-                                        ? getClass().getClassLoader()
-                                        : new AntClassLoader(new RootLoader(EMPTY_URL_ARRAY, null), getProject(), getClasspath());
-                            }
-                        });
-        if (parent instanceof AntClassLoader) {
-            AntClassLoader antLoader = (AntClassLoader) parent;
+
+        final ClassLoader loader = getClass().getClassLoader();
+        if (loader instanceof AntClassLoader) {
+            AntClassLoader antLoader = (AntClassLoader) loader;
             String[] pathElm = antLoader.getClasspath().split(File.pathSeparator);
             List<String> classpath = configuration.getClasspath();
             /*
@@ -1370,23 +1440,22 @@ public class Groovyc extends MatchingTask {
             }
         }
 
-        GroovyClassLoader loader =
-                AccessController.doPrivileged(
-                        new PrivilegedAction<GroovyClassLoader>() {
-                            @Override
-                            public GroovyClassLoader run() {
-                                return new GroovyClassLoader(parent, configuration);
-                            }
-                        });
+        GroovyClassLoader groovyLoader = AccessController.doPrivileged(new PrivilegedAction<GroovyClassLoader>() {
+            @Override
+            public GroovyClassLoader run() {
+                return new GroovyClassLoader(loader, configuration);
+            }
+        });
         if (!forceLookupUnnamedFiles) {
             // in normal case we don't need to do script lookups
-            loader.setResourceLoader(new GroovyResourceLoader() {
-                public URL loadGroovySource(String filename) throws MalformedURLException {
+            groovyLoader.setResourceLoader(new GroovyResourceLoader() {
+                @Override
+                public URL loadGroovySource(String filename) {
                     return null;
                 }
             });
         }
-        return loader;
+        return groovyLoader;
     }
 
     private Set<String> getScriptExtensions() {
@@ -1395,14 +1464,14 @@ public class Groovyc extends MatchingTask {
 
     private void loadRegisteredScriptExtensions() {
         if (scriptExtensions.isEmpty()) {
-
             scriptExtensions.add(getScriptExtension().substring(2)); // first extension will be the one set explicitly on <groovyc>
 
-            Path classpath = getClasspath() != null ? getClasspath() : new Path(getProject());
-            final String[] pe = classpath.list();
+            Path classpath = getClasspath();
+            if (classpath == null)
+                classpath = new Path(getProject());
             try (GroovyClassLoader loader = new GroovyClassLoader(getClass().getClassLoader())) {
-                for (String file : pe) {
-                    loader.addClasspath(file);
+                for (String element : classpath.list()) {
+                    loader.addClasspath(element);
                 }
                 scriptExtensions.addAll(SourceExtensionHandler.getRegisteredExtensions(loader));
             } catch (IOException e) {