dúvida com JNI(RESOLVIDO)

Olá pessoal, estou precisando criar uma aplicação com JNI porém não estou conseguindo.
Estou seguindo o tutorial http://javafree.uol.com.br/artigo/13913/JNI-Java-Native-Interface.html

Na horá de compilar, aparece a seguinte mensagem:

/tmp/cckCgXyx.o:(.data+0x28): undefined reference to `hidden alias for int BemVindo::main()'
/tmp/cckCgXyx.o:(.data+0x74): undefined reference to `hidden alias for int BemVindo::main()'
collect2: ld returned 1 exit status

O código é esse:


public class BemVindo{
        public native int main();
        static{
                System.loadLibrary("hello");
        }
        public static void main(String args[]){
                new BemVindo().main();

        }

}

Aguardo resposta

Olá cotonety,

Olhando bem rapidamente o seu problema, talvez o que esteja acontecendo é que você declarou a função “nativa” com o nome main (palavra reservada em C++ e Java).

Tente mudar o nome desta função em public native int main(); para ver se funciona

[]'s

eu estava fazendo outro exemplo…e foi dando certo.
porém, no final quando eu vou chamar o programa, aparece o seguinte erro:

Exception in thread "main" java.lang.UnsatisfiedLinkError: libCarnival: libCarnival.so: Não é possivel abrir arquivo de objetos compartilhado: Arquivo ou diretório não encontrado
   at java.lang.Runtime._load(libgcj.so.10)
   at java.lang.Runtime.loadLibrary(libgcj.so.10)
   at java.lang.System.loadLibrary(libgcj.so.10)
   at Carnival.<clinit>(Carnival.java:6)
   at java.lang.Class.initializeClass(libgcj.so.10)

e então…alguem pode me ajudar?
estou no linux

Tem como você postar seu código em C++ e em Java, e também o comando que você está utilizando para compilar?

Eu já quebrei um pouco a cabeça com JNI, quem sabe eu consiga te ajudar…

Código em C

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

JNIEXPORT void JNICALL
Java_Carnival_dance(JNIEnv * env, jobject obj, jstring verse)
{
    const char * vstr = (*env)->GetStringUTFChars(env, verse, NULL);
    printf("%s\n", vstr);
    return;
}

Código em java

public class Carnival
{

// Carregamento da biblioteca que será criada.
static {
System.loadLibrary("Carnival");
}

// Método marcado com modificador "native".
public native void dance(String verse);

public static void main(String[] args) {
new Carnival().dance("...pode chorar, mas chora...");
}
}

comando

gcc -o lib/libCarnival.so -shared -Wl,-soname,libCarnival.so \
-I/opt/jdk/include \
-I/opt/jdk/include/linux Carnival.c \
-static -lc

Olá cotonety,

Olha só, o erro também aconteceu comigo, e era porque eu não tinha a pasta lib do local que eu estava compilando o código C.

Agora, eu não consegui fazer rodar perfeitamente o programa com o método System.loadLibrary, por isso modifiquei para System.load. A diferença é que este método exige o caminho completo do arquivo, diferente do loadLibrary, que exige o nome da biblioteca.

Então meu código Java ficou assim:

import java.io.File;


public class Carnival {

	// Método marcado com modificador "native".
	public native void dance(String verse);


	// Carregamento da biblioteca que será criada.
	static {
        System.load("/tmp/libCarnival.so");
	}

	public static void main(String[] args) {
		new Carnival().dance("...pode chorar, mas chora...");
	}
}

e para compilar a lib ficou assim:

	gcc -o /tmp/libCarnival.so -shared -shared -Wl,-soname,libCarnival.so -I/usr/lib/jvm/jdk1.6.0_21/include -I/usr/lib/jvm/jdk1.6.0_21/include/linux Carnival.c -static -lc

Observe que estou gerando a bibioteca em “/tmp” e ao carregá-la, também indico este caminho.

Espero ter ajudado.
Até mais.

