清洁方式结合多个罐子?最好使用Ant

时间:2009-02-05 11:01:14

标签: java ant jar

我对某些外部jar有运行时依赖性,我想“重新”到一个jar中。这些外部依赖项存储在external_jars目录中,我希望不必全部列出它们(即,如果我的依赖项发生更改,则不需要更改构建脚本)。有什么想法吗?

Google为我提供了一个很好的答案 - 如果你不介意将每个jar列为依赖:

http://markmail.org/message/zijbwm46maxzzoo5

粗略地说,我想要下面的内容,将lib目录中的所有jar组合成out.jar(带有一些合理的覆盖规则)。

jar -combine -out out.jar -in lib/*.jar

11 个答案:

答案 0 :(得分:65)

弗拉基米尔的答案是正确的,但我觉得他的建议意味着重新包装一个大的out.jar中的所有罐子,然后将其作为单个<zipfileset>或类似的东西送到Ant Jar任务。这种两步法是不必要的。我不确定这是否与Ant版本相关联,但我有Ant 1.7.1,其<jar>任务理解<zipgroupfileset>,它允许直接提供第三方罐子的所有内容。

<jar destfile="MyApplication.jar">
  <zipgroupfileset dir="lib" includes="*.jar" /> 
  <!-- other options -->
  <manifest>
    <attribute name="Main-Class" value="Main.MainClass" />
  </manifest>
</jar>

答案 1 :(得分:54)

只需将zipgroupfileset与Ant Zip task

一起使用即可
<zip destfile="out.jar">
    <zipgroupfileset dir="lib" includes="*.jar"/>
</zip>

这将使所有包含的jar库内容变得扁平化。

答案 2 :(得分:23)

你可以查看jarjar:

http://code.google.com/p/jarjar/

答案 3 :(得分:9)

首先尝试将JAR提取到编组目录:

<target name="combine-jars">
    <mkdir dir="${marshall.dir}"/>
    <unzip dest="${marshall.dir}">
        <fileset dir="${external.jar.dir}">
            <include name="**/*.jar"/>
        </fileset>
    </unzip>
    <jar destfile="${combined.jar}" basedir="${marshall.dir"}>
    <delete dir="${marshall.dir}"/>
</target>

${marshall.dir}是临时目录,${external.jar.dir}是保留JAR的地方,${combined.jar}是目标JAR。

答案 4 :(得分:4)

如果使用maven,为什么不呢? :) 只需使用maven-shade-plugin,就像魅力一样!

  <project>
  ...
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>1.5</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
            <configuration>
              <transformers>
                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                  <mainClass>com.YOUR_COMPANY.YOUR_MAIN_CLASS</mainClass>
                </transformer>
              </transformers>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  ...
</project>

答案 5 :(得分:2)

这是我的解决方案:

<target name="-post-jar">
    <echo>Packaging ${application.title} into a single JAR</echo>

    <jar destfile="${basedir}${file.separator}${dist.dir}${file.separator}_${ant.project.name}_.jar">
        <zipgroupfileset dir="${basedir}${file.separator}${dist.dir}" includes="${ant.project.name}.jar"/>
        <zipgroupfileset dir="${basedir}${file.separator}${dist.dir}${file.separator}lib" includes="*.jar"/>
        <manifest>
            <attribute name="Main-Class" value="${main.class}"/>
        </manifest>
    </jar>
</target>

答案 6 :(得分:1)

您是否考虑过使用Maven或其他自动管理依赖项的系统?然后,您不需要指定每个库的位置,它们的名称以及您的直接依赖项具有的传递依赖性。您只需在一个位置说明依赖关系及其版本是什么,系统将负责下载库,配置类路径和构建项目。

答案 7 :(得分:1)

这个问题得到了很好的回答。我想提一个我觉得有用的工具 - One-Jar。 One-Jar更干净地处理资源(通过保留所有资源)。如果代码需要process MANIFEST files.

,这会更有用

从网站复制的示例XML ..

<import file="one-jar-ant-task.xml"/>   

    <target name="hello" depends="init">
        <!-- Build lib.jar -->   
        <javac destdir="${classes.dir}/lib">
            <src path="${lib.dir}" />
        </javac>
        <jar destfile="${build.dir}/lib.jar" >
            <fileset dir="${classes.dir}/lib"/>
        </jar>   
        <!-- Build classes for main.jar -->   
        <javac destdir="${classes.dir}/src">
            <src path="${src.dir}" />
            <classpath path="${build.dir}/lib.jar"/>   
        </javac>
        <!-- Construct the One-JAR file -->   
        <one-jar destfile="hello.jar" manifest="hello.mf">
            <main>
                <!-- Construct main.jar from classes and source code -->
                <fileset dir="${classes.dir}/src"/>
            </main>
            <lib>
                <fileset file="${build.dir}/lib.jar" />
            </lib>
        </one-jar>
        <echo>
          Now you can run the Hello One-JAR example using 
          $ java -jar hello.jar
        </echo>   

    </target>

答案 8 :(得分:1)

如果你正在用ant构建(我正在使用eclipse中的ant),你可以添加额外的jar文件 通过对蚂蚁说来添加它们...... 如果你有一个由多人维护的项目,但它适用于一个人项目并且很容易,那么这不一定是最好的方法。

例如,构建.jar文件的目标是:

<jar destfile="${plugin.jar}" basedir="${plugin.build.dir}">
    <manifest>
        <attribute name="Author" value="ntg"/>
        ................................
        <attribute name="Plugin-Version" value="${version.entry.commit.revision}"/>
    </manifest>
</jar>

我刚添加了一行来制作它:

<jar ....">
    <zipgroupfileset dir="${external-lib-dir}" includes="*.jar"/>
    <manifest>
        ................................
    </manifest>
</jar>

,其中

<property name="external-lib-dir" value="C:\...\eclipseWorkspace\Filter\external\...\lib" />

是外部罐子的目录。 就是这样......你也可以添加多个zipgroupfileset标签。

答案 9 :(得分:0)

好吧,我不是那么喜欢编程 - 但是对我来说更简单的东西......如果问题意味着 - 将jar文件合并到一个。当然,这是手动的,肮脏的解决方案。 我只是解开了所有的tars ...然后......通过将untarring-in形成的所有目录添加到新的tar文件中来创建一个新的tar文件。有效。

答案 10 :(得分:0)

Maven或其他构建工具无法“管理”多个版本的类文件的解析。实际上,Maven首先会通过传递包含项目未明确要求的所有下游jar文件来解决这些问题。

假设项目的传递闭包中的某个地方(项目所需的所有库和模块,以及所有它依赖的项目,递归地),有两个版本的类文件。 Maven怎么可能知道哪一个是'正确的'?程序员打算使用哪一个?

它不能,因为当显式依赖关系被抛弃而转向传递时(保存XML类型),此信息丢失了。