views:

3753

answers:

4

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>
+1  A: 

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
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
Edited answer in response to comment.
Jason Day
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
You'll have to write a custom ant task or script to do that.
Jason Day
+1  A: 

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.

This works. I used this solution in my ant scripts at some point. But it is messy.
Toader Mihai Claudiu
Messy indeed. I would really like to see a working example of this that chops the leading path bits in a cross-platform way...
amarillion
+7  A: 

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>
McDowell
+1  A: 
<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>

See more at The detail

Qianjigui