2011-05-11 16 views
49

Cómo llamar a la función c desde Java. Parece que c está basado en el compilador.Llamada a la función c desde Java

Me gustaría llamar a la función C en Windows desde Java, y función GCC de Java también.

¿Alguna referencia?

+0

Es posible que quiera mirar en JNI (Java Native Interface). –

+1

Comenzaría con estos http://www.google.co.uk/search?q=JNI+tutorial –

+0

Ok. Muchas gracias. – Wen

Respuesta

54

Echa un vistazo a Java Native Interface: Getting Started.

2,1 Descripción general

[...] escribir una sencilla aplicación Java que llama a una función C para imprimir "Hello World!". El proceso consta de los siguientes pasos:

Cree una clase (HelloWorld.java) que declare el método nativo. Use javac para compilar el archivo fuente HelloWorld, lo que da como resultado el archivo de la clase HelloWorld.class. El compilador javac se suministra con JDK o Java 2 versiones de SDK. Use javah -jni para generar un archivo de encabezado C (HelloWorld.h) que contenga el prototipo de función para la implementación del método nativo . La herramienta java se proporciona con versiones de JDK o Java 2 SDK . Escriba la implementación C (HelloWorld.c) del método nativo . Compile la implementación de C en una biblioteca nativa, creando Hello-World.dll o libHello-World.so. Utilice el compilador de C y el vinculador disponibles en el entorno de host. Ejecute el programa HelloWorld utilizando el intérprete de tiempo de ejecución de java. Tanto el archivo de clase (HelloWorld.class) y la biblioteca nativa (HelloWorld.dll o libHelloWorld.so) se cargan en tiempo de ejecución. El resto de este capítulo explica estos pasos en el detalle .

2,2 declarar el método nativo

Se empieza por escribir el siguiente programa en el lenguaje de programación Java . El programa define una clase llamada HelloWorld que contiene un método nativo , imprimir.

class HelloWorld { 
    private native void print(); 

    public static void main(String[] args) { 
     new HelloWorld().print(); 
    } 

    static { 
     System.loadLibrary("HelloWorld"); 
    } 
} 

La definición de clase HelloWorld comienza con la declaración del método nativo de impresión. Esto es seguido por un método principal que instancia la clase Hello-World e invoca el método nativo de impresión para esta instancia. La última parte de la definición de clase es un inicializador estático que carga la biblioteca nativa que contiene la implementación del método nativo de impresión.

Existen dos diferencias entre la declaración de un método nativo , como la impresión y la declaración de métodos regulares en el lenguaje de programación Java . Una declaración de método nativo debe contener el modificador nativo . El modificador nativo indica que este método es implementado en otro idioma. Además, la declaración de método nativo finaliza con un punto y coma, el símbolo de terminador de declaración, porque no hay implementación para métodos nativos en la clase . Implementaremos el método de impresión en un archivo C separado.

Antes de que se pueda invocar la impresión del método nativo, se debe cargar la biblioteca nativa que implementa la impresión. En este caso, cargamos la biblioteca nativa en el inicializador estático de la clase HelloWorld. La máquina virtual Java ejecuta automáticamente el inicializador estático antes de invocando cualquier método en la clase HelloWorld, asegurando así que la biblioteca nativa se carga antes de llamar al método nativo de impresión.

Definimos un método principal para poder ejecutar la clase HelloWorld. Hello-World.main llama al método nativo para imprimir de la misma manera que que llamaría un método normal.

System.loadLibrary toma un nombre de biblioteca, localiza una biblioteca nativa que corresponde a ese nombre, y carga la biblioteca nativa en la aplicación . Discutiremos el proceso de carga exacto más adelante en el libro . Por ahora simplemente recuerde que para que System.loadLibrary("HelloWorld") tenga éxito, necesitamos crear una biblioteca nativa llamada HelloWorld.dll en Win32, o libHelloWorld.so en Solaris.

2.3 compilar la clase HelloWorld

Después de haber definido la clase HelloWorld, guarde el código fuente en un archivo llamado HelloWorld.java. A continuación, compile el archivo fuente usando el compilador javac que viene con la versión 2 del SDK de Java JDK o:

javac HelloWorld.java 

Este comando generará un archivo HelloWorld.class en el directorio actual.

2.4 Crear archivo de cabecera del método nativo

A continuación usaremos la herramienta javah para generar un archivo de cabecera de estilo JNI que es útil en la aplicación del método nativo en C. Puede ejecutar javah en el Hello-World la clase de la siguiente manera:

javah -jni HelloWorld 

