Browse Source

Added modulepath, modulesourcepath and upgrademodulepath into Javac task.

master
Tomas Zezula Stefan Bodewig 9 years ago
parent
commit
83eaf48045
5 changed files with 809 additions and 23 deletions
  1. +82
    -6
      manual/Tasks/javac.html
  2. +415
    -17
      src/main/org/apache/tools/ant/taskdefs/Javac.java
  3. +64
    -0
      src/main/org/apache/tools/ant/taskdefs/compilers/DefaultCompilerAdapter.java
  4. +85
    -0
      src/tests/junit/org/apache/tools/ant/taskdefs/JavacTest.java
  5. +163
    -0
      src/tests/junit/org/apache/tools/ant/taskdefs/compilers/DefaultCompilerAdapterTest.java

+ 82
- 6
manual/Tasks/javac.html View File

@@ -135,7 +135,7 @@ invoking the compiler.</p>
<td valign="top">srcdir</td> <td valign="top">srcdir</td>
<td valign="top">Location of the java files. (See the <td valign="top">Location of the java files. (See the
<a href="#srcdirnote">note</a> below.)</td> <a href="#srcdirnote">note</a> below.)</td>
<td align="center" valign="top">Yes, unless nested <code>&lt;src&gt;</code> elements are present.</td>
<td align="center" valign="top">Yes, unless nested <code>&lt;src&gt;</code> elements or <code>modulesourcepath</code> attribute or elements are present.</td>
</tr> </tr>
<tr> <tr>
<td valign="top">destdir</td> <td valign="top">destdir</td>
@@ -459,6 +459,51 @@ invoking the compiler.</p>
</td> </td>
<td align="center" valign="top">No - default is "true"</td> <td align="center" valign="top">No - default is "true"</td>
</tr> </tr>
<tr>
<td valign="top">modulepath</td>
<td valign="top">
Specify where to find application modules. A list of directories of modules, module files or exploded modules.
<em>since Ant 1.9.7</em>
</td>
<td align="center" valign="top">No</td>
</tr>
<tr>
<td valign="top">modulepathref</td>
<td valign="top">
The modulepath to use, given as <a href="../using.html#references">reference</a> to a PATH defined elsewhere.
<em>since Ant 1.9.7</em></td>
<td align="center" valign="top">No</td>
</tr>
<tr>
<td valign="top">modulesourcepath</td>
<td valign="top">
Specify where to find input source files for multiple module compilation.
<em>since Ant 1.9.7</em>
</td>
<td align="center" valign="top">Yes, unless <code>srcdir</code> attribute or nested <code>&lt;src&gt;</code> elements are present</td>
</tr>
<tr>
<td valign="top">modulesourcepathref</td>
<td valign="top">
The modulesourcepath to use, given as <a href="../using.html#references">reference</a> to a PATH defined elsewhere.
<em>since Ant 1.9.7</em></td>
<td align="center" valign="top">No</td>
</tr>
<tr>
<td valign="top">upgrademodulepath</td>
<td valign="top">
Specify the location of modules that replace upgradeable modules in the runtime image.
<em>since Ant 1.9.7</em>
</td>
<td align="center" valign="top">No</td>
</tr>
<tr>
<td valign="top">upgrademodulepathref</td>
<td valign="top">
The upgrademodulepath to use, given as <a href="../using.html#references">reference</a> to a PATH defined elsewhere.
<em>since Ant 1.9.7</em></td>
<td align="center" valign="top">No</td>
</tr>
</table> </table>


<h3>Parameters specified as nested elements</h3> <h3>Parameters specified as nested elements</h3>
@@ -468,17 +513,23 @@ supports most attributes of <code>&lt;fileset&gt;</code>
<code>&lt;include&gt;</code>, <code>&lt;exclude&gt;</code> and <code>&lt;include&gt;</code>, <code>&lt;exclude&gt;</code> and
<code>&lt;patternset&gt;</code> elements.</p> <code>&lt;patternset&gt;</code> elements.</p>
<h4><code>srcdir</code>, <code>classpath</code>, <code>sourcepath</code>, <h4><code>srcdir</code>, <code>classpath</code>, <code>sourcepath</code>,
<code>bootclasspath</code> and <code>extdirs</code></h4>
<code>bootclasspath</code>, <code>modulepath</code>, <code>modulesourcepath</code>,
<code>upgrademodulepath</code> and <code>extdirs</code></h4>
<p><code>&lt;javac&gt;</code>'s <code>srcdir</code>, <code>classpath</code>, <p><code>&lt;javac&gt;</code>'s <code>srcdir</code>, <code>classpath</code>,
<code>sourcepath</code>, <code>bootclasspath</code>, and
<code>extdirs</code> attributes are
<code>sourcepath</code>, <code>bootclasspath</code>,
<code>extdirs</code>, <code>modulepath</code>, <code>modulesourcepath</code>,
and <code>upgrademodulepath</code> attributes are
<a href="../using.html#path">path-like structures</a> <a href="../using.html#path">path-like structures</a>
and can also be set via nested and can also be set via nested
<code>&lt;src&gt;</code> (note the different name!), <code>&lt;src&gt;</code> (note the different name!),
<code>&lt;classpath&gt;</code>, <code>&lt;classpath&gt;</code>,
<code>&lt;sourcepath&gt;</code>, <code>&lt;sourcepath&gt;</code>,
<code>&lt;bootclasspath&gt;</code> and
<code>&lt;extdirs&gt;</code> elements, respectively.</p>
<code>&lt;bootclasspath&gt;</code>,
<code>&lt;extdirs&gt;</code>,
<code>&lt;modulepath&gt;</code>,
<code>&lt;modulesourcepath&gt;</code> and
<code>&lt;upgrademodulepath&gt;</code>
elements, respectively.</p>


