----- Original Message -----
From: "Sam Ruby/Raleigh/IBM" <[EMAIL PROTECTED]>
To: <[EMAIL PROTECTED]>
Sent: Thursday, October 26, 2000 10:35
Subject: Re: Role of scripts [was Re: increment task]
> Steve Loughran wrote:
> >
> > As a case in point I am partway through coding up a CSC task to
> > build C# code from inside ant. I suspect that many people would
> > (perhaps quite rightly) feel that that should not be part of the
> > official optional task list on the basis it aids and abets the
> > complete antithesis of the Java world. But shouldt stop that
> > those of us doing .net work dont to use ant, and the appropriate
> > tasks to make it possible.
>
> Cool! Let me know when it is ready! I've been doing some C# work lately,
> and I miss ant...
>
attached: one (very rough) Csharp task, plus example use case (add your own
.cs files)
I dont think the task is ready for commitment yet, as it is still way too
raw. It lacks
-rigorous testing
-apache style rules
-documentation
All the task does is build up the CSC.exe command line from the settings in
build.xml and the usual file include patterns.
One area where it is broken is in the references section. CSC needs a
reference list for includes, roughly like a classpath. But %PATH% is sort of
on the include list already, so you should be able to do
/reference:system.dll and have that dll included as it is on the execute
path.
But add references="System.dll" in my task and it spits out
"/reference:[path to here]/system.dll, which causes the compiler to bail
out. Someone needs to fix that. Over to you, Mr Ruby.
-Steve
/* -*-Java-*-
*******************************************************************
*
* File: Csharp.java
* RCS: $Header: /net/csharp_task/src/org/apache/tools/ant/taskdefs/optional/Csharp.java 1 00-10-19 12:58 Slo $
* Author: Steve Loughran
* Created: July 21, 2000
* Modified: $Modtime: 00-10-19 12:56 $
* Language: Java
* Status: Experimental
*
*********************************************************************/
/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact [EMAIL PROTECTED]
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
/* build notes
-The reference CD to listen to while editing this file is
Underworld Everything, Everything
-variable naming policy from Fowler's refactoring book.
*/
// ====================================================================
// place in the optional ant tasks package
// in case we ever become an official ant task
// ====================================================================
package org.apache.tools.ant.taskdefs.optional;
// ====================================================================
// imports
// ====================================================================
import org.apache.tools.ant.*;
import org.apache.tools.ant.taskdefs.*;
import org.apache.tools.ant.types.*;
import java.io.*;
import java.util.*;
import java.text.*;
// ====================================================================
/**
Ant Task to compile down a CSC file.
This task is derived from the Execute task, as it spawns the CSC.EXE process
The task will only work on win2K
<p>
The first pass is just a proof of concept; enough to test.
<p>
History
<Table>
<tr><td>0.1</td>
<td> "I can't believe it's so rudimentary"</td>
<td> First pass; minimal attribute support; rebuild test broken
</tr>
</table>
@author Steve Loughran [EMAIL PROTECTED]
*/
// ====================================================================
public class Csharp
extends org.apache.tools.ant.taskdefs.MatchingTask
{
//=============================================================================
/** constructor inits everything and set up the search pattern
*/
public Csharp ()
{
Clear();
setIncludes(csc_file_pattern);
}
//-----------------------------------------------------------------------------
/** name of the executable. the .exe suffix is deliberately not included
* in anticipation of the unix version
*/
protected static final String csc_exe_name="csc";
/** what is the file extension we search on?
*/
protected static final String csc_file_ext="cs";
/** and now derive the search pattern from the extension
*/
protected static final String csc_file_pattern="*."+csc_file_ext;
//=============================================================================
/** list of reference classes. (pretty much a classpath equivalent)
*/
protected Path _references;
/**
* Set the classpath to be used for this compilation.
*/
public void setReferences(Path s)
{
_references.append(s);
}
/** get the argument or null for no argument needed
*/
protected String getReferencesParameter()
{
//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:");
s.append(refpath);
return new String(s);
}
//=============================================================================
/* optimise flag
*/
protected boolean _optimize;
/** set the optimise flag on or off
@param 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 argument or null for no argument needed
*/
protected String getOptimizeParameter()
{
return "/optimise"+(_optimize?"+":"-");
}
//=============================================================================
/** incremental build flag */
protected boolean _incremental;
/** set the incremental compilation flag on or off
[EMAIL PROTECTED] on/off flag
*/
public void setIncremental(boolean f)
{
_incremental=f;
}
/** query the incrementalflag
* @return true iff incremental compilation is turned on
*/
public boolean getIncremental()
{
return _incremental;
}
/** get the argument or null for no argument needed
*/
protected String getIncrementalParameter()
{
return "/incremental"+(_incremental?"+":"-");
}
//=============================================================================
/** forced build flag . This is really something used by the ant task to say
* 'always rebuild'.
*/
protected boolean _debug;
/** set the forced build flag on or off
* @param on/off flag
*/
public void setDebug(boolean f)
{this._debug=f;}
/** query the forced build flag
* @return true if forced build is turned on
*/
public boolean getDebug()
{
return _debug;
}
/** get the argument or null for no argument needed
*/
protected String getDebugParameter()
{
return "/debug"+(_debug?"+":"-");
}
//=============================================================================
/** output XML documentation flag
*/
protected File _docFile;
/** file for generated XML documentation
* @param output file
*/
public void setDocFile(String f)
{
_docFile=project.resolveFile(f);
}
/** get the argument or null for no argument needed
*/
protected String getDocFileParameter()
{
if (_docFile!=null)
return "/doc:"+_docFile.toString();
else
return null;
}
//=============================================================================
/** warning level: 0-4, with 4 being most verbose
*/
private int _warnLevel;
/** set warn level (no range checking)
* @param 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 argument or null for no argument needed
*/
protected String getWarnLevelParameter()
{
return "/warn:"+_warnLevel;
}
//=============================================================================
/** enable unsafe code
*/
protected boolean _unsafe;
public void setUnsafe(boolean unsafe)
{this._unsafe=unsafe;}
public boolean getUnsafe()
{return this._unsafe;}
/** get the argument or null for no argument needed
*/
protected String getUnsafeParameter()
{
return _unsafe?"/unsafe":null;
}
//=============================================================================
/** main class (or null for automatic choice) */
protected String _mainClass;
public void setMainClass(String mainClass)
{this._mainClass=mainClass;}
public String getMainClass()
{return this._mainClass;}
/** get the argument or null for no argument needed
*/
protected String getMainClassParameter()
{
if (_mainClass!=null)
return "/main:"+_mainClass;
else
return null;
}
//=============================================================================
// source directory upon which the pattern is applied
private File _srcDir;
/**
* Set the source dir to find the files to be compiled
*/
public void setSrcDir(String srcDirName)
{
_srcDir = project.resolveFile(srcDirName);
}
//=============================================================================
/** destination directory (null means use the source directory
*/
private File _destDir;
/**
* Set the source dir to find the files to be compiled
*/
public void setDestDir(String dirName)
{
_destDir = project.resolveFile(dirName);
}
//=============================================================================
/** 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;
/** define the target
* param target.
* @throws BuildException if target is not one of exe|library|module|winexe
*/
public void setTargetType(String targetType)
throws BuildException
{
targetType=targetType.toLowerCase();
if(targetType.equals("exe") || targetType.equals("library") ||
targetType.equals("module") ||targetType.equals("winexe") ) {
_targetType=targetType;
}
else
throw new BuildException("targetType " +targetType+" is not a valid type");
}
public String getTargetType()
{return _targetType;}
/** get the argument or null for no argument needed
*/
protected String getTargetTypeParameter()
{
if (_targetType!=null)
return "/target:"+_targetType;
else
return null;
}
//=============================================================================
/* icon for incorporation into apps
*/
protected File _win32icon;
/**
* Set the win32 icon
* @param path to the file. Can be relative, absolute, whatever -ant will work it out.
*/
public void setWin32Icon(String fileName)
{
_win32icon = project.resolveFile(fileName);
}
/** get the argument or null for no argument needed
*/
protected String getWin32IconParameter()
{
if (_win32icon!=null)
return "/win32icon:"+_win32icon.toString();
else
return null;
}
//=============================================================================
/** reset all contents.
*/
public void Clear()
{
_targetType=null;
_win32icon=null;
_srcDir=null;
_destDir=null;
_mainClass=null;
_unsafe=false;
_warnLevel=3;
_docFile = null;
_incremental=true;
_optimize=false;
_debug=true;
_references=new Path(this.project);
}
//=============================================================================
/** verbose text log
* @param string to add to log iff verbose is defined for the build
*/
protected void logVerbose(String msg)
{
project.log(msg,Project.MSG_VERBOSE);
}
//=============================================================================
/** error text log
* @param string to add to the error log
*/
protected void logError(String msg)
{
project.log(msg,Project.MSG_ERR);
}
//=============================================================================
/*
* add an argument to a command line; do nothing if the arg is null or empty string
* @param commandline to extend
* @param next arg
* @returns param1 again for chaining
*/
protected Commandline addArgument(Commandline command,String argument)
{
if(argument!=null && argument.length()!=0) {
command.createArgument().setValue(argument);
}
return command;
}
//=============================================================================
/** do the work by building the command line and then calling it
*/
public void execute()
throws BuildException
{
if (_srcDir == null)
_srcDir=project.resolveFile(".");
Commandline command=new Commandline();
command.setExecutable(csc_exe_name);
addArgument(command,getTargetTypeParameter());
addArgument(command,getMainClassParameter());
addArgument(command,getWin32IconParameter());
addArgument(command,getUnsafeParameter());
addArgument(command,getWarnLevelParameter());
addArgument(command,getDocFileParameter());
addArgument(command,getIncrementalParameter());
addArgument(command,getDebugParameter());
addArgument(command,getReferencesParameter());
//get dependencies list.
DirectoryScanner scanner = super.getDirectoryScanner(_srcDir);
String[] dependencies = scanner.getIncludedFiles();
log("compiling "+dependencies.length+" files");
String baseDir=scanner.getBasedir().toString();
for (int i = 0;i < dependencies.length; ++i) {
String cscFile=dependencies[i];
cscFile=baseDir+File.separator+cscFile;
addArgument(command,cscFile);
}
Execute exe=prepareExec();
runExec(exe,command,true);
} // execute
//=============================================================================
/**
* Create an Execute instance with the correct working directory set.
*/
protected Execute prepareExec() throws BuildException
{
// default directory to the project's base directory
File dir = project.getBaseDir();
ExecuteStreamHandler handler=new LogStreamHandler(this,
Project.MSG_INFO, Project.MSG_WARN);
Execute exe = new Execute(handler, null);
exe.setAntRun(project);
exe.setWorkingDirectory(dir);
/* do nothing with env variables
String[] environment = env.getVariables();
exe.setEnvironment(environment);
*/
return exe;
}
//=============================================================================
/**
* Run the command using the given Execute instance.
* @param exe instance
* @param command line
* until it is clear what errors CSC returns, it is not obvious what
* the action on a non zero return code should be.
*/
protected void runExec(Execute exe, Commandline cmdl , boolean failOnError)
throws BuildException {
int err = -1; // assume the worst
try {
//REVISIT: always print the string in debug mode
if(_debug) {
log(cmdl.toString());
}
logVerbose(cmdl.toString());
exe.setCommandline(cmdl.getCommandline());
err = exe.execute();
if (err != 0) {
if (failOnError) {
throw new BuildException("CSC returned: "+err, location);
} else {
log("CSC Result: " + err, Project.MSG_ERR);
}
}
} catch (IOException e) {
throw new BuildException("Csharp failed: " + e, e, location);
}
}
} //end class
<?xml version="1.0"?>
<!-- ***************************************************
esidl Ant file
$Header: /java/DavClient/build.xml 3 00-08-10 16:26 Slo $
***************************************************
-->
<project name="test" default="main" basedir=".">
<!-- having properties inside a target is moot, as they are global,
not mutable, at least in Ant1.1 and later.
But keeping them here is convenient
-->
<target name="init">
<taskdef name="csc" classname="org.apache.tools.ant.taskdefs.optional.Csharp"/>
</target>
<target name="main" depends="test">
</target>
<target name="test">
<!-- quick structure -->
<antstructure output="project.dtd" />
<csc
optimize="false"
debug="true"
docFile="documentation.xml"
warnLevel="4"
unsafe="false"
targetType="winexe"
win32Icon="icon.ico"
incremental="true"
references="System.dll"
/>
</target>
</project>