ant-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Paul Cody <paul.c...@lucida.com>
Subject RE: Using Main-Class and Class-Path in a manifest file
Date Tue, 12 Mar 2002 22:12:18 GMT
Hmm.  Sounds interesting.  I had a look at
org.apache.tools.ant.taskdefs.Manifest to see what I could see.  

-- A Manifest object contains a set of Section object keyed by name
-- A Section contains a set of Attribute objects, keyed by
name.toLowerCase().  
-- Both mappings use java.util.Hashtable to maintain the String:Object
mappings.  

There is no code that I could see which sorts the attributes in a section
upon writing, so the order will be that imposed by the hashCode values of
the keys.  Indeed, running the simple test program test.java:

import java.util.*;

class test {

    public static void main(String[] args) {

        Hashtable h = new Hashtable();
        addEntry(h, "Main-Class");
        addEntry(h, "Created-By");
        addEntry(h, "Class-Path");

        int i = 0;
        for (Enumeration e = h.elements(); e.hasMoreElements();) {
            System.out.println(String.valueOf(i++) + ": " +
e.nextElement());
        }
        
        printHash("Main-Class");
        printHash("Created-By");
        printHash("Class-Path");
        
        printHash("main-class");
        printHash("created-by");
        printHash("class-path");
    }
    
    private static void printHash(String s) {
        System.out.println(s + ": " + s.hashCode());
    }

    private static void addEntry(Hashtable h, String s) {
        s = s.toLowerCase();
        h.put(s, s);
    }

}

Yields the following results:

0: main-class
1: created-by
2: class-path
Main-Class: 1325056100
Created-By: -931871332
Class-Path: 1655920538
main-class: -638856092
created-by: 1369632092
class-path: -336591014

Therefore, the test class printed the elements of the hashtable [0, 1, 2] in
the same order seen by you when the manifest is written to a file, which
also explains why the order of the XML does not matter.

I think I remember reading somewhere about the Class-Path that it *must* be
the line directly following the Manifest-Version string.  Definitely my past
experience with .ear's deployed within Weblogic and JBoss suggest it.
Unfortunately I cannot seem to find any documentation that confirms this.
If that is the case, I would consider this to be a bug in Manifest.java
since it does not enforce this ordering.

The fix to Manifest.java would be to check if the attribute "class-path"
exists, and write this first.

The source for ant 1.4.1 has this 'bug' (if it is one) as well as the cvs
tip.

The workaround would seem to be <exec> jar directly from within ant, it
would appear that <jar> would be unusable for you under these conditions.

Can anyone confirm that Class-Path needs to be the first entry in the main
section of a manifest?

Cheers,
Paul 