<h4>compilerarg</h4> <h4>compilerarg</h4>


@@ -710,6 +761,31 @@ the <tt>&lt;compilerarg&gt;</tt> element:
<p>in which case your compiler adapter can support attributes and <p>in which case your compiler adapter can support attributes and
nested elements of its own.</p> nested elements of its own.</p>


<pre> &lt;javac srcdir=&quot;${src}&quot;
destdir=&quot;${build}&quot;
includeantruntime=&quot;false&quot;
modulepath=&quot;modules&quot;
source=&quot;9&quot;
/&gt;</pre>
<p>compiles all <code>.java</code> files in a single module under the <code>${src}</code> directory,
and stores the <code>.class</code> files in the <code>${build}</code> directory. The compilation uses
application modules located in <code>modules</code> folder.The source level is <code>9</code> to enable modules.</p>

<pre> &lt;javac modulesourcepath=&quot;${src}/*/{gen,lin{32,64}}/classes&quot;
destdir=&quot;${build}&quot;
includeantruntime=&quot;false&quot;
modulepath=&quot;modules&quot;
source=&quot;9&quot;
/&gt;</pre>
<p>compiles all <code>.java</code> files in <code>gen/classes</code>, <code>lin32/classes</code> and
<code>lin64/classes</code> in all source modules under the <code>${src}</code> directory.
Generates module directories in the <code>${build}</code> directory. Each generated module directory under
the <code>${build}</code> directory contains <code>.class</code> files from corresponding source module.
The <code>*</code> is a token representing the name of any of the modules in the compilation module set.
The <code>{ ... , ... }</code> express alternates for expansion.
The compilation uses application modules located in <code>modules</code> folder.The source level is
<code>9</code> to enable modules.</p>

<h3>Jikes Notes</h3> <h3>Jikes Notes</h3>


<p>You need Jikes 1.15 or later.</p> <p>You need Jikes 1.15 or later.</p>


+ 415
- 17
src/main/org/apache/tools/ant/taskdefs/Javac.java View File

@@ -19,12 +19,17 @@
package org.apache.tools.ant.taskdefs; package org.apache.tools.ant.taskdefs;


import java.io.File; import java.io.File;
import java.io.FileFilter;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.TreeMap;


import org.apache.tools.ant.BuildException; import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.DirectoryScanner;
@@ -93,12 +98,20 @@ public class Javac extends MatchingTask {
private static final String CLASSIC = "classic"; private static final String CLASSIC = "classic";
private static final String EXTJAVAC = "extJavac"; private static final String EXTJAVAC = "extJavac";


private static final char GROUP_START_MARK = '{'; //modulesourcepath group start character
private static final char GROUP_END_MARK = '}'; //modulesourcepath group end character
private static final char GROUP_SEP_MARK = ','; //modulesourcepath group element separator character
private static final String MODULE_MARKER = "*"; //modulesourcepath module name marker

private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();


private Path src; private Path src;
private File destDir; private File destDir;
private Path compileClasspath; private Path compileClasspath;
private Path modulepath;
private Path upgrademodulepath;
private Path compileSourcepath; private Path compileSourcepath;
private Path moduleSourcepath;
private String encoding; private String encoding;
private boolean debug = false; private boolean debug = false;
private boolean optimize = false; private boolean optimize = false;
@@ -310,6 +323,49 @@ public class Javac extends MatchingTask {
createSourcepath().setRefid(r); createSourcepath().setRefid(r);
} }


/**
* Set the modulesourcepath to be used for this compilation.
* @param msp the modulesourcepath
* @since 1.9.7
*/
public void setModulesourcepath(final Path msp) {
if (moduleSourcepath == null) {
moduleSourcepath = msp;
} else {
moduleSourcepath.append(msp);
}
}

