Tutorial ANT: Uso con librerías externas y generadores JFlex y CUP

Logo Ant

He dedicado tiempo ultimamente a aprender al menos de manera básica el uso ANT, que para los que no lo sepan es una herramienta para compilación de proyectos JAVA al estilo del make para C. Justo me proponen en la universidad que realice una presentación en clase sobre ello; no me ha podido venir más bien después de haber estado yo haciendo algunos ejemplos. Así que me dispuse a ordenar mis investigaciones para crear un ejemplo sencillo que aunara lo que considero más importante, y sobre ese ejemplo realizar una presentación que me ayudara a explicarlo en clase de la manera más ordenada posible.

Bueno, y ya que he hecho la presentación y el ejemplo pues me animo también a presentar aquí el tutorial

¿Qué es ANT?

Como ya he comentado ANT es una herramienta para compilación de proyectos JAVA, y como tal escrita en el mismo. Se podría decir que es una herramienta como make para programas en C solo que especialmente diseñada pensando en JAVA; nos proporciona los medios para la realización de las tareas que componen el proceso de compilación, documentación, distribución, etc de un proyecto JAVA.

Es muy útil para los casos en los que se trabaja con distintos entornos de desarrollo para disponer de una manera estándar y fácil de compilar el proyecto, y sobretodo en proyectos complejos con muchas librerías o en proyectos web en los que las tareas de compilación comprenden más pasos. Además la mayoría de los entornos de desarrollo disponen de opciones para la ejecución de scripts de ANT.

Por último comentar que actualmente no es ant la herramienta más usada para esto, sino que se está usando cada vez más una herramienta similar llamada Maven, la cual tiene algunas ventajas sobre el que ahora nos ocupa.

Instalación de ANT

La instalación de ANT es bien sencilla, básicamente consiste en situar los archivos de ant en las variables de entorno del sistema. Podemos conseguir los archivos de instalación en la web del proyecto. Pese a ser una obviedad comentaré que se necesita tener instalado el JDK (Java Developer Kit) puesto que ant está escrito en Java.

Mac OS

Yo no he tenido que hacer nada para instalarlo, o viene por defecto o se instaló con el Xcode de Mac OS.

Linux

Si suponemos que hemos situado los archivos ANT en /usr/local/ant

Windows

Si suponemos que hemos situado los archivos de ANT en C:\ant\

Si hemos instalado ant correctamente podremos teclear el comando para ver su versión en la consola y nos deberá reconocer el comando.

Para ejecutar ant sobre un fichero build.xml nos situaremos en el directorio donde este el fichero y teclearemos ant para ejecutar el objetivo por defecto o ant y un objetivo en concreto para ejecutar ese objetivo concreto (se ejecutarán también sus dependencias obviamente)

Algunas definiciones

Vamos a ver en este apartado algunos conceptos que hemos de conocer para trabajar con ANT.

Mientras que en el famoso make de C teníamos un fichero llamado makefile, en este caso tendremos un fichero xml llamado build.xml en el que estarán escritos los pasos que se han de seguir para la compilación de nuestro proyecto. Pasemos ahora a definir los elementos de dicho fichero (o etiquetas puesto que es un fichero XML).

  • project: Es el elemento raíz del fichero XML y como tal solo puede haber uno en el fichero. Es el propio proyecto con el que estamos trabajando
  • target: Elemento que agrupa un conjunto de tareas que se desean realizar en un momento determinado. Como veremos puede haber unos objetivos dependientes de otros
  • task: Es el código ejecutable que será aplicado a la aplicación en algún momento, puede contener distintas propiedades.
  • property: Parámetros en forma de par clave-valor (los nombres serán case-sensitive) para personalizar el proceso de construcción o simplemente como accesos directos a un dato que se use de manera repetitiva en el fichero xml.

Continuemos ahora viendo una estructura de directorios para un proyecto Java.
Estructura Proyecto Java En primer lugar tenemos el directorio classes en donde se almacenarán las clases Java compiladas.

Dentro del directorio dist se encontrará la aplicación empaquetada en forma de jar autoejecutable, también se podía incluir aquí la documentación para su distribución aunque he optado por ponerla en la raíz del proyecto.

En el directorio doc estará la documentación del proyecto en formato javadoc.

En el interior del directorio lib estarán almacenadas las bibliotecas externas que hayamos usado en nuestro proyecto.

Por último el directorio src en el que estará el código fuente de la aplicación organizado en los paquetes que hayamos decidido nosotros mismos.

Nuestro primer build.xml

Vamos a ver aquí nuestro primer ejemplo y sobre él explicaremos las partes básicas a parte de las etiquetas ya explicadas.

Lo primero que nos encontramos es que la raiz del fichero tiene dos atributos que no hemos explicado anteriormente. El primero de ellos es default, este especifica cual es el objetivo que se ejecutará por defecto al ejecutar este script de ant salvo que se especifique uno concreto. El atributo basedir indica donde están situados los directorios del proyecto. En este caso como tendremos el fichero buid.xml al mismo nivel que los directorios del proyecto hemos puesto un punto.

