You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ant.apache.org by Phil Hanna <au...@philhanna.com> on 2000/05/14 03:52:26 UTC

Fixes for org.apache.tools.ant.taskdefs.Javac and org.apache.tools.ant.Project

Appended to this note are fixes for two related Ant bugs:

BUG 1 - Project.translatePath()

1. org.apache.tools.ant.taskdefs.Javac uses Project.translatePath() to convert various paths to native format (i.e., Unix to Win32, etc.).  But Project.translatePath() does not always correctly handle Win32 paths with forward slashes, converting for example

   d:/jdk1.3/jre/lib/ext

to

   d;\jdk1.3\jre\lib\ext

which is interpreted as two directories instead of one.

Here is what happens (I added the DEBUG messages to the source code):

--- CUT HERE ---

D:\jspcr\docs>ant
Buildfile: build.xml
Project base dir set to: D:\jspcr\docs
DEBUG: Javac: setExtdirs: entry
DEBUG: Javac: setExtdirs: extdirs=d:/jdk1.3/jre/lib/ext
DEBUG: Javac: setExtdirs: after project.translatePath()
DEBUG: Javac: setExtdirs: this.extdirs=d;\jdk1.3\jre\lib\ext
DEBUG: Javac: setExtdirs: exit
Executing Target: init
Executing Target: compile
Compiling 1 source files to D:\jspcr\docs
DEBUG: addExtdirsToClasspath: entry
DEBUG: addExtdirsToClasspath: classpath=D:\jspcr\docs;D:\ant\lib\ant.jar;D:\jdk1.3\lib\tools.jar
DEBUG: addExtdirsToClasspath: extdirs=d;\jdk1.3\jre\lib\ext
DEBUG: addExtdirsToClasspath: dir=D:\jspcr\docs\d
Exception in thread "main" java.lang.NullPointerException
        at org.apache.tools.ant.taskdefs.Javac.addExtdirsToClasspath(Javac.java:605)
        at org.apache.tools.ant.taskdefs.Javac.doJikesCompile(Javac.java:466)
        at org.apache.tools.ant.taskdefs.Javac.execute(Javac.java:227)
        at org.apache.tools.ant.Target.execute(Target.java:122)
        at org.apache.tools.ant.Project.runTarget(Project.java:675)
        at org.apache.tools.ant.Project.executeTarget(Project.java:422)
        at org.apache.tools.ant.Main.runBuild(Main.java:248)
        at org.apache.tools.ant.Main.main(Main.java:191)

D:\jspcr\docs>

--- END CUT ---

Here is the build.xml file:

--- CUT HERE ---

<project default="compile" basedir="." >

   <target name="init">
      <tstamp/>
      <property name="java_home" value="d:/jdk1.3"/>
      <property name="extdirs" value="${java_home}/jre/lib/ext" />
      <property name="build.compiler" value="jikes" />
   </target>

   <target name="compile" depends="init">
      <javac srcdir="." destdir="." extdirs="${extdirs}" />
   </target>

</project>

--- END CUT ---

Unfortunately, the translatePath() problem is not always possible to solve because the Unix and Win32 path formats do not map completely.  For example, what should we make of c:/test?  It could be a single Win32 directory or two Unix directories.  (Forward slashes should be treated as valid, even on Win32).

The best we can do is employ a heuristic to determine what platform the string is coded for, and then apply the following decision table:

String      Runtime
Platform    Platform    Action
--------    --------    ------
Unix        Unix        No change required

Unix        Win32       Change ":" to ";", "/" to "\\"

Win32       Unix        Remove "<driveletter>:",
                        then change ";" to ":", "\\" to "/"

Win32       Win32       No change required

A string is considered to be a Win32 path if

1. It contains any ";" characters, OR
2. It contains any "\\" characters, OR
3. It begins with a letter followed by a ":"

I fiddled with Project.translatePath() but ended up writing a replacement.  Here is the patch:

