El Classpath de GCJ

En esta entrada voy a ir completando lo comentado en la introducción a GCJ. Ya expliqué entonces como podemos compilar una clase sencilla, sin dependencias de otras, de manera que obtendremos un ejecutable de la misma manera que si utilizásemos otros lenguajes como C/C++.

La dependencia entre clases en Java se satisface a través del classpath, una variable de entorno (aunque hay otras formas de especificarlo) en la que se enumeran los directorios en los que se encuentran clases o paquetes utilizados. La comprobación se realiza, en el caso de Java, además de al compilar a bytecodes, en tiempo de ejecución de manera que si nos falta una clase, se nos lanzará una excepción del tipo classnotfound; con GCJ esto no es así.

En el caso de GCJ, la comprobación de las dependencias se hace únicamente durante la compilación de las clases mediante una implementación propia del classpath muy similar a la original del Java. Podemos indicarlo de varias maneras:

  • -Idir : Es la opción es la recomendada por los desarrolladores de GCJ, ya que es la que va a permitir diferenciar el classpath para las aplicaciones construidas a partir de este compilador de las que se construyan a partir de otros que también lo implementan.
  • –classpath=path: Mediante esta opción se establece el path del modo tradicional, separando los directorios por medio del símbolo ‘:’. Esta opción no sobrescribe el path por defecto para encontrar la librería de clases estándar que implementa GCJ.
  • –bootclasspath=path: Sustituye al path generado por defecto en el que se encuentran las clases estándar que componen el API de Java para GCJ.
  • CLASSPATH: Se trata de una variable de entorno a definir antes de la llamada al compilador y que mantiene una lista de directorios de la manera estándar.

Existe una prioridad entre cada una de estas posibles implementaciones.  De esta manera, es posible tener una implementación de una determinada clase agregada a la variable de entorno classpath, sin embargo, podremos compilar una aplicación que la utilice especificando una nueva implementación mediante el argumento -I. El orden de prioridades es el siguiente:

  1. En primer lugar irán los directorios especificados por medio del argumento -I.
  2. Se añaden los directorios especificados con la opción --classpath en caso de que haya sido definida.
  3. A continuación irán los directorios especificados en la variable de entorno CLASSPATH.
  4. Se añaden los directorios que están en la ubicación desde la que se llama a GCJ, es decir, el directorio ‘.’
  5. Si se ha especificado un valor para la opción --bootclasspath se anexa su valor, en caso contrario se agrega la ubicación por defecto de libgcj.jar.
  6. Si se especificó durante la compilación e instalación de GCJ, la opción --extdirs, se agregan al classpath los directorios que allí aparezcan.

Las clases que vayan definidas en los directorios incluidos en el classpath podrán ser código fuente o clases compiladas a bytecodes de Java. Vamos a ver un ejemplo sencillo de dos clases dependientes. En primer lugar, tenemos una clase Suma.java con un método que se encarga de sumar dos enteros pasados como parámetros:

// Suma.jav -> contiene un método para sumar dos enteros y devuelve el resultado
package ejemplo.blog;

public class Suma {
    public static int sumar (int a, int b) {
        int c = a+b;
        return c;
    }
}

A continuación tenemos otra clase que recibe dos cadenas como argumentos para hacerles un cast a enteros y sumarlos llamando al método de la clase Suma anterior.

// MiClase.java -> Suma dos números pasados como argumento
import ejemplo.blog.*;

class MiClase {
    public static void main(String args[]) {
        // Los dos números pasados como argumento los convertimos a enteros
        int a = Integer.parseInt(args[0]);
        int b = Integer.parseInt(args[1]);

        // Sumamos los dos números con la llamada al método Sumar.suma()
        int x = Suma.sumar(a, b);

        // Mostramos el resultado por pantalla
        System.out.println(x);
    }
}

La primera clase está ubicada en /home/elmo/miclase y la segunda se encuentra en /home/elmo/ejemplo/blog. Para el caso de la compilación tradicional en Java hemos de indicar la ubicación de las clases dependientes a través de la variable de entorno $CLASSPATH de modo que haremos:

$ cd /home/elmo/ejemplo/blog
$ javac Suma.java
$ cd /home/elmo/miclase
$ export CLASSPATH="/home/elmo/"
$ javac MiClase.java