[quote=cotonety]Olá pessoal, estou precisando criar uma aplicação com JNI porém não estou conseguindo.
Estou seguindo o tutorial http://javafree.uol.com.br/artigo/13913/JNI-Java-Native-Interface.html

Na horá de compilar, aparece a seguinte mensagem:

/tmp/cckCgXyx.o:(.data+0x28): undefined reference to `hidden alias for int BemVindo::main()'
/tmp/cckCgXyx.o:(.data+0x74): undefined reference to `hidden alias for int BemVindo::main()'
collect2: ld returned 1 exit status

O código é esse:


public class BemVindo{
        public native int main();
        static{
                System.loadLibrary("hello");
        }
        public static void main(String args[]){
                new BemVindo().main();

        }

}

Aguardo resposta[/quote]

Vê se te ajuda:
http://www.guj.com.br/java/229892-resolvidoerro-ao-carregar-dll-no-java#1180355

Joyle

tem que ser com JNI. Não pode JNA.

mrsuzuki

Fiz do jeito que você disse, porém, deu o mesmo erro

Oi cotonety,

O erro que você se refere é: “Não é possivel abrir arquivo de objetos compartilhado

Se sim, verifique se ao executar a linha:

gcc -o /tmp/libCarnival.so -shared -shared -Wl,-soname,libCarnival.so -I/usr/lib/jvm/jdk1.6.0_21/include -I/usr/lib/jvm/jdk1.6.0_21/include/linux Carnival.c -static -lc

Existe em seu linux o diretório /tmp.
Se existir, verifique se o seu usuário tem permissão de escrita para este diretório.

Em todo o caso, você pode mudar este diretório para um outro caminho, porém terá que mudar no código java também.

[]'s

Consegui resolver o tutorial.
Agora estou com problema em relação ao meu código em C, com o método da JNI

aonde que eu coloco a função que eu quero?


JNIEXPORT void JNICALL
Java_Carnival_dance(JNIEnv * env, jobject obj, jstring verse)
{
   //AQUI?
}

Exato. Quando você executa o “javah”, ele cria a assinatura do método em C, que será chamado pelo Java.
Repare que o(s) parâmetro(s) que você passou ao chamar o método em Java vem logo após os parâmetros “env” e “obj”

no caso a minha aplicação está assim:


int main (int argc, char **argv){
   drawText( &argc, &argv, "TESTE" );
   return 0;

}  

