40

In the build file below, the jar target refers to the jar.class.path property for the manifest class-path. The compile target refers to project.class.path

There is redundancy here, because jar.class.path and project.class.path are very similar. They must be both updated when libraries are added, which can be a pain if the list of libraries gets very long. Is there a better way? Any solution must be cross-platform and always use relative paths.

Edit:
It should generate the JAR classpath from a fileset and not the other way around, so I can use wildcards to e.g. include all JAR files in a directory.

<?xml version="1.0"?>
<project name="Higgins" default="jar" basedir=".">

    <property name="jar.class.path" value="lib/forms-1.2.0.jar lib/BrowserLauncher.jar"/>

    <path id="project.class.path">
      <pathelement location="build"/>
      <fileset dir="lib">
        <include name="forms-1.2.0.jar"/>
        <include name="BrowserLauncher.jar"/>
      </fileset>
    </path>

    <target name="prepare">
        <mkdir dir="build"/>
    </target>

    <target name="compile" depends="prepare" description="Compile core sources">
        <javac srcdir="src"
               includes="**"
               destdir="build"
               debug="true"
               source="1.5">
          <classpath refid="project.class.path"/>
        </javac>
    </target>

    <target name="jar" depends="compile" description="Generates executable jar file">
        <jar jarfile="higgins.jar">
            <manifest>
                <attribute name="Main-Class" value="nl.helixsoft.higgins.Main"/>
                <attribute name="Class-Path" value="${jar.class.path}"/>
            </manifest>
            <fileset dir="build" includes="**/*.class"/>            
            <fileset dir="src" includes="**/*.properties"/>         
        </jar>
    </target>

</project>
informatik01
  • 16,038
  • 10
  • 74
  • 104
amarillion
  • 24,487
  • 15
  • 68
  • 80

4 Answers4

50
<path id="build.classpath">
  <fileset dir="${basedir}">
     <include name="lib/*.jar"/>
  </fileset>
</path>

<pathconvert property="manifest.classpath" pathsep=" ">
  <path refid="build.classpath"/>
  <mapper>
    <chainedmapper>
       <flattenmapper/>
       <globmapper from="*.jar" to="lib/*.jar"/>
    </chainedmapper>
  </mapper>
</pathconvert>

<target depends="compile" name="buildjar">
  <jar jarfile="${basedir}/${test.jar}">
     <fileset dir="${build}" />
     <manifest>
       <attribute name="Main-Class" value="com.mycompany.TestMain"/>
       <attribute name="Class-Path" value="${manifest.classpath}"/>
     </manifest>
 </jar>
</target>

For further information check out this article.

Alan Q.
  • 394
  • 2
  • 10
Qianjigui
  • 699
  • 5
  • 5
46

Assuming Ant 1.7 or above, you can use the manifestclasspath task.

<path id="dep.runtime">
    <fileset dir="./lib">
        <include name="**/*.jar" />
    </fileset>
</path>
<property name="dep_cp" value="${toString:dep.runtime}" />

<target name="default">
    <manifestclasspath property="manifest_cp" jarfile="myjar.jar">
        <classpath refid="dep.runtime" />
    </manifestclasspath>
    <echo message="Build Classpath: ${dep_cp}" />
    <echo message="Manifest Classpath: ${manifest_cp}" />
</target>
martin clayton
  • 76,436
  • 32
  • 213
  • 198
McDowell
  • 107,573
  • 31
  • 204
  • 267
  • 1
    This works, but only if you don't have absolute paths in your classpath. For example, if you're using the debian package `libhibernate3-java` which installs in `/usr/share/java/hibernate3.jar` and you include that in your classpath, the manifestclasspath ant task will throw an error. Qianjigui's solution still works though. – joscarsson May 04 '13 at 22:36
2

If you just want a common subpath shared between two (or more) paths, that is easy to do:

<path id="lib.path>
    <fileset dir="lib">
        <include name="forms-1.2.0.jar"/>
        <include name="BrowserLauncher.jar"/>
    </fileset>
</path>

<path id="project.class.path">
    <pathelement location="build"/>
    <path refid="lib.path"/>
</path>

<property name="jar.class.path" refid="lib.path"/>

EDIT Sorry, I misunderstood the question. Try this:

<property name="jar.class.path" value="lib/forms-1.2.0.jar lib/BrowserLauncher.jar"/>

<path id="project.class.path">
    <pathelement location="build"/>
    <fileset dir="." includes="${jar.class.path}"/>
</path>
Jason Day
  • 8,809
  • 1
  • 41
  • 46
  • No, that is incorrect. In this case, the value of jar.class.path is separated by colons instead of spaces, and what is worse, it will use full paths making it useless for the jar manifest. – amarillion May 15 '09 at 07:26
  • Edited answer in response to comment. – Jason Day May 15 '09 at 14:52
  • Yeah, that does work in the example I gave. But I really would like to build the jar classpath from a fileset and not the other way around, so I can use wildcards. – amarillion May 15 '09 at 15:01
  • You'll have to write a custom ant task or script to do that. – Jason Day May 15 '09 at 17:16
1

You can use <pathconvert> to convert a path (which can contain a fileset) into a plain string. You'll likely need to <echo> that string to a file, use either <replace> or <replaceregexp> to chop the leading path bits, then finally use <loadfile> to load the manipulated string into the final property.

Implementation left as an exercise to the reader.