Llegados a este punto, tenemos las clases compiladas a bytecodes. Hay que notar que, dado que en MiClase.java estamos importando las clases del paquete ejemplo.blog, la ruta indicada en el classpath será la que corresponde a la ubicación del paquete y no de la clase, es decir /home/elmo. Para ejecutar en Java tendríamos que indicar también en la variable de entorno dónde están todas las clases que vamos a utilizar por lo que haríamos:

$ export CLASSPATH=$CLASSPATH":/home/elmo/miclase"
$ java MiClase 5 7
12

Una vez visto cómo se hace en Java, vamos a ver como podemos compilar este ejemplo con GCJ. Vamos a indicar el classpath con el argumento -I que es la opción que recomiendan los desarrolladores. Por supuesto, la utilización en forma de paquetes es exactamente la misma por lo que las rutas de indicarán de la misma manera que tradicionalmente en Java.

$ export CLASSPATH=""
$ cd /home/elmo/ejemplo/blog
$ gcj -c Suma.java -o Suma.o
$ cd /home/elmo/miclase
$ gcj -c -I/home/elmo MiClase.java -o MiClase.o
$ cd /home/elmo
$ gcj --main=MiClase /home/elmo/miclase/MiClase.o /home/elmo/ejemplo/blog/Suma.o -o MiClase.out
$ ./MiClase 5 7
12

La primera línea la ejecutamos para borrar el classpath actual, luego compilamos a objeto el código fuente de la cada una de las clases. En el caso de MiClase.java indicamos la ruta del paquete que utiliza, ejemplo.blog, mediante el argumento -I/home/elmo. Por último hacemos el enlace indicando cual de las clases es la que contiene el método main de nuestro programa, en este caso MiClase. Es importante decir también que si hubiéramos hecho que MiClase.java fuera parte del paquete miclase, al indicar el main se haría por medio de --main=miclase.MiClase. En el caso de java tradicional la ejecución habría sido con java miclase.MiClase 5 7 y en el CLASSPATH en lugar de poner /home/elmo/miclase habría bastado con /home/elmo.

Espero que todo esto haya sido útil a quién lo lea y que si surge alguna duda o alguna corrección, dejéis un comentario.

Anuncios

7 pensamientos en “El Classpath de GCJ

  1. Muchas gracias por tu tutorial, creo que aun no nos hemos dado cuenta del potencial que significa gcj para el desarrollo de aplicaciones multiplataforma nativas. Lamentablemente la web va hacia los escritorios debido a el alto volumen de informacion que las aplicaciones manejan y las futuras PC se van a convertir en terminales web (retornamos a la epoca de los mainframes pero ahora mas distribuidos y con graficos).
    Saludos

  2. Me alegra que el tutorial te haya parecido bueno. Al fin alguien se ha animado a dejar un comentario después de la cantidad de visitas que ha tenido este post.

    La verdad es que GCJ es una herramienta con bastante potencial dentro de sus posibilidades. Eso sí, como ya he comentado, según mi experiencia le queda mucho que mejorar cuando la aplicación es muy pesada. En esos casos la máquina virtual de java desarrollada por Sun es mucho más rápida. Para aplicaciones pequeñas es una genialidad poder ejecutar Java nativamente.

    Un saludo !

  3. Elmo sé que el post es bastante viejo, sin embargo es ahora que estoy incursionando en gcj, por lo tanto estoy muy pendiente de la documentación y la tuya ha sido excelente, sin embargo, ¿no escribiste ningún post sobre como hacer un makefile?, lo pregunto porque lo comentaste en tu post de introducción a gcj

  4. Hola! Pues si que es bastante viejo el post… la verdad es que iba a poner el Makefile pero al final entre unas cosa y otras tengo esto muy abandonado. De todos modos si te interesa mucho puedo pasarte el Makefile que hice yo para compilar una librería bastante compleja (en cuanto a cantidad de archivos, paquetes, etc) por si te sirviera de ayuda.

    Saludos !

  5. Hola, espero aún tengas ese makefile. Tu post me ha resultado muy util y te agradezco enormemente.
    te dejo mi correo:
    fernandogrant(arroba)yahoo.com.ar

    saludos y todas las gracias

  6. Hola! No suelo entrar a mirar el blog así que no he visto el comentario hasta hoy. Tengo el Makefile en el portátil, mañana lo subo a una carpeta pública de Dropbox y pongo el enlace en el post que está muy solicitado!

    Saludos!

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s