/**
* Gets the modulesourcepath to be used for this compilation.
* @return the modulesourcepath
* @since 1.9.7
*/
public Path getModulesourcepath() {
return moduleSourcepath;
}

/**
* Adds a path to modulesourcepath.
* @return a modulesourcepath to be configured
* @since 1.9.7
*/
public Path createModulesourcepath() {
if (moduleSourcepath == null) {
moduleSourcepath = new Path(getProject());
}
return moduleSourcepath.createPath();
}

/**
* Adds a reference to a modulesourcepath defined elsewhere.
* @param r a reference to a modulesourcepath
* @since 1.9.7
*/
public void setModulesourcepathRef(final Reference r) {
createModulesourcepath().setRefid(r);
}

/** /**
* Set the classpath to be used for this compilation. * Set the classpath to be used for this compilation.
* *
@@ -350,6 +406,92 @@ public class Javac extends MatchingTask {
createClasspath().setRefid(r); createClasspath().setRefid(r);
} }


/**
* Set the modulepath to be used for this compilation.
* @param mp an Ant Path object containing the modulepath.
* @since 1.9.7
*/
public void setModulepath(final Path mp) {
if (modulepath == null) {
modulepath = mp;
} else {
modulepath.append(mp);
}
}

/**
* Gets the modulepath to be used for this compilation.
* @return the modulepath
* @since 1.9.7
*/
public Path getModulepath() {
return modulepath;
}

/**
* Adds a path to the modulepath.
* @return a modulepath to be configured
* @since 1.9.7
*/
public Path createModulepath() {
if (modulepath == null) {
modulepath = new Path(getProject());
}
return modulepath.createPath();
}

/**
* Adds a reference to a modulepath defined elsewhere.
* @param r a reference to a modulepath
* @since 1.9.7
*/
public void setModulepathRef(final Reference r) {
createModulepath().setRefid(r);
}

/**
* Set the upgrademodulepath to be used for this compilation.
* @param ump an Ant Path object containing the upgrademodulepath.
* @since 1.9.7
*/
public void setUpgrademodulepath(final Path ump) {
if (upgrademodulepath == null) {
upgrademodulepath = ump;
} else {
upgrademodulepath.append(ump);
}
}

/**
* Gets the upgrademodulepath to be used for this compilation.
* @return the upgrademodulepath
* @since 1.9.7
*/
public Path getUpgrademodulepath() {
return upgrademodulepath;
}

/**
* Adds a path to the upgrademodulepath.
* @return an upgrademodulepath to be configured
* @since 1.9.7
*/
public Path createUpgrademodulepath() {
if (upgrademodulepath == null) {
upgrademodulepath = new Path(getProject());
}
return upgrademodulepath.createPath();
}

/**
* Adds a reference to the upgrademodulepath defined elsewhere.
* @param r a reference to an upgrademodulepath
* @since 1.9.7
*/
public void setUpgrademodulepathRef(final Reference r) {
createUpgrademodulepath().setRefid(r);
}