--- CUT HERE ---
--- Project.java Wed May 10 16:20:34 2000
+++ Project.java.new Sat May 13 15:15:03 2000
@@ -482,43 +482,127 @@
     }
 
     /**
-        Translate a path into its native (platform specific)
-        path. This should be extremely fast, code is
-        borrowed from ECS project.
-        <p>
-        All it does is translate the : into ; and / into \
-        if needed. In other words, it isn't perfect.
-
-        @returns translated string or empty string if to_process is null or empty
-        @author Jon S. Stevens <a href="mailto:jon@clearink.com">jon@clearink.com</a>
+    * Translates a path into its native (platform specific)
+    * path.
+    * <P>
+    * This is not always possible because the
+    * Unix and Win32 path formats do not map completely.
+    * For example, what should we make of <CODE>c:/test</CODE>?
+    * It could be a single Win32 directory or two Unix
+    * directories.  (Forward slashes should be treated
+    * as valid, even on Win32).
+    * <P>
+    * The best we can do is employ a heuristic to determine
+    * what platform the string is coded for, and then apply
+    * the following decision table:
+    * <PRE>
+    * String      Runtime
+    * Platform    Platform    Action
+    * --------    --------    ------
+    * Unix        Unix        No change required
+    *
+    * Unix        Win32       Change ":" to ";", "/" to "\\"
+    *
+    * Win32       Unix        Remove "&lt;driveletter&gt;:",
+    *                         then change ";" to ":", "\\" to "/"
+    *
+    * Win32       Win32       No change required
+    * </PRE>
+    * A string is considered to be a Win32 path if
+    * <OL>
+    * <LI>It contains any ";" characters, <B>OR</B>
+    * <LI>It contains any "\\" characters, <B>OR</B>
+    * <LI>It begins with a letter followed by a ":"
+    * </OL>
+    *
+    * @param pathString a path string
+    * @return translated string
+    *      or empty string if pathString is null or empty
     */
