- /*
- * Copyright 2001-2004 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
- /*
- * build notes
- * -The reference CD to listen to while editing this file is
- * nap:Cream+Live+2001+CD+2
- */
-
- // place in the optional ant tasks package
- // but in its own dotnet group
-
- package org.apache.tools.ant.taskdefs.optional.dotnet;
-
- // imports
-
- import java.io.File;
- import java.util.Vector;
- import java.util.Enumeration;
- import java.util.Hashtable;
-
- import org.apache.tools.ant.BuildException;
- import org.apache.tools.ant.Project;
- import org.apache.tools.ant.types.Path;
- import org.apache.tools.ant.types.FileSet;
- import org.apache.tools.ant.types.EnumeratedAttribute;
-
-
- /**
- * Abstract superclass for dotnet compiler tasks.
- *
- * History
- * <table>
- * <tr>
- * <td>
- * 0.1
- * </td>
- * <td>
- * First creation
- * </td>
- * <td>
- * Most of the code here was copied verbatim from v0.3 of
- * Steve Loughran's CSharp optional task. Abstracted functionality
- * to allow subclassing of other dotnet compiler types.
- * </td>
- * </tr>
- *
- * </table>
- *
- *
- * @version 0.1
- */
-
- public abstract class DotnetCompile
- extends DotnetBaseMatchingTask {
-
- /**
- * list of reference classes. (pretty much a classpath equivalent)
- */
- private String references;
-
- /**
- * flag to enable automatic reference inclusion
- */
- private boolean includeDefaultReferences = true;
-
- /**
- * icon for incorporation into apps
- */
- private File win32icon;
-
- /**
- * icon for incorporation into apps
- */
- private File win32res;
-
- /**
- * flag to control action on execution trouble
- */
- private boolean failOnError;
-
- /**
- * using the path approach didn't work as it could not handle the implicit
- * execution path. Perhaps that could be extracted from the runtime and
- * then the path approach would be viable
- */
- private Path referenceFiles;
-
- /**
- * optimise flag
- */
- private boolean optimize;
-
- /**
- * a list of definitions to support;
- */
- protected Vector definitionList = new Vector();
-
- /**
- * our resources
- */
- protected Vector resources = new Vector();
-
- /**
- * executable
- */
-
- protected String executable;
-
- protected static final String REFERENCE_OPTION = "/reference:";
-
- /**
- * debug flag. Controls generation of debug information.
- */
- protected boolean debug;
-
- /**
- * warning level: 0-4, with 4 being most verbose
- */
- private int warnLevel;
-
- /**
- * main class (or null for automatic choice)
- */
- protected String mainClass;
-
- /**
- * any extra command options?
- */
- protected String extraOptions;
-
- /**
- * type of target. Should be one of exe|library|module|winexe|(null)
- * default is exe; the actual value (if not null) is fed to the command
- * line. <br>
- * See /target
- */
- protected String targetType;
-
- /**
- * utf out flag
- */
-
- protected boolean utf8output = false;
-
- /**
- * list of extra modules to refer to
- */
- protected String additionalModules;
- /**
- * filesets of references
- */
- protected Vector referenceFilesets = new Vector();
-
- /**
- * flag to set to to use @file based command cache
- */
- private boolean useResponseFile = false;
- private static final int AUTOMATIC_RESPONSE_FILE_THRESHOLD = 64;
-
- /**
- * constructor inits everything and set up the search pattern
- */
-
- public DotnetCompile() {
- clear();
- setIncludes(getFilePattern());
- }
-
- /**
- * reset all contents.
- */
- public void clear() {
- targetType = null;
- win32icon = null;
- srcDir = null;
- mainClass = null;
- warnLevel = 3;
- optimize = false;
- debug = true;
- references = null;
- failOnError = true;
- additionalModules = null;
- includeDefaultReferences = true;
- extraOptions = null;
- }
-
-
- /**
- * Semicolon separated list of DLLs to refer to.
- *
- *@param s The new References value
- */
- public void setReferences(String s) {
- references = s;
- }
-
-
- /**
- * get the reference string or null for no argument needed
- *
- *@return The References Parameter to CSC
- */
- protected String getReferencesParameter() {
- //bail on no references
- if (notEmpty(references)) {
- return REFERENCE_OPTION + references;
- } else {
- return null;
- }
- }
-
- /**
- * Path of references to include.
- * Wildcards should work.
- *
- *@param path another path to append
- */
- public void setReferenceFiles(Path path) {
- //demand create pathlist
- if (referenceFiles == null) {
- referenceFiles = new Path(this.getProject());
- }
- referenceFiles.append(path);
- }
-
- /**
- * add a new reference fileset to the compilation
- * @param reference
- */
- public void addReference(FileSet reference) {
- referenceFilesets.add(reference);
- }
-
-
-
- /**
- * turn the path list into a list of files and a /references argument
- *
- *@return null or a string of references.
- */
- protected String getReferenceFilesParameter() {
- //bail on no references
- if (references == null) {
- return null;
- }
- //iterate through the ref list & generate an entry for each
- //or just rely on the fact that the toString operator does this, but
- //noting that the separator is ';' on windows, ':' on unix
- String refpath = references.toString();
-
- //bail on no references listed
- if (refpath.length() == 0) {
- return null;
- }
-
- StringBuffer s = new StringBuffer(REFERENCE_OPTION);
- s.append(refpath);
- return new String(s);
- }
-
-
- /**
- * If true, automatically includes the common assemblies
- * in dotnet, and tells the compiler to link in mscore.dll.
- *
- * set the automatic reference inclusion flag on or off this flag controls
- * the /nostdlib option in CSC
- *
- *@param f on/off flag
- */
- public void setIncludeDefaultReferences(boolean f) {
- includeDefaultReferences = f;
- }
-
-
- /**
- * query automatic reference inclusion flag
- *
- *@return true if flag is turned on
- */
- public boolean getIncludeDefaultReferences() {
- return includeDefaultReferences;
- }
-
-
- /**
- * get the include default references flag or null for no argument needed
- *
- *@return The Parameter to CSC
- */
- protected String getIncludeDefaultReferencesParameter() {
- return "/nostdlib" + (includeDefaultReferences ? "-" : "+");
- }
-
-
-
- /**
- * If true, enables optimization flag.
- *
- *@param f on/off flag
- */
- public void setOptimize(boolean f) {
- optimize = f;
- }
-
-
- /**
- * query the optimise flag
- *
- *@return true if optimise is turned on
- */
- public boolean getOptimize() {
- return optimize;
- }
-
-
- /**
- * get the optimise flag or null for no argument needed
- *
- *@return The Optimize Parameter to CSC
- */
- protected String getOptimizeParameter() {
- return "/optimize" + (optimize ? "+" : "-");
- }
-
-
- /**
- * set the debug flag on or off.
- *
- *@param f on/off flag
- */
- public void setDebug(boolean f) {
- debug = f;
- }
-
-
- /**
- * query the debug flag
- *
- *@return true if debug is turned on
- */
- public boolean getDebug() {
- return debug;
- }
-
-
- /**
- * get the debug switch argument
- *
- *@return The Debug Parameter to CSC
- */
- protected String getDebugParameter() {
- return "/debug" + (debug ? "+" : "-");
- }
-
-
- /**
- * Level of warning currently between 1 and 4
- * with 4 being the strictest.
- *
- *@param warnLevel warn level -see .net docs for valid range (probably
- * 0-4)
- */
- public void setWarnLevel(int warnLevel) {
- this.warnLevel = warnLevel;
- }
-
-
- /**
- * query warn level
- *
- *@return current value
- */
- public int getWarnLevel() {
- return warnLevel;
- }
-
-
- /**
- * get the warn level switch
- *
- *@return The WarnLevel Parameter to CSC
- */
- protected String getWarnLevelParameter() {
- return "/warn:" + warnLevel;
- }
-
-
- /**
- * Sets the name of main class for executables.
- *
- *@param mainClass The new MainClass value
- */
- public void setMainClass(String mainClass) {
- this.mainClass = mainClass;
- }
-
-
- /**
- * Gets the MainClass attribute
- *
- *@return The MainClass value
- */
- public String getMainClass() {
- return this.mainClass;
- }
-
-
- /**
- * get the /main argument or null for no argument needed
- *
- *@return The MainClass Parameter to CSC
- */
- protected String getMainClassParameter() {
- if (mainClass != null && mainClass.length() != 0) {
- return "/main:" + mainClass;
- } else {
- return null;
- }
- }
-
-
- /**
- * Any extra options which are not explicitly supported
- * by this task.
- *
- *@param extraOptions The new ExtraOptions value
- */
- public void setExtraOptions(String extraOptions) {
- this.extraOptions = extraOptions;
- }
-
-
- /**
- * Gets the ExtraOptions attribute
- *
- *@return The ExtraOptions value
- */
- public String getExtraOptions() {
- return this.extraOptions;
- }
-
-
- /**
- * get any extra options or null for no argument needed
- *
- *@return The ExtraOptions Parameter to CSC
- */
- protected String getExtraOptionsParameter() {
- if (extraOptions != null && extraOptions.length() != 0) {
- return extraOptions;
- } else {
- return null;
- }
- }
-
-
- /**
- * Set the destination directory of files to be compiled.
- *
- *@param dirName The new DestDir value
- */
- public void setDestDir(File dirName) {
- log("DestDir currently unused", Project.MSG_WARN);
- }
-
-
- /**
- * set the target type to one of exe|library|module|winexe
- * @param targetType
- */
- public void setTargetType(TargetTypes targetType) {
- this.targetType = targetType.getValue();
- }
- /**
- * Set the type of target.
- *
- *@param ttype The new TargetType value
- *@exception BuildException if target is not one of
- * exe|library|module|winexe
- */
- public void setTargetType(String ttype)
- throws BuildException {
- ttype = ttype.toLowerCase();
- if (ttype.equals("exe") || ttype.equals("library")
- || ttype.equals("module") || ttype.equals("winexe")) {
- targetType = ttype;
- } else {
- throw new BuildException("targetType " + ttype
- + " is not one of 'exe', 'module', 'winexe' or 'library'");
- }
- }
-
-
- /**
- * Gets the TargetType attribute
- *
- *@return The TargetType value
- */
- public String getTargetType() {
- return targetType;
- }
-
-
- /**
- * get the argument or null for no argument needed
- *
- *@return The TargetType Parameter to CSC
- */
- protected String getTargetTypeParameter() {
- if (notEmpty(targetType)) {
- return "/target:" + targetType;
- } else {
- return null;
- }
- }
-
-
- /**
- * Set the filename of icon to include.
- *
- *@param fileName path to the file. Can be relative, absolute, whatever.
- */
- public void setWin32Icon(File fileName) {
- win32icon = fileName;
- }
-
-
- /**
- * get the argument or null for no argument needed
- *
- *@return The Win32Icon Parameter to CSC
- */
- protected String getWin32IconParameter() {
- if (win32icon != null) {
- return "/win32icon:" + win32icon.toString();
- } else {
- return null;
- }
- }
-
-
- /**
- * Sets the filename of a win32 resource (.RES) file to include.
- * This is not a .NET resource, but what Windows is used to.
- *
- *@param fileName path to the file. Can be relative, absolute, whatever.
- */
- public void setWin32Res(File fileName) {
- win32res = fileName;
- }
-
- /**
- * Gets the file of the win32 .res file to include.
- * @return path to the file.
- */
- public File getWin32Res() {
- return win32res;
- }
-
-
- /**
- * get the argument or null for no argument needed
- *
- *@return The Win32Res Parameter to CSC
- */
- protected String getWin32ResParameter() {
- if (win32res != null) {
- return "/win32res:" + win32res.toString();
- } else {
- return null;
- }
- }
-
-
- /**
- * If true, require all compiler output to be in UTF8 format.
- *
- *@param enabled The new utf8Output value
- */
- public void setUtf8Output(boolean enabled) {
- utf8output = enabled;
- }
-
-
- /**
- * Gets the utf8OutpuParameter attribute of the CSharp object
- *
- *@return The utf8OutpuParameter value
- */
- protected String getUtf8OutputParameter() {
- return utf8output ? "/utf8output" : null;
- }
-
-
- /**
- * add a define to the list of definitions
- * @param define
- */
- public void addDefine(DotnetDefine define) {
- definitionList.addElement(define);
- }
-
-
- /**
- * get a list of definitions or null
- * @return a string beginning /D: or null for no definitions
- */
- protected String getDefinitionsParameter() throws BuildException {
- StringBuffer defines = new StringBuffer();
- Enumeration defEnum = definitionList.elements();
- boolean firstDefinition = true;
- while (defEnum.hasMoreElements()) {
- //loop through all definitions
- DotnetDefine define = (DotnetDefine) defEnum.nextElement();
- if (define.isSet(this)) {
- //add those that are set, and a delimiter
- if (!firstDefinition) {
- defines.append(getDefinitionsDelimiter());
- }
- defines.append(define.getValue(this));
- firstDefinition = false;
- }
- }
- if (defines.length() == 0) {
- return null;
- } else {
- return "/d:" + defines;
- }
- }
-
-
- /**
- * Semicolon separated list of modules to refer to.
- *
- *@param params The new additionalModules value
- */
- public void setAdditionalModules(String params) {
- additionalModules = params;
- }
-
-
- /**
- * get the argument or null for no argument needed
- *
- *@return The AdditionalModules Parameter to CSC
- */
- protected String getAdditionalModulesParameter() {
- if (notEmpty(additionalModules)) {
- return "/addmodule:" + additionalModules;
- } else {
- return null;
- }
- }
-
-
- /**
- * get the argument or null for no argument needed
- *
- *@return The OutputFile Parameter to CSC
- */
- protected String getDestFileParameter() {
- if (outputFile != null) {
- return "/out:" + outputFile.toString();
- } else {
- return null;
- }
- }
-
-
- /**
- * If true, fail on compilation errors.
- *
- *@param b The new FailOnError value
- */
- public void setFailOnError(boolean b) {
- failOnError = b;
- }
-
-
- /**
- * query fail on error flag
- *
- *@return The FailFailOnError value
- */
- public boolean getFailOnError() {
- return failOnError;
- }
-
- /**
- * link or embed a resource
- * @param resource
- */
- public void addResource(DotnetResource resource) {
- resources.add(resource);
- }
-
- /**
- * This method gets the name of the executable.
- * @return the name of the executable
- */
- protected String getExecutable() {
- return executable;
- }
-
- /**
- * set the name of the program, overriding the defaults.
- * Can be used to set the full path to a program, or to switch
- * to an alternate implementation of the command, such as the Mono or Rotor
- * versions -provided they use the same command line arguments as the
- * .NET framework edition
- * @param executable
- */
- public void setExecutable(String executable) {
- this.executable = executable;
- }
-
- /**
- * test for a string containing something useful
- *
- *@param s string in
- *@return true if the argument is not null or empty
- */
- protected boolean notEmpty(String s) {
- return s != null && s.length() != 0;
- }
-
- /**
- * validation code
- * @throws BuildException if validation failed
- */
- protected void validate()
- throws BuildException {
- if (outputFile != null && outputFile.isDirectory()) {
- throw new BuildException("destFile cannot be a directory");
- }
- if (getExecutable() == null) {
- throw new BuildException("There is no executable defined for this task");
- }
- }
-
- /**
- * Get the pattern for files to compile.
- * @return The compilation file pattern.
- */
- public String getFilePattern() {
- return "**/*." + getFileExtension();
- }
-
- /**
- * getter for flag
- * @return The flag indicating whether the compilation is using a response file.
- */
- public boolean isUseResponseFile() {
- return useResponseFile;
- }
-
- /**
- * Flag to turn on response file use; default=false.
- * When set the command params are saved to a file and
- * this is passed in with @file. The task automatically switches
- * to this mode with big commands; this option is here for
- * testing and emergencies
- * @param useResponseFile
- */
- public void setUseResponseFile(boolean useResponseFile) {
- this.useResponseFile = useResponseFile;
- }
-
- /**
- * do the work by building the command line and then calling it
- *
- *@throws BuildException if validation or execution failed
- */
- public void execute()
- throws BuildException {
- validate();
- NetCommand command = createNetCommand();
- //set up response file options
- command.setAutomaticResponseFileThreshold(AUTOMATIC_RESPONSE_FILE_THRESHOLD);
- command.setUseResponseFile(useResponseFile);
- //fill in args
- fillInSharedParameters(command);
- addResources(command);
- addCompilerSpecificOptions(command);
- int referencesOutOfDate
- = addReferenceFilesets(command, getOutputFileTimestamp());
- //if the refs are out of date, force a build.
- boolean forceBuild = referencesOutOfDate > 0;
- addFilesAndExecute(command, forceBuild);
-
- }
-
- /**
- * Get the delimiter that the compiler uses between references.
- * For example, c# will return ";"; VB.NET will return ","
- * @return The string delimiter for the reference string.
- */
- public abstract String getReferenceDelimiter();
-
- /**
- * Get the extension of filenames to compile.
- * @return The string extension of files to compile.
- */
- public abstract String getFileExtension();
-
-
- /**
- * fill in the common information
- * @param command
- */
- protected void fillInSharedParameters(NetCommand command) {
- command.setFailOnError(getFailOnError());
- //fill in args
- command.addArgument("/nologo");
- command.addArgument(getAdditionalModulesParameter());
- command.addArgument(getDebugParameter());
- command.addArgument(getDefinitionsParameter());
- command.addArgument(getExtraOptionsParameter());
- command.addArgument(getMainClassParameter());
- command.addArgument(getOptimizeParameter());
- command.addArgument(getDestFileParameter());
- command.addArgument(getReferencesParameter());
- command.addArgument(getTargetTypeParameter());
- command.addArgument(getUtf8OutputParameter());
- command.addArgument(getWin32IconParameter());
- command.addArgument(getWin32ResParameter());
- }
-
- /**
- * for every resource declared, we get the (language specific)
- * resource setting
- */
- protected void addResources(NetCommand command) {
- Enumeration e = resources.elements();
- while (e.hasMoreElements()) {
- DotnetResource resource = (DotnetResource) e.nextElement();
- command.addArgument(createResourceParameter(resource));
- }
- }
-
- /**
- * from a resource, get the
- * @param resource
- * @return a string containing the resource param, or a null string
- * to conditionally exclude a resource.
- */
- protected abstract String createResourceParameter(DotnetResource resource);
-
-
- /**
- * run through the list of reference files and add them to the command
- * @param outputTimestamp timestamp to compare against
- * @return number of files out of date
- */
-
- protected int addReferenceFilesets(NetCommand command, long outputTimestamp) {
- int filesOutOfDate = 0;
- Hashtable filesToBuild = new Hashtable();
- for (int i = 0; i < referenceFilesets.size(); i++) {
- FileSet fs = (FileSet) referenceFilesets.elementAt(i);
- filesOutOfDate += command.scanOneFileset(
- fs.getDirectoryScanner(getProject()),
- filesToBuild,
- outputTimestamp);
- }
- //bail out early if there were no files
- if (filesToBuild.size() == 0) {
- return 0;
- }
- StringBuffer referenceList = new StringBuffer(REFERENCE_OPTION);
- //now scan the hashtable and add the files
- Enumeration files = filesToBuild.elements();
- boolean firstEntry = true;
- while (files.hasMoreElements()) {
- File file = (File) files.nextElement();
- if (isFileManagedBinary(file)) {
- if (!firstEntry) {
- referenceList.append(getReferenceDelimiter());
- }
- referenceList.append(file.toString());
- firstEntry = false;
- } else {
- log("ignoring " + file + " as it is not a managed executable",
- Project.MSG_VERBOSE);
- }
-
- }
- //add it all to an argument
- command.addArgument(referenceList.toString());
- return filesOutOfDate;
- }
-
- /**
- * create our helper command
- * @return a command prefilled with the exe name and task name
- */
- protected NetCommand createNetCommand() {
- NetCommand command = new NetCommand(this, getTaskName(), getExecutable());
- return command;
- }
-
- /**
- * add any compiler specifics
- * @param command
- */
- protected abstract void addCompilerSpecificOptions(NetCommand command);
-
- /**
- * override point for delimiting definitions.
- * @return The definitions limiter, i.e., ";"
- */
- public String getDefinitionsDelimiter() {
- return ";";
- }
-
-
- /**
- * test for a file being managed or not
- * @return true if we think this is a managed executable, and thus OK
- * for linking
- * @todo look at the PE header of the exe and see if it is managed or not.
- */
- protected static boolean isFileManagedBinary(File file) {
- String filename = file.toString().toLowerCase();
- return filename.endsWith(".exe") || filename.endsWith(".dll")
- || filename.endsWith(".netmodule");
- }
-
- /**
- * Target types to build.
- * valid build types are exe|library|module|winexe
- */
- public static class TargetTypes extends EnumeratedAttribute {
- public String[] getValues() {
- return new String[] {
- "exe",
- "library",
- "module",
- "winexe"
- };
- }
- }
-
-
- }
-
-