/** /**
* Sets the bootclasspath that will be used to compile the classes * Sets the bootclasspath that will be used to compile the classes
* against. * against.
@@ -918,19 +1060,45 @@ public class Javac extends MatchingTask {


// scan source directories and dest directory to build up // scan source directories and dest directory to build up
// compile lists // compile lists
final String[] list = src.list();
for (int i = 0; i < list.length; i++) {
final File srcDir = getProject().resolveFile(list[i]);
if (!srcDir.exists()) {
throw new BuildException("srcdir \""
+ srcDir.getPath()
+ "\" does not exist!", getLocation());
}
// Both src and modulesourcepath can be passed to javac, in this case
// the src becomes a part of the unnamed module.
if (hasPath(src)) {
final String[] list = src.list();
for (int i = 0; i < list.length; i++) {
final File srcDir = getProject().resolveFile(list[i]);
if (!srcDir.exists()) {
throw new BuildException("srcdir \""
+ srcDir.getPath()
+ "\" does not exist!", getLocation());
}


final DirectoryScanner ds = this.getDirectoryScanner(srcDir);
final String[] files = ds.getIncludedFiles();
final DirectoryScanner ds = this.getDirectoryScanner(srcDir);
final String[] files = ds.getIncludedFiles();


scanDir(srcDir, destDir != null ? destDir : srcDir, files);
scanDir(srcDir, destDir != null ? destDir : srcDir, files);
}
} else {
assert hasPath(moduleSourcepath) : "Either srcDir or moduleSourcepath must be given";
final FileUtils fu = FileUtils.getFileUtils();
for (String pathElement : moduleSourcepath.list()) {
boolean valid = false;
for (Map.Entry<String,Collection<File>> modules : resolveModuleSourcePathElement(getProject().getBaseDir(), pathElement).entrySet()) {
final String moduleName = modules.getKey();
for (File srcDir : modules.getValue()) {
if (srcDir.exists()) {
valid = true;
final DirectoryScanner ds = getDirectoryScanner(srcDir);
final String[] files = ds.getIncludedFiles();
scanDir(srcDir, fu.resolveFile(destDir, moduleName), files);
}
}
}
if (!valid) {
throw new BuildException("modulesourcepath \""
+ pathElement
+ "\" does not exist!", getLocation());
}
}
} }


compile(); compile();
@@ -1106,13 +1274,23 @@ public class Javac extends MatchingTask {
* @exception BuildException if an error occurs * @exception BuildException if an error occurs
*/ */
protected void checkParameters() throws BuildException { protected void checkParameters() throws BuildException {
if (src == null) {
throw new BuildException("srcdir attribute must be set!",
getLocation());
}
if (src.size() == 0) {
throw new BuildException("srcdir attribute must be set!",
if (hasPath(src)) {
if (hasPath(moduleSourcepath)) {
throw new BuildException("modulesourcepath cannot be combined with srcdir attribute!",
getLocation());
}
} else if (hasPath(moduleSourcepath)) {
if (hasPath(src) || hasPath(compileSourcepath)) {
throw new BuildException("modulesourcepath cannot be combined with srcdir or sourcepath !",
getLocation());
}
if (destDir == null) {
throw new BuildException("modulesourcepath requires destdir attribute to be set!",
getLocation()); getLocation());
}
} else {
throw new BuildException("either srcdir or modulesourcepath attribute must be set!",
getLocation());
} }


if (destDir != null && !destDir.isDirectory()) { if (destDir != null && !destDir.isDirectory()) {
@@ -1251,6 +1429,226 @@ public class Javac extends MatchingTask {
} }
} }


/**
* Checks if a path exists and is non empty.
* @param path to be checked
* @return true if the path is non <code>null</code> and non empty.
* @since 1.9.7
*/
private static boolean hasPath(final Path path) {
return path != null && path.size() > 0;
}

/**
* Resolves the modulesourcepath element possibly containing groups
* and module marks to module names and source roots.
* @param projectDir the project directory
* @param element the modulesourcepath elemement
* @return a mapping from module name to module source roots
* @since 1.9.7
*/
private static Map<String,Collection<File>> resolveModuleSourcePathElement(
final File projectDir,
final String element) {
final Map<String,Collection<File>> result = new TreeMap<String, Collection<File>>();
for (CharSequence resolvedElement : expandGroups(element)) {
findModules(projectDir, resolvedElement.toString(), result);
}
return result;
}

/**
* Expands the groups in the modulesourcepath entry to alternatives.
* <p>
* The <code>'*'</code> is a token representing the name of any of the modules in the compilation module set.
* The <code>'{' ... ',' ... '}'</code> express alternates for expansion.
* An example of the modulesourcepath entry is <code>src/&#42;/{linux,share}/classes</code>
* </p>
* @param element the entry to expand groups in
* @return the possible alternatives
* @since 1.9.7
*/
private static Collection<? extends CharSequence> expandGroups(
final CharSequence element) {
List<StringBuilder> result = new ArrayList<StringBuilder>();
result.add(new StringBuilder());
StringBuilder resolved = new StringBuilder();
for (int i = 0; i < element.length(); i++) {
final char c = element.charAt(i);
switch (c) {
case GROUP_START_MARK:
final int end = getGroupEndIndex(element, i);
if (end < 0) {
throw new BuildException(String.format(
"Unclosed group %s, starting at: %d",
element,
i));
}
final Collection<? extends CharSequence> parts = resolveGroup(element.subSequence(i+1, end));
switch (parts.size()) {
case 0:
break;
case 1:
resolved.append(parts.iterator().next());
break;
default:
final List<StringBuilder> oldRes = result;
result = new ArrayList<StringBuilder>(oldRes.size() * parts.size());
for (CharSequence part : parts) {
for (CharSequence prefix : oldRes) {
result.add(new StringBuilder(prefix).append(resolved).append(part));
}
}
resolved = new StringBuilder();
}
i = end;
break;
default:
resolved.append(c);
}
}
for (StringBuilder prefix : result) {
prefix.append(resolved);
}
return result;
}

/**
* Resolves the group to alternatives.
* @param group the group to resolve
* @return the possible alternatives
* @since 1.9.7
*/
private static Collection<? extends CharSequence> resolveGroup(final CharSequence group) {
final Collection<CharSequence> result = new ArrayList<CharSequence>();
int start = 0;
int depth = 0;
for (int i = 0; i < group.length(); i++) {
final char c = group.charAt(i);
switch (c) {
case GROUP_START_MARK:
depth++;
break;
case GROUP_END_MARK:
depth--;
break;
case GROUP_SEP_MARK:
if (depth == 0) {
result.addAll(expandGroups(group.subSequence(start, i)));
start = i + 1;
}
break;
}
}
result.addAll(expandGroups(group.subSequence(start, group.length())));
return result;
}

/**
* Finds the index of an enclosing brace of the group.
* @param element the element to find the enclosing brace in
* @param start the index of the opening brace.
* @return return the index of an enclosing brace of the group or -1 if not found
* @since 1.9.7
*/
private static int getGroupEndIndex(
final CharSequence element,
final int start) {
int depth = 0;
for (int i = start; i < element.length(); i++) {
final char c = element.charAt(i);
switch (c) {
case GROUP_START_MARK:
depth++;
break;
case GROUP_END_MARK:
depth--;
if (depth == 0) {
return i;
}
break;
}
}
return -1;
}

/**
* Finds modules in the expanded modulesourcepath entry.
* @param root the project root
* @param pattern the expanded modulesourcepath entry
* @param collector the map to put modules into
* @since 1.9.7
*/
private static void findModules(
final File root,
String pattern,
final Map<String,Collection<File>> collector) {
pattern = pattern
.replace('/', File.separatorChar)
.replace('\\', File.separatorChar);
final int startIndex = pattern.indexOf(MODULE_MARKER);
if (startIndex == -1) {
findModules(root, pattern, null, collector);
} else {
if (startIndex == 0) {
throw new BuildException("The modulesourcepath entry must be a folder.");
}
final int endIndex = startIndex + MODULE_MARKER.length();
if (pattern.charAt(startIndex - 1) != File.separatorChar) {
throw new BuildException("The module mark must be preceded by separator");
}
if (endIndex < pattern.length() && pattern.charAt(endIndex) != File.separatorChar) {
throw new BuildException("The module mark must be followed by separator");
}
if (pattern.indexOf(MODULE_MARKER, endIndex) != -1) {
throw new BuildException("The modulesourcepath entry must contain at most one module mark");
}
final String pathToModule = pattern.substring(0,startIndex);
final String pathInModule = endIndex == pattern.length() ?
null :
pattern.substring(endIndex+1); //+1 the separator
findModules(root, pathToModule, pathInModule, collector);
}
}

/**
* Finds modules in the expanded modulesourcepath entry.
* @param root the project root
* @param pathToModule the path to modules folder
* @param pathInModule the path in module to source folder
* @param collector the map to put modules into
* @since 1.9.7
*/
private static void findModules(
final File root,
final String pathToModule,
final String pathInModule,
final Map<String,Collection<File>> collector) {
final FileUtils fu = FileUtils.getFileUtils();
final File f = fu.resolveFile(root, pathToModule);
if (!f.isDirectory()) {
return;
}
final File[] modules = f.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.isDirectory();
}
});
for (File module : modules) {
final String moduleName = module.getName();
final File moduleSourceRoot = pathInModule == null ?
module :
new File(module, pathInModule);
Collection<File> moduleRoots = collector.get(moduleName);
if (moduleRoots == null) {
moduleRoots = new ArrayList<File>();
collector.put(moduleName, moduleRoots);
}
moduleRoots.add(moduleSourceRoot);
}
}