Lo siguiente que nos encontraremos serán las propiedades que como dije son pares clave valor. En este caso yo las he usado para tener un acceso más rápido a los distintos directorios y menos problemas si alguno de ellos fuera cambiado. Accederemos a ellas posteriormente así ${propiedad}

Finalmente nos encontramos con un objetivo sencillo que realiza la compilación con la tarea javac, tiene como atributos srcdir que indica donde está el código fuente a compilar y destdir indica en que directorio se han de dejar las clases compiladas.

Los objetivos pueden tener dependencias, las cuales se indican con el atributo depends. Las dependencias entre objetivos indican que un objetivo que depende de otro no será ejecutado sin que se haya ejecutado previamente ese otro del que depende. Veamos un ejemplo sencillo.

Empaquetado del proyecto

En este apartado veremos como crear un objetivo que se encargue de empaquetar las clases compiladas en un único jar autoejecutable.

Un archivo jar es como un archivo zip, incluso con la misma compresión; y en su interior contiene las clases java organizadas en paquetes y una carpeta más llamada META-INF, esa carpeta es la usada para meter en su interior meta-información sobre el archivo jar.

Dentro de la carpeta nombrada se suele encontrar un fichero llamado manifest.mf, el cual tiene en su interior un conjunto de pares clave valor que pueden ser necesarios. En nuestro ejemplo lo que indicaremos en el fichero será cual es la clase main (Main-Class) de nuestro proyecto para que se sepa por donde tiene que empezar la ejecución. Sin esto no podríamos ejecutar el archivo jar, al menos con el típico doble click, habría que hacerlo pasando por la consola y llamando directamente a la clase Main.

Como hemos visto, la tarea jar contiene dos atributos, el primero de ellos llamado destfile que indicará la ruta donde queremos el fichero jar generado, el atributo basedir indica donde se encuentran las clases compiladas a incluir y finalmente el atributo includes que me indicará que tipo de ficheros se incluyen dentro del fichero jar creado.

Como se puede ver, un nivel por debajo de la tarea jar nos encontramos con la etiqueta manifest, la cual, como podemos suponer, sirve para incluir conjuntos de pares clave valor dentro del fichero que comenté anteriormente. Como se observa se indica la ruta a la clase main tal y como hemos comentado.

Generación de documentación

En este apartado veremos como crear un objetivo que cree documentación javadoc sobre nuestro proyecto. Vamos a poner aquí un pequeño ejemplo y lo explicaremos posteriormente.

Como vemos la tarea que se encarga de generar la documentación javadoc del proyecto tiene bastantes atributos, los primeros de ellos son los más importantes de todos. El primero de ellos, packagenames, indica los paquetes sobre los que se desea generar la documentación, esta vez hemos puesto asterisco para generar la documentación de todos ellos, sourcepath es el directorio donde se encuentran los archivos fuente del proyecto, destdir indica el directorio donde se van a guardar los archivos generados en el proceso de documentación (el resultado final).

Los demás atributos que observamos son de menos importancia que los anteriores ya que se refieren más a la personalización de esa documentación a generar, por ejemplo tomar en cuenta etiquetas @author o @version, el título y el pie de página del documento, etc…

Limpieza e Inicialización

Entre las muchas tareas predefinidas con las que cuenta ant podemos encontrar tareas para crear y borrar carpetas (y archivos).

Puede ser que queramos borrar las clases compiladas antes de una nueva compilación para que no haya problemas, y obviamente también habrá que crear las carpetas después de borrarlas.

Veamos aquí dos ejemplos de objetivos de ejemplo para crear y borrar carpetas. En este ejemplo haremos que se borre el paquete jar autoejecutable, las clases compiladas y la documentación generada; parece lo más lógico hacerlo así para evitar problemas si hay cambios grandes en la estructura de clases y paquetes.

Como podemos ver la tarea delete tiene como función borrar directorios y con los atributos se indica que es lo que se quiere borrar. Y, con la tarea mkdir se hace lo contrario, crear directorios.

Como podeis ver el objetivo init depende del objetivo limpiar. Lo que quiere decir que llamar al objetivo init impicará borrar todo lo anterior y dejar las carpetas listas para la compilación, empaquetado y generación de documentación.

Utilización con librerías externas

En este apartado veremos como trabajar con librerías externas y veremos como hacer las tareas que ya hemos realizado pero usando librerías externas.

Es posible hacer referencia a una carpeta con librerías de varias formas, pero si se quiere usar esa referencia en varios lugares del fichero build.xml la mejor forma es hacer uso del elemento path, dentro del cual se selecciona la carpeta con las librerías, pudiéndose también hacer uso de filtros para seleccionar solo determinados ficheros.