static void drawText(int *argc, char **argv[], char *texto){
...
...
...

O problema é que eu quero utilizar apenas a função drawText.
Como faço?

Quando precisei utilizar JNI, fiz da seguinte forma (talvez seja uma boa solução para você também).

1 - No Java, criei como seria a chamada do método, com os parâmetros necessários. No seu caso talvez seria:

public native void dance(int argc, String args[], String texto);  

2 - Criei a assinatura do método com o javah

3 - Depois, no método em C com a assinatura criada, simplesmente chamei a minha função em C, que já estava pronta. No seu caso, talvez algo do tipo (não sei se o javah irá gerar isso, estou tirando da minha cabeça):

JNIEXPORT void JNICALL Java_Carnival_dance(JNIEnv * env, jobject obj, jint argc, jstring args[], jstring texto)  {  
    //Atribua os parâmetros argc, args e texto
    //Chame sua função drawText aqui.
}  

Com isso, você cria uma interface entre o código Java e o código C, porém não mexe na sua função que já está pronta.

[]'s

eu entendi a idéia…porém aparece o seguinte erro:


public class App{

	// Carregamento da biblioteca que será criada.
	static {
	System.loadLibrary("AppDrawText");
	}

	// Método marcado com modificador "native".
	public native void drawText(int argc, String args[], String texto);

	public static void main(String[] args) {
		new AplicacaoLavid().drawText("TESTE");
	}
}
App.java:12: error: The method drawText(int, String[], String) in the type App is not applicable for the arguments (String)
	new App().drawText("TESTE");
	                     ^^^^^^^^
1 problem (1 error)

Então cotonety,

Tem 2 coisas:

  1. O nome da sua classe é “App” e você está chamando o método AplicacaoLavid

  2. Você declarou seu método como

public native void drawText(int argc, String args[], String texto);

Porém você só está passando 1 parâmetro (“TESTE”).

Caso você não precise do “argc” e “argv”, você não precisa declará-los no seu método.

Até mais.

modifiquei, e agora esá assim:

JAVA

public class AplicacaoLavid{

	// Carregamento da biblioteca que será criada.
	static {
	System.loadLibrary("AppDrawText");
	}

	// Método marcado com modificador "native".
	public native void drawText(String texto);

	public static void main(String[] args) {
		new AplicacaoLavid().drawText("TESTE");
	}
}

C


JNIEXPORT void JNICALL Java_AplicacaoLavid_drawText(JNIEnv *env, jobject obj, jstring texto) { 

	

	drawText(texto);

}

Ai agora está dando o seguinte erro:

AplicacaoLavid.c:46: error: expected ?=?, ?,?, ?;?, ?asm? or ?__attribute__? before ?void

Tava faltando alguns #includes.

agora está dando outro erro:

/usr/bin/ld: cannot find -lpthread-I/opt/jdk/include/linux
collect2: ld returned 1 exit status

Estou compilando dessa maneira

cc -o AplicacaoLavid.so -shared -Wl,-soname,AplicacaoLavid.so -I/opt/jdk/include `directfb-config --cflags` `directfb-config --libs`-I/opt/jdk/include/linux AplicacaoLavid.c -static -lc

Eu acho que está faltado um espaço entre o “-lpthread” e o “-I/opt/jdk/include/linux”, pois o compilador está reclamando que não encontra a biblioteca.
Se não for isso, verifique onde está a biblioteca “pthread” (talvez o nome do arquivo seja libpthread.so), e passe este caminho com o parâmetro -L (ex.: -L/usr/lib).

Oi mrsuzuki,
compilei dessa forma



gcc -o AplicacaoLavid.so -shared -Wl,-soname,AplicacaoLavid.so -I/usr/java/jdk/include `directfb-config --cflags` `directfb-config --libs` -L/usr/lib -I/usr/java/jdk/include/linux  AplicacaoLavid.c -static -lc

só que ai começou a dar esse erro agora:

Exception in thread "main" java.lang.NoClassDefFoundError: AplicacaoLavid
   at gnu.java.lang.MainThread.run(libgcj.so.10)
Caused by: java.lang.ClassNotFoundException: AplicacaoLavid not found in gnu.gcj.runtime.SystemClassLoader{urls=[], parent=gnu.gcj.runtime.ExtensionClassLoader{urls=[], parent=null}}
   at java.net.URLClassLoader.findClass(libgcj.so.10)
   at gnu.gcj.runtime.SystemClassLoader.findClass(libgcj.so.10)
   at java.lang.ClassLoader.loadClass(libgcj.so.10)
   at java.lang.ClassLoader.loadClass(libgcj.so.10)
   at gnu.java.lang.MainThread.run(libgcj.so.10)

mrsuzuki,

Recompilei, deu certo a questao do classpath tal.
acho que agora é mais a questao de código do directfb, pois está dando o seguinte erro:

(!) DirectFBCreate: DirectFBInit has to be called before DirectFBCreate!
AplicacaoLavid.c <60>:
	(#) DirectFBError [DirectFBCreate (&dfb)]: Initialization error!

O código esta dessa forma

//INICIAR O DIRECTFB
int iniciarDFB(int argc, char **argv){
   DFBCHECK (DirectFBInit (&argc, &argv));
   return 0;

}  


JNIEXPORT void JNICALL Java_AplicacaoLavid_drawText(JNIEnv *env, jobject obj, jstring texto) { 

	drawText(texto);
	
	
}
//Função de desenhar texto na janela
static void drawText(char *texto){
DFBCHECK (DirectFBCreate (&dfb));
...
...
...