wiki:AntResume

Ant versus Make

(Jean-Noël Albert / Avril 2005 / Groupe de développeurs du LAL)

présentation

Make et Ant sont tous deux des systèmes pour la construction d'application.

Make :

  • est un standard UNIX
  • est orienté “tâche à accomplir”

tandis que Ant :

  • vise la portabilité
  • est orienté “enchaînement de taches”
  • est extensible
  • est écrit en Java et donc très bien adapté aux développements Java

Make

c'est l'histoire d'un make…

Make est devenu un standard au même titre que UNIX

  • il existe une implémentation de Make par variante de UNIX, globalement similaires, mais assez différentes dans les détails pour rendre difficile les portages ;
  • plus une variante GNU : GNU Make ou GMake
    • la plus riche en extensions ;
    • la plus utilisée par les développeurs ;
    • adoptée par Linux.

L'approche Make

Principe : on décrit le but à atteindre, et non pas la façon d'y parvenir.

Exemple : pour construire le programme hello à partir du source hello.c, il suffit de lancer la commande :

% make hello

Make procède automatiquement à la recherche des fichiers qui lui permettent d'atteindre le but demandé (la construction de hello). Il trouve un fichier hello.c. Il dispose d'une règle interne lui permettant de passer d'un fichier C à une application. Il lance la compilation et l'édition de liens C.

Résultat :

cc     hello.c   -o hello

Et le programme hello est construit. Ca marcherait aussi avec un fichier source en Fortran, en C++ etc.

Si on relance la même commande :

% make hello