private static final byte[] PACKAGE_INFO_CLASS_HEADER = { private static final byte[] PACKAGE_INFO_CLASS_HEADER = {
(byte) 0xca, (byte) 0xfe, (byte) 0xba, (byte) 0xbe, 0x00, 0x00, 0x00, (byte) 0xca, (byte) 0xfe, (byte) 0xba, (byte) 0xbe, 0x00, 0x00, 0x00,
0x31, 0x00, 0x07, 0x07, 0x00, 0x05, 0x07, 0x00, 0x06, 0x01, 0x00, 0x0a, 0x31, 0x00, 0x07, 0x07, 0x00, 0x05, 0x07, 0x00, 0x06, 0x01, 0x00, 0x0a,


+ 64
- 0
src/main/org/apache/tools/ant/taskdefs/compilers/DefaultCompilerAdapter.java View File

@@ -73,7 +73,10 @@ public abstract class DefaultCompilerAdapter
protected Path bootclasspath; protected Path bootclasspath;
protected Path extdirs; protected Path extdirs;
protected Path compileClasspath; protected Path compileClasspath;
protected Path modulepath;
protected Path upgrademodulepath;
protected Path compileSourcepath; protected Path compileSourcepath;
protected Path moduleSourcepath;
protected Project project; protected Project project;
protected Location location; protected Location location;
protected boolean includeAntRuntime; protected boolean includeAntRuntime;
@@ -112,13 +115,20 @@ public abstract class DefaultCompilerAdapter
extdirs = attributes.getExtdirs(); extdirs = attributes.getExtdirs();
compileList = attributes.getFileList(); compileList = attributes.getFileList();
compileClasspath = attributes.getClasspath(); compileClasspath = attributes.getClasspath();
modulepath = attributes.getModulepath();
upgrademodulepath = attributes.getUpgrademodulepath();
compileSourcepath = attributes.getSourcepath(); compileSourcepath = attributes.getSourcepath();
moduleSourcepath = attributes.getModulesourcepath();
project = attributes.getProject(); project = attributes.getProject();
location = attributes.getLocation(); location = attributes.getLocation();
includeAntRuntime = attributes.getIncludeantruntime(); includeAntRuntime = attributes.getIncludeantruntime();
includeJavaRuntime = attributes.getIncludejavaruntime(); includeJavaRuntime = attributes.getIncludejavaruntime();
memoryInitialSize = attributes.getMemoryInitialSize(); memoryInitialSize = attributes.getMemoryInitialSize();
memoryMaximumSize = attributes.getMemoryMaximumSize(); memoryMaximumSize = attributes.getMemoryMaximumSize();
if (moduleSourcepath != null && src == null && compileSourcepath == null) {
//Compatibility to prevent NPE from Jikes, Jvc, Kjc
compileSourcepath = new Path(getProject());
}
} }


