web-dev-qa-db-fra.com

Une manière propre de combiner plusieurs pots? Utiliser de préférence Ant

J'ai des dépendances d'exécution sur certains fichiers jars externes que je voudrais "rejar" en un seul fichier. Ces dépendances externes sont stockées dans un répertoire external_jars, et j'aimerais ne pas avoir à toutes les répertorier (c'est-à-dire, ne pas avoir besoin de changer mes scripts de construction si mes dépendances changent). Des pensées?

Google m'a donné une bonne réponse sur la façon de procéder - si cela ne vous dérange pas de répertorier chaque pot comme une dépendance:

http://markmail.org/message/zijbwm46maxzzoo5

En gros, je veux quelque chose dans le sens de ce qui suit, qui combinerait tous les pots du répertoire lib dans out.jar (avec quelques règles d'écrasement sensées).

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

Utilisez simplement zipgroupfileset avec la fourmi tâche Zip

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

Cela aplatira tout le contenu des bibliothèques de pots inclus.

55
Vladimir

La réponse de Vladimir est correcte, mais je pense que ce qu'il suggère implique de reconditionner tous les pots dans un seul grand fichier out.jar, qui est ensuite alimenté dans la tâche Ant Jar comme un seul <zipfileset> ou quelque chose comme ça. Cette approche en deux étapes n'est pas nécessaire. Je ne sais pas si cela est lié à la version Ant, mais j'ai Ant 1.7.1 et son <jar> la tâche comprend <zipgroupfileset>, qui permet d'alimenter directement tout le contenu des pots tiers.

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

Vous pouvez consulter jarjar:

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

23
Staale

Essayez d'abord d'extraire vos fichiers JAR dans un répertoire de marshalling:

<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} est un répertoire temporaire, ${external.jar.dir} est l'endroit où vous conservez les fichiers JAR, et ${combined.jar} est le fichier JAR cible.

9
David Grant

Si vous utilisez maven, pourquoi ne le feriez-vous pas? :) Utilisez simplement le plug-in maven-shadow, fonctionne comme un charme!

  <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>
3
Mozart Brocchini

Voici ma solution:

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

La question est bien répondue. Je voulais mentionner un outil que je trouve utile - One-Jar . One-Jar gère les ressources plus proprement (en les conservant toutes). Ceci est plus utile si le code doit traiter les fichiers MANIFEST.

Exemple XML copié à partir du site Web ..

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

Si vous construisez avec ant (j'utilise ant d'Eclipse), vous pouvez simplement ajouter les fichiers jar supplémentaires en disant à ant de les ajouter ... Pas nécessairement la meilleure méthode si vous avez un projet maintenu par plusieurs personnes mais ça marche pour un projet d'une personne et est facile.

par exemple, ma cible qui construisait le fichier .jar était:

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

Je viens d'ajouter une ligne pour le faire:

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

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

était le dir avec les pots externes. Et c'est tout ... Vous pouvez également ajouter plusieurs balises zipgroupfileset.

1
ntg

Avez-vous envisagé d'utiliser Maven ou un autre système qui gère automatiquement vos dépendances? Ensuite, vous n'auriez pas besoin de spécifier où se trouve chaque bibliothèque, quels sont leurs noms et quelles dépendances transitives ont vos dépendances directes. Vous indiqueriez simplement en un seul endroit ce que sont la dépendance et sa version, et le système se chargerait de télécharger les bibliothèques, de configurer le chemin de classe et de construire le projet.

1
Esko Luontola

Eh bien, je ne suis pas tellement dans la programmation - mais quelque chose de plus simple a fonctionné pour moi ... si la question signifiait - combiner des fichiers jar en un. Bien sûr, c'est une solution manuelle et sale. J'ai juste décompressé tous les goudrons ... et puis ... créé un nouveau fichier tar, en ajoutant tous les répertoires formés par décompactage dans le nouveau fichier tar. ça a marché.

0
Sowmya

Maven ou d'autres outils de construction ne peuvent pas "gérer" la résolution de plusieurs versions de fichiers de classe. En fait, Maven provoque ces problèmes en premier lieu, par l'inclusion transitive de tous les fichiers jar en aval qui ne sont pas explicitement requis par un projet.

Supposons quelque part dans la fermeture transitive d'un projet (toutes les bibliothèques et tous les modules requis par le projet, et tous ses projets dépendants, récursivement), il existe deux versions d'un fichier de classe. Comment Maven pourrait-il savoir lequel est le "bon"? lequel était destiné par le programmeur?

Cela ne peut pas parce que ces informations ont été perdues lorsque des dépendances explicites ont été jetées au profit de transitives (pour économiser le typage XML).

0
hans anderson