-    public String translatePath(String to_process) {
-        if ( to_process == null || to_process.length() == 0 ) return "";
+    public String translatePath(String pathString) {
+
+        //  Simple cases first
+
+        if (pathString == null)
+            return "";
+        int length = pathString.length();
+        if (length == 0)
+            return null;
+
+        //  The string to process is considered a Win32 path if
+        //  it contains any semicolons, backslashes, or if it
+        //  begins with a drive letter + ":"
+
+        boolean string_is_win32 =
+            (pathString.indexOf(";") != -1) ||
+            (pathString.indexOf("\\") != -1) ||
+            ((length > 1)
+                && (Character.isLetter(pathString.charAt(0)))
+                && (pathString.charAt(1) == ':'));
+
+        //  The runtime platform is considered to be Win32
+        //  if the path separator is ";"
+
+        boolean platform_is_win32 =
+            System.getProperty("path.separator").equals(";");
+
+        //  No change is required if the platforms are the same
+
+        if (string_is_win32 == platform_is_win32)
+            return pathString;
+
+        //  Win32 to Unix translation:
 
-        StringBuffer bs = new StringBuffer(to_process.length() + 50);
-        StringCharacterIterator sci = new StringCharacterIterator(to_process);
-        String path = System.getProperty("path.separator");
-        String file = System.getProperty("file.separator");
-        String tmp = null;
-        for (char c = sci.first(); c != CharacterIterator.DONE; c = sci.next()) {
-            tmp = String.valueOf(c);
-
-            if (tmp.equals(":")) {
-                // could be a DOS drive or a Unix path separator...
-                // if followed by a backslash, assume it is a drive
-                c = sci.next();
-                tmp = String.valueOf(c);
-                bs.append( tmp.equals("\\") ? ":" : path );
-                if (c == CharacterIterator.DONE) break;
+        if (string_is_win32) {
+
+            //  Ugly problem: There is no completely correct
+            //  way to translate drive letters, since Unix
+            //  does not use them.  Moreover, if an absolute
+            //  path is intended, it probably does not make
+            //  sense to convert it to "/" - it is more likely
+            //  to be "~/" or something.
+            //
+            //  Solution: Remove drive letters and the colons
+            //  that follow them altogether.  If the user has
+            //  a mix of "C:" and "D:" designations in the
+            //  path and wants to run it on Unix, the user must
+            //  untangle it first.
+
+            int p = pathString.indexOf(":");
+            if (p != -1) {
+                StringBuffer sb = new StringBuffer();
+                int goodLength = 0;  // Last known good length
+                for (int i = 0; i < length; i++) {
+                    char c = pathString.charAt(i);
+                    if (c == ':') {
+                        sb.setLength(goodLength);
+                    }
+                    else {
+                        sb.append(c);
+                        if (c == ';')
+                            goodLength = sb.length();
+                    }
+                }
+                pathString = sb.toString();
             }
 
-            if (tmp.equals(":") || tmp.equals(";"))
-                tmp = path;
-            else if (tmp.equals("/") || tmp.equals ("\\"))
-                tmp = file;
-            bs.append(tmp);
+            //  Now translate ";" to ":" and "\\" to "/"
+
+            pathString = pathString.replace(';', ':');
+            pathString = pathString.replace('\\', '/');
         }
-        return(bs.toString());
+
+        //  Unix to Win32 translation:
+
+        else {
+
+            //  Translate ":" to ";" and "/" to "\\"
+
+            pathString = pathString.replace(':', ';');
+            pathString = pathString.replace('/', '\\');
+        }
+
+        return pathString;
     }
 
     /**

--- END CUT ---

BUG 2 - Javac.addExtdirsToClasspath()

2. org.apache.tools.ant.taskdefs.Javac gets a null pointer exception in addExtdirsToClasspath() if any element of the path refers to a directory which does not exist.  The fix consists of testing the file list for null before entering the loop.  Here is the patch:

--- CUT HERE ---
--- Javac.java Wed May 10 16:20:34 2000
+++ Javac.java.new Sat May 13 15:45:58 2000
@@ -593,6 +593,7 @@
            while (tok.hasMoreTokens()) {
                File dir = project.resolveFile(tok.nextToken());
                String[] files = dir.list(new JarFilenameFilter());
+               if (files == null) continue;
                for (int i=0 ; i < files.length ; i++) {
                    File f = new File(dir,files[i]);
                    if (f.exists() && f.isFile()) {

--- END CUT ---

Thanks,
Phil Hanna

Re: Beginner questions for setting up build environment

Posted by Stefan Bodewig <bo...@bost.de>.
Hi Tom,

>>>>> "tg" == tom goodman <to...@bigfoot.com> writes:

 tg> 1) I've have the java files in a hierarchy and want to compile
 tg> the entire tree into a single jar file containing .class files.
 tg> Is there a simple way to do that?

Sure, look at Ant's own build.xml which does exactly what you want for
Ant itself.

 tg> 2) The files need to compile in the right order to satisfy the
 tg> include dependencies in the .java files.

All files are compiled at the same time which is guaranteed to be the
right order 8^).

 tg> I know this must be simple stuff written up in a doc somewhere
 tg> but I can't find it.

See docs/index.html in Ant's CVS repository and take a look at
spec/core.html to get a feeling for things to come.

HTH

        Stefan

Beginner questions for setting up build environment

Posted by tom goodman <to...@bigfoot.com>.
I'm trying to set up an JSP, servlet, bean, apache, jakarta-tomcat, java 1.2
environment.  and would like to use ant to manage the compile dependencies.
I have all the pieces installed.

Can someone tell me where I might find a good running demo of this that I
can start with?  Or a good tutorial?  I dowloaded Sun's JavaPetStore code
demo (which uses ant, etc) but it looks like that requires the  J2EE sdk
which doesn't seem to be available on Linux yet.

Two basic questions:

1) I've have the java files in a hierarchy and want to compile the entire
tree into a single jar file containing .class files.  Is there a simple way
to do that?

2) The files need to compile in the right order to satisfy the include
dependencies in the .java files.

I know this must be simple stuff written up in a doc somewhere but I can't
find it.
If ant (or something simpler) helps, I'll gladly use it.

Thanks any help.

tom


Re: Fixes for org.apache.tools.ant.taskdefs.Javac and org.apache.tools.ant.Project

Posted by Tom Cook <tc...@ardec.com.au>.
A few comments:

On Sat, 13 May 2000, Phil Hanna wrote:

> Unfortunately, the translatePath() problem is not always possible to solve because the Unix and Win32 path formats do not map completely.

True.

> For example, what should we make of c:/test?  It could be a single Win32
> directory or two Unix directories.

Mmmmm, how likely is it that absolute paths will map from a win32 to UNIX
environment? To take your example, it seems very unlikely to me that a
'C:\test' on one system will map to '/test' on another system. Things get
more complicated as the paths get deeper - different conventions are used
on each system. For instance, applications are in "C:\Program Files" on
Win32, and are smattered over /usr, /usr/local, /opt and /mnt/* on UNIX
systems. None of these are restrictive, but they clearly don't map well. I
wonder, then, how valuable mapping absolute paths from Win32 to UNIX and
back again is. Clearly relative paths within a project are likely to
remain consistent, but absolute paths I feel need more thought.

> (Forward slashes should be treated as valid, even on Win32).

Do M$ Win32 systems recognize them?

Cheerio
--
Tom Cook - Software Engineer

"The brain is a wonderful organ. It starts functioning the moment you get
up in the morning, and does not stop until you get into the office."
	- Robert Frost

LISAcorp - www.lisa.com.au

--------------------------------------------------
38 Greenhill Rd.          Level 3, 228 Pitt Street
Wayville, SA, 5034        Sydney, NSW, 2000

Phone:   +61 8 8272 1555  Phone:   +61 2 9283 0877
Fax:     +61 8 8271 1199  Fax:     +61 2 9283 0866
--------------------------------------------------