/** /**
@@ -182,6 +192,45 @@ public abstract class DefaultCompilerAdapter
return classpath; return classpath;
} }


/**
* Builds the modulepath.
* @return the modulepath
* @since 1.9.7
*/
protected Path getModulepath() {
final Path mp = new Path(getProject());
if (modulepath != null) {
mp.addExisting(modulepath);
}
return mp;
}

/**
* Builds the upgrademodulepath.
* @return the upgrademodulepath
* @since 1.9.7
*/
protected Path getUpgrademodulepath() {
final Path ump = new Path(getProject());
if (upgrademodulepath != null) {
ump.addExisting(upgrademodulepath);
}
return ump;
}

/**
* Builds the modulesourcepath for multi module compilation.
* @return the modulesourcepath
* @since 1.9.7
*/
protected Path getModulesourcepath() {
final Path msp = new Path(getProject());
if (moduleSourcepath != null) {
msp.add(moduleSourcepath);
}
return msp;
}

/** /**
* Get the command line arguments for the switches. * Get the command line arguments for the switches.
* @param cmd the command line * @param cmd the command line
@@ -350,6 +399,21 @@ public abstract class DefaultCompilerAdapter
setImplicitSourceSwitch(cmd, t, adjustSourceValue(t)); setImplicitSourceSwitch(cmd, t, adjustSourceValue(t));
} }
} }
final Path msp = getModulesourcepath();
if (msp.size() > 0) {
cmd.createArgument().setValue("-modulesourcepath");
cmd.createArgument().setPath(msp);
}
final Path mp = getModulepath();
if (mp.size() > 0) {
cmd.createArgument().setValue("-modulepath");
cmd.createArgument().setPath(mp);
}
final Path ump = getUpgrademodulepath();
if (ump.size() > 0) {
cmd.createArgument().setValue("-upgrademodulepath");
cmd.createArgument().setPath(ump);
}
return cmd; return cmd;
} }




+ 85
- 0
src/tests/junit/org/apache/tools/ant/taskdefs/JavacTest.java View File

@@ -18,6 +18,7 @@


package org.apache.tools.ant.taskdefs; package org.apache.tools.ant.taskdefs;


import java.io.File;
import org.apache.tools.ant.Project; import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.compilers.CompilerAdapter; import org.apache.tools.ant.taskdefs.compilers.CompilerAdapter;
import org.apache.tools.ant.taskdefs.compilers.CompilerAdapterFactory; import org.apache.tools.ant.taskdefs.compilers.CompilerAdapterFactory;
@@ -28,10 +29,13 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;


import static org.apache.tools.ant.AntAssert.assertContains; import static org.apache.tools.ant.AntAssert.assertContains;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.types.Path;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;


/** /**
* Testcase for <javac>. * Testcase for <javac>.
@@ -244,4 +248,85 @@ public class JavacTest {
javac.setTarget("1.5"); javac.setTarget("1.5");
assertEquals("1.5", javac.getTarget()); assertEquals("1.5", javac.getTarget());
} }

@Test
public void testModulesourcepathOrSrcDirRequired() {
try {
javac.checkParameters();
fail("Build exception should have been thrown - neither srcDir nor modulesourcepath");
} catch (BuildException e) {
//pass
}
}

@Test
public void testModulesourcepathAndSrcDirForbidden() {
try {
javac.checkParameters();
final Path p = new Path(project);
p.setPath("src");
javac.setSrcdir(p);
final Path mp = new Path(project);
p.setPath("modsrc");
javac.setModulesourcepath(mp);
fail("Build exception should have been thrown - neither srcDir nor modulesourcepath");
} catch (BuildException e) {
//pass
}
}

@Test
public void testModulesourcepathAndSourcepathForbidden() {
try {
javac.checkParameters();
final Path p = new Path(project);
p.setPath("src");
javac.setSourcepath(p);
final Path mp = new Path(project);
p.setPath("modsrc");
javac.setModulesourcepath(mp);
fail("Build exception should have been thrown - neither srcDir nor modulesourcepath");
} catch (BuildException e) {
//pass
}
}

@Test
public void testSrcDir() {
final Path p = new Path(project);
p.setPath("src");
javac.setSrcdir(p);
javac.checkParameters();
}

@Test
public void testModulesourcepath() {
final File tmp = new File(System.getProperty("java.io.tmpdir")); //NOI18N
final File destDir = new File(tmp, String.format("%stestMP%d",
getClass().getName(),
System.currentTimeMillis()/1000));
destDir.mkdirs();
try {
final Path p = new Path(project);
p.setPath("src");
javac.setModulesourcepath(p);
javac.setDestdir(destDir);
javac.checkParameters();
} finally {
destDir.delete();
}
}

@Test
public void testModulesourcepathRequiresDestdir() {
try {
final Path p = new Path(project);
p.setPath("src");
javac.setModulesourcepath(p);
javac.checkParameters();
fail("Build exception should have been thrown - modulesourcepath requires destdir");
} catch (BuildException e) {
//pass
}
}
} }

+ 163
- 0
src/tests/junit/org/apache/tools/ant/taskdefs/compilers/DefaultCompilerAdapterTest.java View File

@@ -18,12 +18,23 @@


package org.apache.tools.ant.taskdefs.compilers; package org.apache.tools.ant.taskdefs.compilers;


import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.apache.tools.ant.Project; import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.Javac; import org.apache.tools.ant.taskdefs.Javac;
import org.apache.tools.ant.types.Commandline; import org.apache.tools.ant.types.Commandline;
import org.junit.Test; import org.junit.Test;


import static org.apache.tools.ant.AntAssert.assertContains; import static org.apache.tools.ant.AntAssert.assertContains;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.util.FileUtils;
import org.junit.Assert;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;


public class DefaultCompilerAdapterTest { public class DefaultCompilerAdapterTest {
@@ -174,6 +185,127 @@ public class DefaultCompilerAdapterTest {
testSource(null, "javac1.9", "", "9"); testSource(null, "javac1.9", "", "9");
} }


@Test
public void testSingleModuleCompilation() throws IOException {
final File workDir = createWorkDir("testSMC");
try {
final File src = new File(workDir, "src");
src.mkdir();
final File java1 = createFile(src,"org/apache/ant/tests/J1.java");
final File java2 = createFile(src,"org/apache/ant/tests/J2.java");
final File modules = new File(workDir, "modules");
modules.mkdir();
final Project prj = new Project();
prj.setBaseDir(workDir);
final LogCapturingJavac javac = new LogCapturingJavac();
javac.setProject(prj);
final Commandline[] cmd = new Commandline[1];
final DefaultCompilerAdapter impl = new DefaultCompilerAdapter() {
@Override
public boolean execute() throws BuildException {
cmd[0] = setupModernJavacCommand();
return true;
}
};
final Path srcPath = new Path(prj);
srcPath.setLocation(src);
javac.setSrcdir(srcPath);
javac.createModulepath().setLocation(modules);
javac.setSource("9");
javac.setTarget("9");
javac.setIncludeantruntime(false);
javac.add(impl);
javac.execute();
Assert.assertNotNull(cmd[0]);
final List<String> cmdLine = Arrays.asList(cmd[0].getCommandline());
//No modulesourcepath
assertEquals(-1, cmdLine.indexOf("-modulesourcepath"));
//The -sourcepath has to be followed by src
int index = cmdLine.indexOf("-sourcepath");
Assert.assertTrue(index != -1 && index < cmdLine.size() - 1);
assertEquals(src.getAbsolutePath(), cmdLine.get(index + 1));
//The -modulepath has to be followed by modules
index = cmdLine.indexOf("-modulepath");
Assert.assertTrue(index != -1 && index < cmdLine.size() - 1);
assertEquals(modules.getAbsolutePath(), cmdLine.get(index + 1));
//J1.java & J2.java has to be in files list
final Set<String> expected = new TreeSet<String>();
Collections.addAll(expected, java1.getAbsolutePath(), java2.getAbsolutePath());
final Set<String> actual = new TreeSet<String>();
actual.addAll(cmdLine.subList(cmdLine.size() - 2, cmdLine.size()));
assertEquals(expected, actual);
} finally {
delete(workDir);
}
}

@Test
public void testMultiModuleCompilation() throws IOException {
final File workDir = createWorkDir("testMMC");
try {
final File src = new File(workDir, "src");
src.mkdir();
final File java1 = createFile(src,"main/m1/lin64/classes/org/apache/ant/tests/J1.java");
final File java2 = createFile(src,"main/m2/lin32/classes/org/apache/ant/tests/J2.java");
final File java3 = createFile(src,"main/m3/sol/classes/org/apache/ant/tests/J3.java");
final File modules = new File(workDir, "modules");
modules.mkdir();
final File build = new File(workDir, "build");
build.mkdirs();
final Project prj = new Project();
prj.setBaseDir(workDir);
final LogCapturingJavac javac = new LogCapturingJavac();
javac.setProject(prj);
final Commandline[] cmd = new Commandline[1];
final DefaultCompilerAdapter impl = new DefaultCompilerAdapter() {
@Override
public boolean execute() throws BuildException {
cmd[0] = setupModernJavacCommand();
return true;
}
};
final String moduleSrcPathStr = "src/main/*/{lin{32,64},sol}/classes";
final Path moduleSourcePath = new Path(prj);
moduleSourcePath.setPath(moduleSrcPathStr);
javac.setModulesourcepath(moduleSourcePath);
javac.createModulepath().setLocation(modules);
javac.setSource("9");
javac.setTarget("9");
javac.setDestdir(build);
javac.setIncludeantruntime(false);
javac.add(impl);
javac.execute();
Assert.assertNotNull(cmd[0]);
final List<String> cmdLine = Arrays.asList(cmd[0].getCommandline());
//No sourcepath
assertEquals(-1, cmdLine.indexOf("-sourcepath"));
//The -modulesourcepath has to be followed by the pattern
int index = cmdLine.indexOf("-modulesourcepath");
Assert.assertTrue(index != -1 && index < cmdLine.size() - 1);
String expectedModSrcPath = String.format("%s/%s",
workDir.getAbsolutePath(),
moduleSrcPathStr)
.replace('/', File.separatorChar)
.replace('\\', File.separatorChar);
assertEquals(expectedModSrcPath, cmdLine.get(index + 1));
//The -modulepath has to be followed by modules
index = cmdLine.indexOf("-modulepath");
Assert.assertTrue(index != -1 && index < cmdLine.size() - 1);
assertEquals(modules.getAbsolutePath(), cmdLine.get(index + 1));
//J1.java, J2.java & J3.java has to be in files list
final Set<String> expectedFiles = new TreeSet<String>();
Collections.addAll(expectedFiles,
java1.getAbsolutePath(),
java2.getAbsolutePath(),
java3.getAbsolutePath());
final Set<String> actualFiles = new TreeSet<String>();
actualFiles.addAll(cmdLine.subList(cmdLine.size() - 3, cmdLine.size()));
assertEquals(expectedFiles, actualFiles);
} finally {
delete(workDir);
}
}

private void commonSourceDowngrades(String javaVersion) { private void commonSourceDowngrades(String javaVersion) {
testSource("1.3", javaVersion, testSource("1.3", javaVersion,
"If you specify -target 1.1 you now must also specify" "If you specify -target 1.1 you now must also specify"
@@ -220,4 +352,35 @@ public class DefaultCompilerAdapterTest {
assertEquals(expectedSource, args[1]); assertEquals(expectedSource, args[1]);
} }
} }

private File createWorkDir(String testName) {
final File tmp = new File(System.getProperty("java.io.tmpdir")); //NOI18N
final File destDir = new File(tmp, String.format("%s%s%d",
getClass().getName(),
testName,
System.currentTimeMillis()/1000));
destDir.mkdirs();
return destDir;
}

private File createFile(File folder, String relativePath) throws IOException {
final File file = new File(
folder,
relativePath.replace('/', File.separatorChar).replace('\\', File.separatorChar));
FileUtils.getFileUtils().createNewFile(file, true);
return file;
}

private void delete(File f) {
if (f.isDirectory()) {
final File[] clds = f.listFiles();
if (clds != null) {
for (File cld : clds) {
delete(cld);
}
}
}
f.delete();
}

} }

Loading…
Cancel
Save