Articulo de referencia

Compilador GNU para Java

{{cite web|url=https://gcc.gnu.org/news/gcj-announce.txt|author=Anthony Green, Cygnus Solutions|title=GCJ announcement}} "},"discontinued":{"wt":"yes"},"latest release version":...

El compilador GNU para Java ( GCJ ) es un compilador gratuito descontinuado para el lenguaje de programación Java . Formaba parte de la Colección de Compiladores GNU . [ 2 ] [ 3 ]

GCJ compila el código fuente de Java a bytecode de la máquina virtual de Java (JVM) o a código máquina para diversas arquitecturas de CPU . También puede compilar archivos de clase y JAR completos que contienen bytecode a código máquina. [ 4 ] [ 5 ]

Historia

El código fuente original de las bibliotecas de tiempo de ejecución de GCJ proviene del proyecto GNU Classpath , pero existe una diferencia de código entre las bibliotecas libgcj . GCJ 4.3 utiliza el compilador Eclipse para Java como interfaz. [ 6 ]

En 2007, se trabajó mucho para implementar soporte para las dos API gráficas de Java en GNU Classpath : AWT y Swing . El soporte de software para AWT era incompleto. "Una vez que el soporte para AWT funcione, se podrá considerar el soporte para Swing. Hay al menos una implementación parcial de software libre de Swing que podría ser utilizable." [ 7 ] Para cuando se eliminó, GCC tenía soporte para hasta la versión 1.4 de Java (y por lo tanto carecía de soporte para la mayoría de las características posteriores, como genéricos , anotaciones o módulos JPMS ; a pesar de esto, se implementaron partes de la biblioteca java.nio ). [ 8 ] GNU Classpath nunca se completó ni siquiera al estado de Java 1.2 y ahora parece haber sido abandonado por completo.

Hasta 2015, no se anunciaron nuevos desarrollos de GCJ y el producto estaba en modo de mantenimiento , mientras que el desarrollo de la cadena de herramientas Java de código abierto se realizaba principalmente dentro de OpenJDK . [ 9 ] GCJ fue eliminado del tronco de GCC el 30 de septiembre de 2016. [ 10 ] [ 11 ] El anuncio de su eliminación se realizó con el lanzamiento de GCC 7.1, que no lo contiene. [ 12 ] GCJ sigue siendo parte de GCC 6.

Actuación

La función de compilación en GCJ debería tener un tiempo de inicio más rápido que el bytecode equivalente lanzado en una JVM al compilar código Java a código máquina. [ 13 ]

Interfaz nativa compilada

La Interfaz Nativa Compilada ( CNI ), anteriormente llamada "Interfaz Nativa de Cygnus", es un marco de software para GCJ que permite que el código Java llame y sea llamado por aplicaciones nativas (programas específicos de una plataforma de hardware y sistema operativo) y bibliotecas escritas en C++ . [ 14 ] Podía funcionar con C++ hasta C++17 (la última versión de C++ compatible con GCC 6.5, la versión final de GCJ).

CNI se asemeja mucho al marco de trabajo de la Interfaz Nativa de Java (JNI), que viene de serie con varias máquinas virtuales de Java .

GCJ admite además un " enlace Java " con , que se utiliza al hacer referencia a código Java compilado por GCJ y utilizado en código C++ para indicar que un símbolo que se consume proviene de Java. [ 15 ]extern"Java"

Por ejemplo, considere el siguiente código Java:

paquete org.wikipedia.examples ;clase pública Foo { int público agregar ( int a , int b ) { return a + b ; } }

Luego, desde C++ se puede consumir de la siguiente manera:

#include <gcj/cni.h> #include <java/lang/Object.h>// Encabezado generado automáticamente #include <org/wikipedia/examples/Foo.h>using namespace java :: lang ;usando org :: wikipedia :: ejemplos :: Foo ;extern "Java" {int addThroughJava ( int a , int b ) { Foo * foo = new Foo (); return foo -> add ( a , b ); // Nota: foo no debe eliminarse, ya que es recolectado por el recolector de basura }namespace org :: wikipedia :: examples { // Herencia de un objeto Java // Solo se admite la herencia simple class Bar : public Object { // ... }; }}

Una implementación de libjava (que contiene los encabezados de C++ para la biblioteca de clases de Java ) se puede encontrar aquí (en una versión de GCC 6). Las clases de Java se exponen a C++ como archivos de encabezado (autogenerados) por una clase por encabezado [ 16 ] , preservando la estructura de espacios de nombres por paquete de Java . [ 17 ]

Todos los tipos de referencia de Java Xse traducen a un puntero X*en C++. Por ejemplo, java.lang.Stringse convierte en java::lang::String*. [ 18 ] Debido a que las clases de Java son administradas por el recolector de basura de Java , no deben eliminarse usando el deleteoperador de C++, aunque ambas se instancian usando new[ 19 ] ; los objetos de Java son eliminados automáticamente por el recolector de basura. [ 20 ] Las clases de Java, cuando se usan en C++, mantienen el mismo orden y alineación de campos, y no ampliarán los tipos nativos de 8 bits y 16 bits a 32 bits. [ 21 ]

La reflexión de Java sobre objetos Java en C++ es posible usando CNI, que incluye jfieldIDy jmethodID(como se ve en JNI). [ 22 ] (Java ya ofrece java.lang.reflect.Field/ java.lang.reflect.Method, pero estos no son utilizados por GCJ). Si bien los genéricos de Java nunca se implementaron para cuando se eliminó GCJ, se habían llevado a cabo algunas discusiones sobre cómo operarían con C++ (por ejemplo, traduciendo directamente los genéricos a plantillas u omitiéndolos por completo, lo que hace la JVM en tiempo de ejecución).

Los tipos primitivos de Java pueden mapearse exactamente a los tipos primitivos correspondientes de C/C++. Sin embargo, en el caso de que no lo hagan (ya que C/C++ no especifica el ancho exacto de los tipos enteros), se proporcionan definiciones de tipo como sigue: [ 23 ]

voidSe corresponden exactamente igual entre lenguajes, ya que no hacen referencia a ningún valor. Se recomendó usar estos typedefs de Java en lugar de los tipos nativos de C++ para evitar posibles errores. [ 23 ]

Los arrays de Java se implementan con la plantilla de clase JArray<T>y heredan java::lang::Object(e implementan ). Se proporcionan definiciones de tipo adicionales para cada puntero a array de tipos primitivos de Java. [ 24 ]operator[]

Las funciones variádicas en Java se representan internamente como matrices; por lo tanto, en GCJ una firma con un parámetro variádico como se genera como .voidf(T...args);voidf(JArray<T>args);

Además, las clases comunes reciben los siguientes typedefs: [ 18 ]

Tenga en cuenta que en JNI, jobjecty jstringeran jclassmanejadores opacos sin ningún dato [ 25 ] [ 26 ] ; en CNI, las clases Java a las que apuntan tienen datos.

Además, todas las clases de Java Xexponen un campo estático en C++, que se comporta de forma equivalente a en Java. Sin embargo, el campo es de tipo (no ). Java se tradujo originalmente al C++ más antiguo (sin embargo, la constante de puntero nulo puede sustituirse debido a conversiones implícitas). [ 27 ] Las clases adicionales, y denotan respectivamente tipos de referencia no escaneados (que no serán comprobados por el compilador y pueden almacenar cualquier estructura de datos de C/C++), y datos que pueden ser marcados por el administrador de memoria y ser recolectados por el recolector de basura. [ 28 ]X::class$X.classclass$java::lang::Classjava::lang::Class*nullNULLnullptrgnu::gcj::RawDatagnu::gcj::RawDataManaged

En C++, java::lang::String*(o jstring) deben crearse manualmente utilizando funciones de utilidad CNI (análogas a las de JNI); no pueden convertirse implícitamente desde o C++ . [ 29 ]constchar*std::string

Los bloques Java synchronizedse implementan en C++ utilizando la ::JvSynchronizeclase (que reside en el espacio de nombres global). [ 30 ] Por ejemplo, lo siguiente es equivalente a Javasynchronized(obj){/* code... */}

{ JvSynchronize _ ( obj ); // crea un bloqueo ficticio, destruido al finalizar el ámbito // código... }

En C++, cualquier clase que aplique el modelo de herencia de Java debe heredar de la java::lang::Objectclase base y puede heredar como máximo una clase base. Aunque estaba previsto, la compatibilidad con la herencia de interfaces nunca se implementó en GCJ antes de su eliminación. [ 31 ] A pesar de esto, existía un atributo para marcar una clase como una interfaz de Java, junto con una pragma . [ 15 ] Sin embargo, se podían implementar métodos de interfaces, pero llamar a un método de una superinterfaz requería convertir la clase de nuevo a la superinterfaz. [ 31 ] Además, los especificadores de acceso de Java nunca se aplicaron estrictamente en C++; solo los campos y métodos de Java se mapeaban correctamente a en C++, pero todo lo demás se mapeaba a . [ 21 ][[gnu::java_interface]]#pragma interfaceprivateprivatepublic

Los métodos se corresponden directamente entre Java y C++ con los mismos nombres y tipos correspondientes, y se conservan los métodos estáticos (que aún se llaman ::para su resolución). La modificación de nombres para los métodos sobrecargados utiliza el mismo esquema de codificación entre Java y C++. Si bien Java no permite que un constructor sea un método nativo en sí mismo, un constructor puede llamar a un método nativo. [ 32 ]

La asignación fallida de una clase Java generará una excepción java::lang::OutOfMemoryError. [ 33 ]

libgcj utiliza internamente señales POSIX , y el uso de la misma señal puede interferir con libgcj o incluso provocar su fallo. Por ejemplo,genera una señal,utiliza otra señal, mientras que otras señales (potencialmente dependientes de la plataforma) pueden ser utilizadas por el gestor de memoria o. [ 28 ]SIGSEGVjava::lang::NullPointerExceptionjava::lang::Runtime::exec()SIGCHLDjava::lang::Thread::interrupt()

Comparación del uso del lenguaje

Los autores de CNI afirman varias ventajas sobre JNI: [ 34 ]

Utilizamos CNI porque creemos que es una mejor solución, especialmente para una implementación de Java basada en la idea de que Java es simplemente otro lenguaje de programación que puede implementarse mediante técnicas de compilación estándar. En consecuencia, y considerando que los lenguajes implementados con GCC deben ser compatibles cuando sea pertinente, se deduce que la convención de llamada de Java debe ser lo más similar posible a la utilizada en otros lenguajes, especialmente C++, ya que podemos considerar Java como un subconjunto de C++. CNI es simplemente un conjunto de funciones auxiliares y convenciones basadas en la idea de que C++ y Java comparten la misma convención de llamada y estructura de objetos; son compatibles a nivel binario. (Esta es una simplificación, pero bastante acertada).

CNI depende de que las clases Java aparezcan como clases C++ . Por ejemplo, [ 35 ] dada una clase Java,

paquete org.wikipedia.examples ;clase pública MyInteger { int i privado ;public MyInteger ( int i ) { this . i = i ; }public int obtener () { return i ; }public void set ( int j ) { i = j ; }public static final MyInteger ZERO = new MyInteger ( 0 ); }

Se puede utilizar la clase de la siguiente manera:

#include <gcj/cni.h> #include <org/wikipedia/examples/MyInteger.h>usando org :: wikipedia :: ejemplos :: MyInteger ;MyInteger * mult ( MyInteger & p , jint k ) { if ( k == 0 ) { return MyInteger :: ZERO ; // Acceso a miembro estático. }return new MyInteger ( p.get ( ) * k ) ; }

GCJ permite el uso de excepciones de Java en C++, pero no se pueden usar en la misma unidad de traducción que las excepciones de C++. [ 36 ] Se debe usar la pragma para asegurar que se llamen a los destructores al propagar una excepción de Java a través de C++. [ 37 ] A pesar de esto, nunca se incluyó soporte para bloques. Las excepciones de Java se capturan por puntero en lugar de por referencia, porque las referencias de Java se representan en CNI a través de punteros. Además, no están calificadas porque los objetos de Java son referencias inherentemente mutables. [ 38 ]#pragma GCC java_exceptionsfinallyconst

Por ejemplo, lo siguiente captura una excepción de Java, mientras se utiliza la API de invocación: [ 27 ]

#pragma GCC java_exceptions#include <gcj/cni.h> #include <java/lang/Integer.h> #include <java/lang/Math.h> #include <java/lang/NumberFormatException.h> #include <java/lang/String.h> #include <java/lang/System.h> #include <java/io/File.h> #include <java/io/IOException.h> #include <java/net/URI.h>using namespace java :: lang ; using java :: io :: File ; using java :: io :: IOException ; using java :: net :: URI ;// Literal auxiliar para crear java::lang::String* String * operator "" _js ( const char * s , [[ maybe_unused ]] size_t len ​​) { return :: JvNewStringLatin1 ( s ); }int main ( int argc , char * argv []) { try { :: JvCreateJavaVM ( nullptr ); :: JvAttachCurrentThread ( nullptr , nullptr ); :: JvInitClass ( & System :: class $ ); :: JvInitClass ( & Math :: class $ ); JArray < String *>* args = :: JvConvertArgv ( argc , argv ); // String[] argsjdouble one = Math :: sin ( Math :: PI / 2 ); URI * location = new URI ( "file:///C:/temp/example.txt" _js ); File * file = new File ( location ); System :: out -> println ( file -> getAbsolutePath ());String * invalid = "no es un número" _js ; jint result = Integer :: parseInt ( invalid ); } catch ( NumberFormatException * e ) { System :: err -> println ( "Error al formatear el número: " _js -> concat ( e -> getMessage ())); e -> printStackTrace (); } catch ( IOException * e ) { System :: err -> println ( "Error en la operación de E/S: " _js -> concat ( e -> getMessage ())); e -> printStackTrace (); } return 0 ; }

Tenga en cuenta que las clases Java con campos estáticos, como java::lang::Systemy java::lang::Math, deben inicializarse primero mediante una ::JvInitClass()llamada a una función.

Véase también

Notas

  1. Tenga en cuenta que, como los genéricos nunca se implementaron en GCJ,Classno tenían parámetros de plantilla .

Referencias

  1. Anthony Green, Cygnus Solutions. "Anuncio de GCJ" .
  2. "GCJ: El compilador GNU para Java - Proyecto GNU - Fundación del Software Libre (FSF)" . Archivado del original el 9 de mayo de 2007. Consultado el 22 de abril de 2010 .
  3. Campbell, Bill (2013). Introducción a la construcción de compiladores en un mundo Java . CRC Press Taylor & Francis Group. ISBN 978-1-4398-6088-5. Consultado el 6 de febrero de 2014 .
  4. "Compilando Java con GCJ | Linux Journal" .
  5. "Compilador GNU para Java" .
  6. "gcj utilizará el compilador Eclipse como interfaz" . 8 de enero de 2007. Archivado del original el 9 de mayo de 2007. Consultado el 20 de mayo de 2007 .
  7. Preguntas frecuentes del GCJ
  8. Wiki de GCC (7 de agosto de 2017). "GCJ - Wiki de GCC" . gcc.gnu.org . Proyecto GNU.
  9. GCC busca desactivar Java y reemplazarlo con Go o ADA.
  10. Andrew Haley (30 de septiembre de 2016). " [ gcc ] Revisión 240661" .
  11. Tromey, Tom (2 de octubre de 2016). "La eliminación de gcj" . The Cliffs of Inanity . Recuperado el 3 de octubre de 2016 .
  12. "Serie de lanzamientos de GCC 7: cambios, nuevas características y correcciones" . Consultado el 9 de mayo de 2017 .
  13. "GCJ: El compilador estático de Java de GNU" (PDF) . Archivado del original (PDF) el 7 de junio de 2011. Consultado el 2 de agosto de 2009 .
  14. Bothner, Per (enero de 2003). "Compilación de Java con GCJ". Linux J. 2003 ( 105). Belltown Media: 4. ISSN 1075-3583 . 
  15. 1 2 Proyecto GNU. "7.7 Atributos de variables, funciones y tipos específicos de C++" . gcc.gnu.org . Proyecto GNU . Consultado el 19 de mayo de 2026 .
  16. Proyecto GNU. "11.1 Conceptos básicos" . gcc.gnu.org . Proyecto GNU . Consultado el 22 de mayo de 2026 .
  17. Proyecto GNU. "Paquetes 11.2" . gcc.gnu.org . Proyecto GNU . Consultado el 22 de mayo de 2026 .
  18. 1 2 Proyecto GNU. "11.4 Tipos de referencia" . gcc.gnu.org . Proyecto GNU . Consultado el 22 de mayo de 2026 .
  19. Proyecto GNU. "Inicialización de clase 11.7" . gcc.gnu.org . Proyecto GNU . Consultado el 22 de mayo de 2026 .
  20. Proyecto GNU. "11.8 Asignación de objetos" . gcc.gnu.org . Proyecto GNU . Consultado el 22 de mayo de 2026 .
  21. 1 2 Proyecto GNU. "11.6 Objetos y clases" . gcc.gnu.org . Proyecto GNU . Consultado el 22 de mayo de 2026 .
  22. Proyecto GNU. "11.17 Reflection" . gcc.gnu.org . Proyecto GNU . Consultado el 22 de mayo de 2026 .
  23. 1 2 Proyecto GNU. "11.3 Tipos primitivos" . gcc.gnu.org . Proyecto GNU . Consultado el 22 de mayo de 2026 .
  24. Proyecto GNU. "11.10 Arrays" . gcc.gnu.org . Proyecto GNU . Consultado el 22 de mayo de 2026 .
  25. ^ OpenJDK (13 de noviembre de 2024). "openjdk/jdk-jni.h" . github.com . AbiertoJDK.
  26. Benjamin Crawford Pierce. "Programación JNI en C++" . cis.upenn.edu . Universidad de Pensilvania . Consultado el 12 de junio de 2026 .
  27. 1 2 Proyecto GNU. "11.16 Invocación" . gcc.gnu.org . Proyecto GNU . Consultado el 22 de mayo de 2026 .
  28. 1 2 Proyecto GNU. "11.13 Interoperabilidad con C/C++" . gcc.gnu.org . Proyecto GNU . Consultado el 22 de mayo de 2026 .
  29. Proyecto GNU. "11.12 Strings" . gcc.gnu.org . Proyecto GNU . Consultado el 22 de mayo de 2026 .
  30. Proyecto GNU. "Sincronización 11.15" . gcc.gnu.org . Proyecto GNU . Consultado el 22 de mayo de 2026 .
  31. 1 2 Proyecto GNU. "Interfaces 11.5" . gcc.gnu.org . Proyecto GNU . Consultado el 22 de mayo de 2026 .
  32. Proyecto GNU. "Métodos 11.11" . gcc.gnu.org . Proyecto GNU . Consultado el 22 de mayo de 2026 .
  33. Proyecto GNU. "11.9 Asignación de memoria" . gcc.gnu.org . Proyecto GNU . Consultado el 22 de mayo de 2026 .
  34. Preguntas frecuentes de GCJ – Proyecto GNU – Fundación del Software Libre (FSF)
  35. El ejemplo proviene de: https://gcc.gnu.org/onlinedocs/gcj/Objects-and-Classes.html#Objects-and-Classes Archivado el 20/10/2016 en Wayback Machine
  36. Proyecto GNU. "Excepciones de Java 6.10" . gcc.gnu.org . Proyecto GNU . Consultado el 21 de mayo de 2026 .
  37. Tom Tromey (27 de junio de 2011). "GNU gcj" (PDF) . Proyecto GNU.
  38. Per Bothner; Tom Tromey (abril de 2001). "Integración Java/C++: Escritura de métodos Java nativos en C++ natural" (PDF) . Actas del Primer Simposio de Investigación y Tecnología de la Máquina Virtual Java . Monterey, California: USENIX.
  • Sitio web oficial . GCC . GNU. 30 de marzo de 2007. Archivado del original el 9 de mayo de 2007.
  • "Manual GCJ" . Archivado del original el 22 de agosto de 2016.
  • "Documentación de GCC - 11 Acerca de CNI" . GCC . Proyecto GNU. 26 de octubre de 2018. Archivado del original el 11 de diciembre de 2025.
  • Wielaard, Mark (6 de abril de 2005). "GCJ: pasado, presente y futuro" . LWN. Archivado del original el 2 de agosto de 2019.