从Ant的<classpath>生成清单类路径

40
在下面的构建文件中,jar目标引用manifest class-path的jar.class.path属性。编译目标引用project.class.path。
这里存在冗余,因为jar.class.path和project.class.path非常相似。当添加库时,它们都必须得到更新,如果库列表变得很长,这就会很麻烦。是否有更好的方法?任何解决方案都必须是跨平台的,并始终使用相对路径。
编辑:
它应该从一个文件集生成JAR类路径,而不是反过来,这样我就可以使用通配符来包括目录中的所有JAR文件。
<?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>
4个回答

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>

如需更多信息,请查看本篇文章


为什么这个答案没有被接受?它是完美的,即使有多个路径转换器也可以正常工作。 - ha9u63a7

47

假设您使用的是 Ant 1.7 或以上版本,则可以使用 manifestclasspath 任务。

<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>

1
这个方法是可行的,但前提是你的类路径中没有绝对路径。例如,如果你正在使用 Debian 包 libhibernate3-java,它安装在 /usr/share/java/hibernate3.jar 中,并将其包含在你的类路径中,那么 manifestclasspath ant 任务将会抛出错误。不过,Qianjigui 的解决方案仍然有效。 - joscarsson

2
如果您只想要两个(或更多)路径之间共享一个常见子路径,那么这很容易实现:
<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"/>

编辑 对不起,我误解了问题。请尝试以下方法:

<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>

不,那是不正确的。在这种情况下,jar.class.path的值是由冒号分隔而不是空格,并且更糟糕的是,它将使用完整路径,使其对于jar清单无用。 - amarillion
根据评论编辑的回答。 - Jason Day
是的,这在我给出的示例中有效。但我真的想从文件集构建jar类路径,而不是反过来,这样我就可以使用通配符。 - amarillion
你需要编写一个自定义的Ant任务或脚本来完成这个任务。 - Jason Day

1

您可以使用 <pathconvert> 将路径(可以包含文件集)转换为纯字符串。您可能需要将该字符串 <echo> 到文件中,使用 <replace> 或 <replaceregexp> 去掉前导路径位,最后使用 <loadfile> 将处理后的字符串加载到最终属性中。

具体实现留给读者作为练习。


这个可行。我曾经在我的Ant脚本中使用过这个解决方案。但它很混乱。 - Mihai Toader
确实有些混乱。我真的很想看到一个能够以跨平台方式切割前导路径位的工作示例... - amarillion

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接