el nombre del archivo de cabecera es el nombre de la clase con un ".h" adjunta al final de la misma. El comando que se muestra arriba genera un archivo llamado HelloWorld.h. No enumeraremos el archivo de encabezado generado en su totalidad aquí. La parte más importante del archivo de cabecera es el prototipo de función para Java_HelloWorld_print, que es la función C que implementa el método HelloWorld.print:

JNIEXPORT void JNICALL Java_HelloWorld_print (JNIEnv *, jobject); 

ignorar el JNIEXPORT y JNICALL macros por ahora. Puede haber notado que la implementación C del método nativo acepta dos argumentos aunque la declaración correspondiente del método nativo acepta sin argumentos. El primer argumento para cada implementación de método nativo es un puntero de interfaz JNIEnv.El segundo argumento es una referencia al objeto HelloWorld (algo así como el "this" puntero en C++). Discutiremos cómo utilizar el JNIEnv interfaz puntero y los argumentos jobject más adelante en este libro, pero este simple ejemplo ignora ambos argumentos.

2.5 Escribir la Implementación del Método Nativo

El archivo de cabecera de estilo JNI generada por javah le ayuda a escribir C o C++ para las implementaciones del método nativo. La función que escriba debe seguir el -prototipo especificado en el archivo de encabezado generado. Usted puede poner en práctica el método Hello-World.print en un archivo C HelloWorld.c como sigue:

#include <jni.h> 
#include <stdio.h> 
#include "HelloWorld.h" 

JNIEXPORT void JNICALL Java_HelloWorld_print(JNIEnv *env, jobject obj) { 
    printf("Hello World!\n"); 
    return; 
} 

La implementación de este método nativo es sencillo. Utiliza la función printf para mostrar la cadena "Hello World!" y luego regresa Como se mencionó anteriormente, se ignoran ambos argumentos, el puntero JNIEnv y la referencia al objeto.

El programa C incluye tres archivos de cabecera:

jni.h - Este fichero de cabecera proporciona información del código nativo necesita para llamar a funciones JNI. Al escribir métodos nativos, siempre debe incluir este archivo en sus archivos fuente C o C++. stdio.h - El código snippet anterior también incluye stdio.h porque utiliza la función printf . HelloWorld.h - El archivo de encabezado que generó usando javah. Incluye el prototipo C/C++ para la función Java_HelloWorld_print . 2.6 Compilar el C Fuente y crear una biblioteca nativa

Recuerde que cuando se creó la clase HelloWorld en el archivo HelloWorld.java, que incluyó una línea de código que carga un biblioteca nativa en el programa:

System.loadLibrary("HelloWorld"); 

Ahora que está escrito todo el código C necesario , debe compilar Hello-World.c y compilar esta biblioteca nativa .

Diferentes sistemas operativos admiten diferentes formas de compilar bibliotecas nativas. En Solaris, el siguiente comando crea una biblioteca compartida llamada libHello-World.so:

cc -G -I/java/include -I/java/include/solaris HelloWorld.c -o libHelloWorld.so 

La opción -G indica al compilador C para generar una biblioteca compartida en lugar de un archivo normal de Solaris ejecutable. Debido a la limitación del ancho de página en este libro, , rompemos la línea de comando en dos líneas. Debe escribir el comando en una sola línea o colocar el comando en un archivo de script.En Win32, el siguiente comando construye una librería de enlace dinámico (DLL) HelloWorld.dll usando el compilador de Visual C++ de Microsoft:

cl -Ic:\java\include -Ic:\java\include\win32 -MD -LD HelloWorld.c -FeHelloWorld.dll 

La opción -MD asegura que HelloWorld.dll está vinculado con la biblioteca C multiproceso Win32. La opción -LD indica al compilador de C que genere una DLL en lugar de un ejecutable regular de Win32. Por supuesto, tanto en Solaris como en Win32, usted necesita incluir las rutas de acceso que reflejan la configuración en su propia máquina .

2.7 Ejecutar el Programa

En este punto, usted tiene los dos componentes listos para ejecutar el programa. El archivo de clase (HelloWorld.class) llama a un método nativo y la biblioteca nativa (Hello-World.dll) implementa el método nativo.

Porque la clase HelloWorld contiene su propio método principal, puede ejecutar el programa en Solaris o Win32 de la siguiente manera:

java HelloWorld 

debería ver el siguiente resultado:

Hello World! 

Es Es importante establecer correctamente la ruta de la biblioteca nativa para que se ejecute su programa. La ruta de la biblioteca nativa es una lista de directorios que la máquina virtual Java busca al cargar bibliotecas nativas. Si usted no tiene una ruta de biblioteca nativa estableció correctamente, entonces usted verá un error similar al siguiente:

java.lang.UnsatisfiedLinkError: no HelloWorld in library path 
     at java.lang.Runtime.loadLibrary(Runtime.java) 
     at java.lang.System.loadLibrary(System.java) 
     at HelloWorld.main(HelloWorld.java) 