> -----Original Message-----
> From: Todd Wilson [mailto:todd_wilson@byu.edu]
> Sent: Tuesday, March 12, 2002 1:20 PM
> To: ant-user@jakarta.apache.org
> Subject: Using Main-Class and Class-Path in a manifest file
> 
> 
> Greetings,
> 
> We're attempting to use Ant in generating a JAR file that creates a 
> manifest file which uses both the Class-Path and Main-Class 
> properties, 
> but can't seem to be able to get it to work.
> 
> Here is some information that would be useful to any wanting 
> to respond--
> 
> 
> ====================================================
> Our directory structure:
> ====================================================
> ant_test
> '- build
>    '- lib
>      '- log4j.jar
> '- build.xml
> '- dist
> '- src
>    '- HelloWorld.java
> ====================================================
> 
> 
> ====================================================
> Our build.xml file:
> ====================================================
> <project name="HelloWorld" default="dist" basedir=".">
> 
>    <target name="init">
>      <!-- set global properties for this build -->
>      <property name="src" value="src"/>
>      <property name="build" value="build"/>
>      <property name="dist"  value="dist"/>
> 
>      <!-- Create the time stamp -->
>      <tstamp/>
>      <!-- Create the build directory structure used by compile -->
>      <mkdir dir="${build}"/>
>    </target>
> 
>    <target name="compile" depends="init">
>      <!-- Compile the java code from ${src} into ${build} -->
>      <javac srcdir="${src}" destdir="${build}"/>
>    </target>
> 
>    <target name="dist" depends="compile">
>      <!-- Create the distribution directory -->
>      <mkdir dir="${dist}"/>
> 
>      <!-- Put everything in ${build} into the HelloWorld.jar file -->
>      <jar jarfile="${dist}/HelloWorld.jar" basedir="${build}">
>        <manifest>
>          <attribute name="Class-Path" value=". ./lib/log4j.jar"/>
>          <attribute name="Main-Class" value="HelloWorld"/>
>        </manifest>
>      </jar>
>    </target>
> 
>    <target name="clean">
>      <!-- Delete the ${build} and ${dist} directory trees -->
>      <delete dir="${build}"/>
>      <delete dir="${dist}"/>
>    </target>
> </project>
> ====================================================
> 
> 
> ====================================================
> HelloWorld.java:
> ====================================================
> import org.apache.log4j.*;
> 
> public class HelloWorld
> {
>    public static Category log = Category.getInstance( 
> HelloWorld.class.getName() );
> 
>    public HelloWorld()
>    {
>      System.out.println( "Hello world!" );
> 
>      log.debug( "Log4J is working." );
>    }
> 
>    public static void main( String args[] )
>    {
>      BasicConfigurator.configure();
> 
>      HelloWorld hw = new HelloWorld();
>    }
> }
> ====================================================
> 
> 
> When we run ant in the "ant_test" directory it produces the 
> HelloWorld.jar file in the "dist" directory as it's supposed to, but 
> running the jar with
> 
> java -jar HellowWorld.jar
> 
> produces the following error message:
> 
> Exception in thread "main" java.lang.NoClassDefFoundError: 
> org/apache/log4j/Category
>          at HelloWorld.<clinit>(Unknown Source)
> 
> So it's apparently finding our "Main-Class" just fine, but 
> seems to be 
> ignoring the "Class-Path" property.
> 
> If we unjar the HelloWorld.jar file it reveals that the following 
> manifest file was generated by Ant:
> 
> ====================================================
> Manifest-Version: 1.0
> Main-Class: HelloWorld
> Created-By: Ant 1.4.1
> Class-Path: . ./lib/log4j.jar
> ====================================================
> 
> In an attempt to diagnose the problem, we then copy the 
> contents of the 
> build directory (which contains the HelloWorld.class file 
> generated when 
> Ant ran as well as the lib directory containing log4j.jar) into a 
> separate tmp directory.  We then attempt to jar up the 
> contents of tmp 
> using the manifest file created by Ant, with the following command:
> 
> jar -cfm HelloWorld.jar ../dist/META-INF/MANIFEST.MF ./*
> 
> Again, notice that we're designating the manifest file that was 
> generated by Ant as the manifest file that should be used for 
> the newly 
> created HelloWorld.jar file.  After running this jar command 
> we attempt 
> to run the second HelloWorld.jar file with
> 
> java -jar HelloWorld.jar
> 
> and it runs just fine.  If we unjar this second 
> HelloWorld.jar file we 
> find that the contents of it are identical to that of the first 
> HelloWorld.jar file (as near as we can tell) aside from the manifest 
> file which now looks like this:
> 
> ====================================================
> Manifest-Version: 1.0
> Created-By: Ant 1.4.1
> Class-Path: . ./lib/log4j.jar
> Main-Class: HelloWorld
> ====================================================
> 
> Running diff on the two files reveals that, aside from white 
> space, the 
> only difference between the two is that the "Main-Class" line in the 
> first manifest file is on the second line where the 
> "Main-Class" line in 
> the second manifest file is on the last line.  It seems odd that the 
> order in which the properties appear in the manifest file 
> would make any 
> difference, but, as I mentioned, that's the only discrepancy we could 
> find between the two jars.
> 
> It's as though the java runtime parses through the manifest file and, 
> upon reaching the "Main-Class" line, immediately invokes the class 
> designated rather than parsing the rest of the file in order 
> to set the 
> classpath first.  If this is the case, is there any way to 
> make Ant put 
> the "Main-Class" property at the end of the manifest file?  
> Rearranging 
> the XML tags doesn't seem to have any affect on this.
> 
> We've also tried creating a manifest file before running Ant that 
> positions the "Main-Class" property at the end, then using the 
> "manifest" attribute of the "jar" tag, but when Ant runs it moves the 
> "Main-Class" property up to the second position, as before.
> 
> We've tried this process on Linux running JDK 1.4 as well as Win2K 
> running JDK 1.3.1_01, and have gotten the same results.  The 
> log4j.jar 
> file can be obtained from http://jakarta.apache.org/log4j/, 
> but I'm sure 
> you all already knew that :)
> 
> Sorry this message is so long-winded, but I figure it's better to be 
> verbose in situations like this rather than terse.  Many thanks in 
> advance to anyone willing to lend a hand.
> 
> Regards,
> 
> Todd Wilson
> 
> P.S.  Lest we be accused otherwise, we've already spent a 
> fair amount of 
> time searching the archives of the list for a solution to 
> this problem, 
> but, unfortunately, haven't been successful.
> 
> 
> --
> To unsubscribe, e-mail:   
<mailto:ant-user-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:ant-user-help@jakarta.apache.org>

--
To unsubscribe, e-mail:   <mailto:ant-user-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:ant-user-help@jakarta.apache.org>


Mime
View raw message