2016-11-02 1 views
1

j'ai trouvé une bonne mise en œuvre de JNI: https://sites.google.com/site/aminer68/jni-wrapper-for-delphi-and-freepascalEn utilisant JNI dans CCPF/Lazarus sur Linux

Il a la version 2.85, et le texte suivant a été écrit en Mars 2016, mais il est écrit pour Windows.

Mais j'eu aucun problème à sauter/enlever tous les trucs associés à Windows (ce que Lazare n'a pas enlevé), mais mon travail échoue encore

Je l'ai fait comme ceci:

procedure TJavaRuntime.Initialize; 
begin 
    if libHandle <> 0 then 
     exit; // already initialized. 
    FRuntimeLib := '/usr/lib/jvm/java-8-oracle/jre/lib/amd64/server/libjvm.so'; 
    libHandle := LoadLibrary(PChar(FRuntimeLib)); 

    if libHandle = 0 then 
     raise EJavaRuntimeCreation.Create('Could not load library ' + FRuntimeLib); 
    @CreateVM := getProcAddress(libHandle, 'JNI_CreateJavaVM'); 
    @GetDefaultArgs := getProcAddress(libHandle, 'JNI_GetDefaultJavaVMInitArgs'); 
    @GetCreatedVMs := getProcAddress(libHandle, 'JNI_GetCreatedJavaVMs'); 
    if (@CreateVM = Nil) or (@GetDefaultArgs = Nil) or (@GetCreatedVMs = Nil) then 
    raise EJavaRuntimeCreation.Create('Library ' + FRuntimeLib + ' is not valid.'); 
    vmargs2.version := $00010008; 
    GetDefaultArgs(@vmargs2); 
end; 

Vous voyez, Je charge la bibliothèque jvm comme nécessaire sous Linux. libHandle devient non nul, donc je pense qu'il le charge bien (si je crée une faute d'orthographe dans le nom de bibliothèque, libHandle reste zéro.)

La découverte des procadresses semble échouer. @CreateVM:>

des renseignements généraux sur CreateVM:

CreateVM : TCreateVM; 
TCreateVM = function (vm : PPJavaVM ; penv : PPJNIEnv ; p : Pointer) : jint; {$IFDEF WIN32} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF} 

(en passant, cdecl est actif, stdcall est grisé dans l'éditeur Lazarus)

J'essaie d'appeler un, comme cette fonction en TJavaRuntime.GetVM

Comme ici

if CreateVM(@pvm, @penv, args) <>0 then 
    raise EJavaRuntimeCreation.Create('Could not create JVM'); 

Il ne va pas à l'exception, mais déclenche une autre exception: Le projet jtest1 a levé la classe d'exception 'Externe: SIGSEGV'. À l'adresse 7FFFE62582B4

J'ai lu quelque part que SIGSEGV entre dans un emplacement de mémoire qui est un défaut d'accès à la mémoire illégale. Cela me ramène au code où l'adresse de CreateVM est récupéré de cette façon:

@CreateVM := getProcAddress(DLLHandle, 'JNI_CreateJavaVM'); 

Je suis sûr qu'une fonction de ce nom existe dans cette bibliothèque:

~ > nm -D /usr/lib/jvm/java-8-oracle/jre/lib/amd64/server/libjvm.so 

---fragment 
000000000070e0f0 T jio_snprintf 
000000000070de80 T jio_vfprintf 
000000000070e0d0 T jio_vsnprintf 
00000000006d0880 T JNI_CreateJavaVM 
00000000006cd1d0 T JNI_GetCreatedJavaVMs 
00000000006cd210 T JNI_GetDefaultJavaVMInitArgs 
000000000070ee00 T JVM_Accept 
0000000000713990 T JVM_ActiveProcessorCount 
0000000000715a20 T JVM_AllocateNewArray 
0000000000727340 T JVM_AllocateNewObj 

Ainsi l'appel avec getProcAddress (.....) ne conduit pas à une adresse valide. Il se peut que la fonction LoadLibrary (PChar (FRuntimeLib)) ne charge pas correctement la bibliothèque, bien qu'elle dispose d'un handle valide. (j'ai aussi essayé SafeLoadLibrary (FRuntimeLib). Ou le GetProcAddress (.....) a quelques problèmes (Soit dit en passant, j'ai essayé aussi GetProcedureAddress)

J'ai aussi essayé d'autres jvm-bibliothèques, de sorte que. .? ne peut pas être le problème

Qui sait ce qui se passe mal ici

Merci à l'avance

Répondre

1

Quelques choses à considérer:

  • utiliser unité cmem, de sorte que pascal et la mémoire C est unifiée
  • peut-être commencer par la fonction la plus simple, comme une vérification de la version?
  • La bibliothèque JNI utilise-t-elle la même convention d'appel sous Linux et Windows? Peut-être que vos en-têtes sont Windows uniquement et contiennent stdcall
  • Je vois beaucoup de @. Si vos bibliothèques et votre code d'appel proviennent de différentes sources, soyez très prudent. Certains pourraient manger des indirections en raison de l'utilisation des paramètres CONST ou VAR, vérifiez soigneusement qu'ils correspondent.
+0

Merci, Marco, J'ai trouvé des informations sur cmem: http://wiki.lazarus.freepascal.org/CMem maintenant est d'abord dans mon fichier lpr. Ne résout pas le problème. En effet beaucoup de stdcall. Maintenant {$ IFDEF WIN32} stdcall; {$ ENDIF} {$ IFDEF LINUX} cdecl; {$ ENDIF}, et les cdecl sont actifs. Les fonctions que j'appelle avec @, comme CreateVM sont nécessaires pour initialiser. Sans eux rien ne fonctionne (comme je le comprends bien). Je ne sais pas si je les utilise correctement, je les utilise de la manière originale du code. Je ne comprends pas votre dernière remarque, pour votre information, mon code et la bibliothèque sont sur le même ordinateur. –

+0

Si le code source de l'en-tête et le code que vous utilisez pour appeler l'en-tête ne proviennent pas de la même source (mais pour un en-tête ou une tête différente), vous risquez de traduire un paramètre pointeur avec VAR. aiguille. –

+0

Salut Marco, il n'y a pas d'en-têtes utilisés dans Pascal loadLibrary et getProcAddress, tout ce que nous faisons est d'utiliser les noms qui sont publiés par la bibliothèque. La bibliothèque elle-même doit avoir été chargée, le handle est devenu non nul. Je l'ai vérifié en déformant délibérément le chemin, puis la poignée devient nulle. Donc, quand la bibliothèque est bien chargée, qu'est-ce que je pense, alors le problème doit être dans l'appel getProcAddress. J'ai aussi essayé de charger un autre libjvm.so, qui avait le même résultat. Je pense que c'est un problème de FPC/Lazarus, mais je n'en suis pas sûr. Je l'ai également posté sur leurs listes de diffusion. –