Чистый способ объединить несколько банок? Желательно с помощью Ant

У меня есть зависимости времени выполнения от некоторых внешних jar-файлов, которые я хотел бы "перекомпилировать" в один jar-файл. Эти внешние зависимости хранятся в каталоге external_jars, и я хотел бы иметь возможность не перечислять их все (т. Е. Не нужно менять сценарии сборки, если меняются зависимости). Какие-нибудь мысли?

Google дал мне хороший ответ о том, как это сделать - если вы не возражаете перечислить каждую банку в качестве зависимости:

http://markmail.org/message/zijbwm46maxzzoo5

Грубо говоря, я хочу что-то вроде следующего: объединить все jar-файлы из каталога lib в out.jar (с некоторыми нормальными правилами перезаписи).

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

11 ответов

Решение

Просто используйте zipgroupfileset с заданием Ant Zip

<zip destfile="out.jar">
    <zipgroupfileset dir="lib" includes="*.jar"/>
</zip>

Это сгладит все содержимое библиотек jar.

Ответ Владимира правильный, но я чувствую, что то, что он предлагает, подразумевает переупаковку всех банок в один большой out.jar, который затем передается в задачу Ant Jar как единый <zipfileset> или что-то типа того. Этот двухэтапный подход не нужен. Я не уверен, связано ли это с версией 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>

Вы можете проверить jarjar:

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

Попробуйте сначала извлечь ваши 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} где вы храните банки, и ${combined.jar} это целевой JAR.

Если вы используете 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>

Это мое решение:

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

Если вы собираете с помощью ant (я использую ant из eclipse), вы можете просто добавить дополнительные jar-файлы, сказав ant для добавления их... Не обязательно лучший метод, если у вас есть проект, поддерживаемый несколькими людьми, но он работает для одного человека проект и легко.

например, моя цель, которая строила файл.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.

На вопрос хорошо ответили. Я хотел упомянуть один инструмент, который я считаю полезным - One-Jar. One-Jar обрабатывает ресурсы более аккуратно (сохраняя их все). Это более полезно, если код должен обрабатывать файлы MANIFEST.

Образец 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>

Рассматривали ли вы использование Maven или какой-либо другой системы, которая автоматически управляет вашими зависимостями? Тогда вам не нужно будет указывать, где находится каждая библиотека, каковы их имена и какие транзитивные зависимости имеют ваши прямые зависимости. Вы бы просто указали в одном месте, какова зависимость и ее версия, и система позаботится о загрузке библиотек, настройке пути к классам и создании проекта.

Ну, я не так сильно разбираюсь в программировании - но что-то более простое сработало для меня... если вопрос имел в виду - объединение jar-файлов в один. Конечно, это ручное, грязное решение. Я просто распаковал все tars... и затем.. создал новый файл tar, добавив все каталоги, сформированные unararring-in, в новый файл tar. это сработало.

Maven или другие инструменты сборки не могут "управлять" разрешением нескольких версий файлов классов. Фактически, Maven вызывает эти проблемы, в первую очередь, путем транзитивного включения всех последующих jar-файлов, которые явно не требуются для проекта.

Предположим, что где-то в транзитивном закрытии проекта (все библиотеки и модули, требуемые проектом, и все его зависимые проекты, рекурсивно) существуют две версии файла класса. Как мог Мейвен узнать, какой из них "правильный"? какой был задуман программистом?

Это невозможно, потому что эта информация была потеряна, когда явные зависимости были отброшены в пользу транзитивных (чтобы сохранить типизацию XML).

Другие вопросы по тегам