Asegúrese de que la biblioteca nativa reside en uno de los directorios de la ruta de biblioteca nativa. Si está ejecutando en un sistema Solaris, la variable de entorno LD_LIBRARY_PATH se usa para definir la ruta de la biblioteca nativa. Asegúrese de que incluya el nombre del directorio que contiene el archivo libHelloWorld.so. Si el archivo libHelloWorld.so está en el directorio actual , puede emitir los dos comandos siguientes en el estándar de shell (sh) o KornShell (ksh) para establecer la variable LD_LIBRARY_PATH entorno adecuadamente:

LD_LIBRARY_PATH=. 
export LD_LIBRARY_PATH 

El equivalente mando en el shell C (csh) es el siguiente:

setenv LD_LIBRARY_PATH . 

Si está ejecutando en un equipo Windows 95 o Windows NT máquina, asegúrese de que está en t HelloWorld.dll El directorio actual , o en un directorio que se enumera en la variable de entorno PATH .

En Java 2 SDK 1.2 de liberación, también puede especificar la ruta de biblioteca nativa en la línea de comandos Java como una propiedad del sistema de la siguiente manera:

java -Djava.library.path=. HelloWorld 

El "-D" opción de línea de comandos establece una propiedad del sistema plataforma Java. Establecer la propiedad java.library.path en "." indica a la máquina virtual Java que busque bibliotecas nativas en el directorio actual.

+0

Los usuarios de Mac pueden ignorar los comandos de Solaris. Este blog me ayudó a terminar lo que ayudó a comenzar esta respuesta: http://nerdposts.blogspot.com/2010/10/jni-mac-os-x-simple-sample.html – cloudsurfin

11

En términos simples, solo asegúrese de cargar la biblioteca relevante que contiene la definición de función, cargar la biblioteca que sigue la especificación JNI y envolver la función objetivo desde la primera biblioteca, exponer métodos nativos de su clase Java y Usted debe ser bueno para ir.

Lo recomiendo contra raw JNI ya que contiene un montón de código repetitivo y terminará maldiciéndose a sí mismo si comienza a envolver una gran biblioteca C grande. De todos modos, siéntase libre de meterse en JNI cuando empiece, pero use algo como JNA en lo que respecta al trabajo real.

+0

¿JNA es tan rápido como JNI? – Pacerier

0

JNI - Java Native Interface

Con el fin de llamar a la función C de Java es necesario utilizar JNI

3

usted las opciones incluyen:

Java Native Interface
véase: https://en.wikipedia.org/wiki/Java_Native_Interface

cita:

JNI permite a los programadores escribir métodos nativos para manejar situaciones cuando una aplicación no puede escribirse completamente en el lenguaje de programación Java, p. cuando la biblioteca de clases estándar de Java no es compatible con las características específicas de la plataforma o biblioteca de programas

Java Native Access

véase: https://en.wikipedia.org/wiki/Java_Native_Access

cita:

Java Native Access es una biblioteca desarrollada por la comunidad que proporciona a los programas Java fácil acceso a bibliotecas compartidas nativas sin usar Java Nat Interfaz.

JNR-FFI

véase: https://github.com/jnr/jnr-ffi

cita:

JNR-fi es una biblioteca Java para cargar bibliotecas nativas sin necesidad de escribir código JNI a mano, o usando herramientas como SWIG.

+0

¿Entonces JNR diff JNA es? – Pacerier

0

Para hacer DLL de 64 bits compatibles Quitar "-MD" opción en las siguientes afirmaciones

"cl ic: \ java \ include -Ic: \ java \ include \ win32 -MD -LD HelloWorld.c -FeHelloWorld.dll "

0

Tengo una solución para este problema. Lo que necesita asegurarse es compilar el código utilizando un compilador de C++ de 64 bits para llamar a la función java que se ejecuta en el JRE de 64 bits. Junto con esto, debemos guardar la ruta del archivo dll creado en "Ruta" en "Variable de entorno".

1

Si se está empleando gcc de Windows y MinGW es posible que tenga la bandera adicional si usted está recibiendo UnsatisfiedLinkError para el método específico en lib:

gcc -D_JNI_IMPLEMENTATION_ -Wl,--kill-at -I"%JAVA_HOME%"\include -I"%JAVA_HOME%"\include\win32 BestCode.c -shared -o BestCode.dll 
0

En primer lugar hacer garantizar a cargar su biblioteca nativa o un archivo .dll en la ruta de clase mediante el establecimiento de ruta en la propiedad java.library.path

a continuación, utilice System.loadLibrary()

Do not use .dll extension at the end. 
Cuestiones relacionadas