make: `hello' is up to date.

Il n'y a rien à faire, puisque l'application hello vient d'être compilée et que la source 'hello.c n'a pas changé. Si on modifie le fichier source :

% touch hello.c

% make hello

cc     hello.c   -o hello

Make détecte que le fichier source est plus récent que l'application compilée et la reconstruit.

Make se base sur la date des fichiers pour savoir quels fichiers reconstruire.

Si l'application dépend de plusieurs sources, Make ne reconstruit que ce qui a changé. Il s'ensuit un _gain de temps_ (surtout avec C++ qui est long à compiler) ; et l'application est toujours en phase avec les développements.

Makefile

Pour des applications plus compliquées, on utilise un fichier de description nommé Makefile (makefile est également accepté – et selon la mouture de Make, d'autres fichiers sont reconnus et traités ; par exemple GMake utilise de préférence le fichier GNUmakefile, si celui-ci existe dans le répertoire).

Le fichier de description contient une liste de “buts à atteindre” (appelés le plus souvent “cible”) et les moyens d'y parvenir.

Lorsqu'un fichier Makefile existe dans le répertoire, Make le lit et exécute le premier “objectif”. Pour exécuter un autre objectif, on l'indique sur la ligne de commandes de Make. Exemple d'un fichier Makefile simple :

hello : hello.c

# Supprime les fichiers compilés et les sauvegardes XEmacs
clean :
   rm hello hello.o *~

Pour construire l'application :

% make

cc    -c -o hello.o hello.c
cc   hello.o   -o hello

Make exécute le premier objectif du fichier (hello).

Un but peut dépendre d'étapes intermédiaires (par exemple pour la construction de librairies).

Exemple très simplifié :

hello : hello.o

hello.o : hello.c

Un but peut ne correspondre à aucun fichier, comme "clean" dans l'exemple précédent. Dans ce cas, il sera toujours accompli.

Exemple : suppression des fichiers compilés :

% make clean

rm hello hello.o *~

Principaux inconvénients

  • Lorsque les Makefiles deviennent compliqués, on ne sait pas toujours très bien quel va être le cheminement de Make, ni s'il va exécuter les étapes prévues, et dans quel ordre.
  • Pas très bien adapté à des projets comportant plusieurs répertoires – il faut souvent un fichier Makefile par répertoire, plus un fichier Makefile général pour reconstruire l'application pour chacun des répertoires.
  • Il faut souvent imposer à Make les opérations à réaliser, en fonction des saveurs de UNIX : options de compilations différentes d'une variante à l'autre, commandes différentes d'une plate-forme à l'autre, …
    • portage difficile - principales difficultés : les options de CC ;
    • GMake introduit des blocs if … else … pour tenir compte des plates-formes
      • ne simplifie pas la compréhension des fichiers Makefile ;
      • nécessite d'installer GMake (on peut aller le chercher sur le site GNU).
  • Portage difficile vers Windows (80-90 % des postes de travail)
    • principale difficulté : les noms de fichiers Windows sont incompatibles avec les noms de fichiers UNIX Exemple :
      • UNIX : /usr/bin/cc
      • Windows : C:\Windows\system32\cc.exe
    • une possibilité : Cygwin (portage des commandes UNIX sous Windows) - représente les fichiers Windows avec la syntaxe UNIX - utilise GMake
      • Exemple : /c/Windows/system32/cc.exe (le ".exe" est alors optionnel)
      • problème : les applications natives de Windows (comme par exemple Java) ne reconnaissent pas les noms UNIX.

Ant

La construction de l'application se fait en indiquant une succession d'opérations à réaliser.

Ant utilise un fichier build.xml.

Une tâche peut dépendre d'une ou de plusieurs autres tâches. L'exécution d'une tâche peut dépendre de conditions, par exemple pour ne pas construire une partie du code qui dépend d'une librairie qui n'est pas installée (exemple : un interface d'accès au HPSS du CC IN2P3).

Tout comme Make, Ant ne traite que les fichiers plus récents que les résultats à obtenir.

Ant assure qu'une tache ne sera accomplie qu'une seule fois dans le processus de construction :

  • ceci évite des situations de bouclage apparaissant avec Make lorsqu'une cible intermédiaire est en prémisse de plusieurs autres cibles
    • cas typiques : génération de fichiers à partir de sources qui ne sont pas des fichiers (base de données, …)

Plutôt que de laisser l'utilisateur indiquer les commandes à exécuter (rm, cc, …), Ant fournit un ensemble de taches permettant de réaliser les opérations escomptées :

  • compiler les fichiers sources
  • construire une librairie
  • construire la documentation
  • créer des répertoires
  • supprimer des fichiers de travail

Ant intègre la notion d'opérations récursives sur un ensemble de fichiers et de répertoires. Il vise la portabilité et tente de masquer les opérations sur les fichiers. Il est bien adapté à Java.

Java, Make & Ant

Les projets Java sont naturellement organisés en packages, et les fichiers sources doivent être placés dans une hiérarchie de répertoires reproduisant la hiérarchie des packages.

Le processus de compilation doit donc parcourir tous les répertoires - l'ordre n'est pas très important grâce au mécanisme de compilation incrémental de Java.

Make ne pas très bien adapté à cette situation; il y aurait deux possibilités : tout recompiler à chaque fois (lourd) ou lancer Make sur chacun des répertoires (peu pratique).

Mêmes difficultés pour construire la documentation (JavaDoc) : il faut passer en revue tous les répertoires.

Ant permet de résoudre la plupart de ces difficultés en trois taches :

<javac srcdir="sources/" destdir="classes/" />
<jar destfile="lib/hello.jar" basedir="classes/" />
<javadoc packagenames="demo" sourcepath="sources/" destdir="docs/" />

L'exemple complet :

<?xml version="1.0"?>
<project name="Hello" default="build" basedir=".">

  <target name="build">
    <javac srcdir="sources/" destdir="classes/" />
    <jar destfile="lib/hello.jar" basedir="classes/" />
  </target>

  <target name="doc" depends="build">
    <javadoc packagenames="demo" 
             sourcepath="sources/" 
             destdir="docs/" />
  </target>

  <target name="clean">
    <delete>
      <fileset dir="." defaultexcludes="no">
        <include name="**/*~"/>   <!-- XEmacs -->
        <include name="**/*.class"/>   <!-- Classes Java -->
        <include name="lib/*.jar"/>   <!-- Library Java -->
        <include name="docs/**/*" />   <!-- Javadoc -->
      </fileset>
    </delete>
   </target>

</project>

La construction de l'application :

% ant

Buildfile: build.xml

build:
    [javac] Compiling 1 source file to /albert/Test/classes
      [jar] Building jar: /albert/Test/lib/hello.jar

BUILD SUCCESSFUL
Total time: 3 seconds

L'élimination des fichiers intermédiaires (par exemple, après l'installation du projet)

% ant clean

Buildfile: build.xml

clean:
   [delete] Deleting 2 files from /albert/Test

BUILD SUCCESSFUL
Total time: 1 second

Portabilité

Ant est écrit en Java, donc portable.

Exemple : exécution du même script Ant sous Windows/XP et Cygwin :

$ ant doc

Buildfile: build.xml

build:
    [javac] Compiling 1 source file to D:\Projets\test\classes
      [jar] Building jar: D:\Projets\test\lib\hello.jar
doc:
  [javadoc] Generating Javadoc
  [javadoc] Javadoc execution
  [javadoc] Loading source files for package demo...
  [javadoc] Constructing Javadoc information...
  [javadoc] Standard Doclet version 1.5.0_01
  [javadoc] Building tree for all the packages and classes...
  [javadoc] Building index for all the packages and classes...
  [javadoc] Building index for all classes...

BUILD SUCCESSFUL
Total time: 9 seconds

Bien qu'on soit dans une émulation de l'environnement UNIX, les fichiers sont indiqués à Java en utilisant la notation native (le Java de Windows ne reconnaît pas la notation UNIX des fichiers…).

Autre exemple sous le shell Windows natif :

D:\Projets\test> PATH D:\externals\Ant\apache-ant-1.6.2\bin;%PATH%

D:\Projets\test> ant doc

Buildfile: build.xml

build:
    [javac] Compiling 1 source file to D:\Projets\test\classes
      [jar] Building jar: D:\Projets\test\lib\hello.jar
  [javadoc] Generating Javadoc
  [javadoc] Javadoc execution
  [javadoc] Loading source files for package demo...
  [javadoc] Constructing Javadoc information...
  [javadoc] Standard Doclet version 1.5.0_01
  [javadoc] Building tree for all the packages and classes...
  [javadoc] Building index for all the packages and classes...
  [javadoc] Building index for all classes...

BUILD SUCCESSFUL
Total time: 4 seconds

Extension

On peut ajouter des tâches en fournissant une archive Jar contenant les classes exécutant les nouvelles opérations et en définissant cette librairie dans le fichier build.xml.

Il n'y a pas de reconstruction de Ant : le chargement des librairies Java est dynamique (-> à l'exécution).

Cet aspect est utilisé par exemple pour le support de C++ et de Doxygen.

Un exemple de fichier build.xml utilisant l'extension C++ :

<?xml version="1.0"?>
<project name="Ant++" default="build" basedir=".">

<taskdef resource="net/sf/antcontrib/antcontrib.properties"/>
<taskdef resource="cpptasks.tasks"/>
<typedef resource="cpptasks.types"/>

<target name="build">
    <cc link="executable" outfile="demo.exe">
   <fileset dir=".">
     <include name="*.cc"/>
   </fileset>
   <syslibset libs="c,stdc++"/>
    </cc>
</target>

</project>

Exemple Linux :

% ant

Buildfile: build.xml

build:
       [cc] 1 total files to be compiled.
       [cc] Starting link

BUILD SUCCESSFUL
Total time: 2 seconds

% ./demo.exe

Hello, world !

Sous Windows, on peut utiliser Cygwin pour avoir un compilateur C++.

Le mécanisme pour écrire des tâches Ant est détaillé dans _Writing Your Own Task_.

Intégration

Ant est accepté par de nombreux IDE (Integrated Development Environment) : Eclipse, JBuilder, VisualAge for Java, WebSphere Studio.

Liens

Note : il faut prendre aussi la distribution cpptasks

Last modified 18 years ago Last modified on Jun 21, 2006, 11:47:01 AM