/* *******************************************************************
* Copyright (c) 2000-2001 Xerox Corporation.
* All rights reserved.
* This program and the accompanying materials are made available
* under the terms of the Eclipse Public License v1.0
* which accompanies this distribution and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Xerox/PARC initial implementation
* ******************************************************************/
package org.aspectj.tools.ant.taskdefs.compilers;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.Javac;
import org.apache.tools.ant.taskdefs.LogOutputStream;
import org.apache.tools.ant.taskdefs.compilers.DefaultCompilerAdapter;
import org.apache.tools.ant.types.Commandline;
import java.io.File;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* Ajc uses this as the CompilerAdapter.
*
* This task was developed by the <a href="http://aspectj.org">AspectJ Project</a>
*
* @author <a href="mailto:palm@parc.xerox.com">Jeffrey Palm</a>
* @see org.aspectj.tools.ant.taskdefs.Ajc
*/
public class Ajc extends DefaultCompilerAdapter {
/** The value of a compiler success. */
public final static int AJC_COMPILER_SUCCESS = 0;
/** The name of the compiler's main class. */
private final static String MAIN_CLASS_NAME = "org.aspectj.tools.ajc.Main";
/**
* List of arguments allowed only by javac and <b>not</b> ajc.
*/
final static List javacOnlyFlags
= finalList(new String[] { "-g:none", "-g:lines",
"-g:vars", "-g:source", "-nowarn"});
final static List javacOnlyArgs
= finalList(new String[] { "-sourcepath",
"-encoding", "-target" });
private static List finalList(String[] args) {
List result = new ArrayList();
result.addAll(Arrays.asList(args));
return Collections.unmodifiableList(result);
}
/**
* Checks the command line for arguments allowed only in AJC and
* disallowed by AJC and then calls the <code>compile()<code> method.
*
* @return true if a good compile, false otherwise.
* @throws org.apache.tools.ant.BuildException
*/
public boolean execute() throws BuildException {
attributes.log("Using AJC", Project.MSG_VERBOSE);
return compile(addAjcOptions(setupJavacCommand()));
}
/**
* Invokes the AJC compiler using reflection.
*
* @param cline the command line to pass the compiler
* @return true for a good compile (0), false otherwise
* @throws org.apache.tools.ant.BuildException
*/
private boolean compile(Commandline cline) throws BuildException {
PrintStream err = System.err;
PrintStream out = System.out;
try {
Class main = Class.forName(MAIN_CLASS_NAME);
if (main == null) {
throw new ClassNotFoundException(MAIN_CLASS_NAME);
}
PrintStream logstr =
new PrintStream(new LogOutputStream(attributes,
Project.MSG_WARN));
System.setOut(logstr);
System.setErr(logstr);
return ((Integer)main.getMethod
("compile", new Class[]{String[].class}).invoke
(main.newInstance(), new Object[]{
removeUnsupported(cline, logstr)
})).intValue() == AJC_COMPILER_SUCCESS;
} catch (Exception e) {
if (e instanceof BuildException) {
throw (BuildException)e;
} else {
throw new BuildException("Error starting AJC compiler",
e, location);
}
} finally {
System.setErr(err);
System.setOut(out);
}
}
/**
* Removes unsupported arguments from <code>cline</code>
* issuing warnings for each using <code>log</code>.
*
* @param cline the <code>org.apache.tools.ant.types.Commandline</code> from
* which the argument is removed.
* @return a new <code>java.lang.String</code> array containing all the
* supported arguments found in <code>cline</code>.
* @throws org.apache.tools.ant.BuildException
*/
private String[] removeUnsupported(Commandline cline, PrintStream log) {
if (null == log) log = System.err;
String[] args = cline.getCommandline();
List argsList = new ArrayList();
for (int i = 0; i < args.length; i++) {
String arg = args[i];
if (javacOnlyFlags.contains(arg)) {
log.println("ignored by ajc " + arg);
} else if (javacOnlyArgs.contains(arg)) {
i++;
if (i < args.length) {
arg = arg + " " + args[i];
}
log.println("ignored by ajc " + arg);
} else {
argsList.add(args[i]);
}
}
return (String[])argsList.toArray(new String[argsList.size()]);
}
/**
* Adds arguments that setupJavacCommand() doesn't pick up.
*
* @param cline <code>org.apache.tools.ant.types.Commandline</code> to
* which arguments are added.
* @throws org.apache.tools.ant.BuildException
* @see AjcCompiler#ajcOnlyArgs
* @see org.apache.tools.ant.taskdefs.compilers#DefaultCompilerAdapter.setupJavacCommand()
*/
private Commandline addAjcOptions(Commandline cline) throws BuildException {
Javac javac = getJavac();
org.aspectj.tools.ant.taskdefs.Ajc2 ajc = null;
try {
ajc = (org.aspectj.tools.ant.taskdefs.Ajc2)javac;
} catch (ClassCastException cce) {
throw new BuildException(cce+"");
}
if (ajc.getThreads() != null) {
cline.createArgument().setValue("-threads");
cline.createArgument().setValue(ajc.getThreads() + "");
}
if (ajc.getNocomments()) {
cline.createArgument().setValue("-nocomments");
}
if (ajc.getNosymbols()) {
cline.createArgument().setValue("-nosymbols");
}
if (ajc.getPreprocess()) {
cline.createArgument().setValue("-preprocess");
}
if (ajc.getWorkingdir() != null) {
cline.createArgument().setValue("-workingdir");
cline.createArgument().setFile(ajc.getWorkingdir());
}
return cline;
}
/**
* Logs the compilation parameters, adds the files to compile and logs the
* &qout;niceSourceList"
*/
protected void logAndAddFilesToCompile(Commandline cmd) {
// Same behavior as DefaultCompilerAdapter.logAndAddFilesToCompile
attributes.log("Compilation args: " + cmd.toString(), Project.MSG_VERBOSE);
StringBuffer niceSourceList = new StringBuffer("File");
if (compileList.length != 1) {
niceSourceList.append("s");
}
niceSourceList.append(" to be compiled:");
niceSourceList.append(lSep);
for (int i=0; i < compileList.length; i++) {
// DefaultCompilerAdapter only expects .java files but we must deal
// with .lst files also
File file = compileList[i];
if (file == null) continue;
String arg = file.getAbsolutePath();
String rest = "";
String name = file.getName();
// For .java files take the default behavior and add that
// file to the command line
if (name.endsWith(".java")) {
cmd.createArgument().setValue(arg);
}
niceSourceList.append(" " + arg + rest + lSep);
}
attributes.log(niceSourceList.toString(), Project.MSG_VERBOSE);
}
}