Posteriormente habrá que usar ese elemento para incluirlo en el classpath durante la compilación y la generación de la documentación.

Y en lo que respecta a la tarea del empaquetado de las clases compiladas hay que tener en cuenta dos cosas, en primer lugar para incluir un fichero jar de librerías en el paquete autoejecutable jar generado lo que se realiza es una descompresión del jar de las librerías para incluirlo en el jar final. Como resultado de este proceso obtendríamos la carpeta META-INF del paquete de las librerías, que de no ser excluido sobreescribiría la carpeta META-INF junto con el manifiesto creado, por lo que se perdería la meta-información que añadíamos a nuestro fichero jar final, y si esta información se perdiese la máquina virtual de JAVA no sabría cual es la clase Main para ejecutar el paquete.

Por lo tanto, para realizar estas tareas usaremos el elemento zipfileset indicando el fichero comprimido a incluir junto con un filtro para excluir la carpeta META-INF como ya hemos dicho.

Ejecución

En este apartado veremos como ejecutar el proyecto tanto desde una clase java como desde el proyecto empaquetado en un jar.

Ejecución desde clase Java

La tarea que nos ayudará a la ejecución es java, y usaremos el atributo classname para indicar la clase a ejecutar, para que pueda encontrar dicha clase tendremos que definir el atributo classpath con la ruta donde esta el paquete y la clase que hemos dicho que tenga que ejecutar.

Para poner los argumentos tendremos que usar arg y el argumento se pondrá en el atributo value. También hay que tener en cuenta que habrá que indicar la ruta de las librerías referenciando al elemento path que creamos en el apartado anterior.

Ejecución desde un archivo jar

Para este caso seguiremos usando la tarea java pero en este caso con el atributo jar en el que indicaremos la ubicación del archivo jar a ejecutar. Recordemos que para que la máquina virtual de java (VM) sepa que clase tiene que ejecutar tendremos que haber definido bien las propiedades en el manifiesto como ya explicamos anteriormente.

Es obligatorio el uso del atributo fork puesto que para ejecutar este jar la VM creará una nueva instancia. Como opción podemos usar el atributo maxmemory para indicar la máxima memoria que se reservará para la nueva instancia de la VM.

El resto será igual que en el caso anterior indicando los argumentos y añadiendo al classpath el elemento path que se definió anteriormente.

Usando ANT con JFlex y CUP

Como consecuencia de haber preparado la presentación para una asignatura sobre procesamiento de lenguajes vamos a tener un apartado extra en este tutorial. Este añadido tratará sobre como automatizar la utilización de Jflex (Generador de analizadores léxicos) y CUP (Generador de analizadores sintácticos).

Pues bien, lo primero que tendremos que hacer es decargar las librerías de JFlex y CUP para situar sendos Jar en la carpeta de librerías.

Conviene saber que ambos generadores contienen en el interior de sus librerías una tarea de ant, por lo que nuestro trabajo consistirá únicamente en usar dichas tareas.

Como vemos usamos el elemento taskdef y como atributos señalamos la carpeta de librerías que ya habíamos definido anteriormente en el apartado donde veíamos como usar librerías externas, posteriormente indicamos la clase en la que se encuentra esa tarea de ant y finalmente se indica el nombre bajo el que se usará esa tarea en el documento build.xml.

Mostramos ahora un objetivo encargado de la generación de los analizadores y posteriormente pasaremos a explicar cada uno de los atributos usados.

JFlex

En lo que se refiere a la tarea de jflex contamos con el atributo file en el cual se indica el fichero flex del que se partirá para la generación del analizador léxico, y finalmente destdir que indica el directorio en el que se generará el fichero java generado organizado en paquetes según se indique en el fichero flex.

CUP

En la tarea de CUP tenemos el atributo srcfile, equivalente al file de Jflex y destdir también equivalente al atributo del mismo nombre en Jflex. También se pueden usar otros atributos como interface para crear una interfaz java en vez de una clase. CUP también producirá su salida organizada en el paquete que se haya especificado en el fichero cup.

Recursos

Como parte de este tutorial dejaré aquí la presentación a modo de resumen y un proyecto de ANT como ejemplo.

En el proyecto de ejemplo se ha creado un objetivo de ant para explicar su uso, por lo que si queremos saber las opciones que tiene este fichero de configuración habrá que usar la siguiente orden en la consola situados en la carpeta del proyecto.


Hasta aquí este tutorial sobre ANT. Espero que os haya sido de utilidad, como siempre digo quedo abierto a todo tipo de sugerencias o adiciones; tenéis los comentarios a vuestra disposición.


Sin Comentarios

Trackbacks/Pingbacks

  1. Bitacoras.com - Información Bitacoras.com... Valora en Bitacoras.com: He dedicado tiempo ultimamente a aprender al menos de manera básica el uso ANT,…

Deja un comentario

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies, pinche el enlace para mayor información.

A %d blogueros les gusta esto: