Java 在Linux上的FPC/Lazarus中使用JNI

Java 在Linux上的FPC/Lazarus中使用JNI,java,linux,java-native-interface,freepascal,Java,Linux,Java Native Interface,Freepascal,我发现JNI有一个很好的实现: 它的版本为2.85,相关文本已于2016年3月编写,但它是为Windows编写的 但是我跳过/删除所有与Windows相关的东西(Lazarus没有删除的东西)没有问题,但我的工作仍然失败 我是这样做的: procedure TJavaRuntime.Initialize; begin if libHandle <> 0 then exit; // already initialized. FRuntimeLib := '/u

我发现JNI有一个很好的实现:

它的版本为2.85,相关文本已于2016年3月编写,但它是为Windows编写的

但是我跳过/删除所有与Windows相关的东西(Lazarus没有删除的东西)没有问题,但我的工作仍然失败

我是这样做的:

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;
(顺便说一句,cdecl处于活动状态,stdcall在Lazarus编辑器中显示为灰色)

我尝试调用一个函数,就像函数TJavaRuntime.GetVM中的一样

像这里

if CreateVM(@pvm, @penv, args) <>0 then
    raise EJavaRuntimeCreation.Create('Could not create JVM');
我确信该库中存在具有该名称的函数:

~ > 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
因此,使用getProcAddress(…)的调用不会导致有效的地址。 可能是LoadLibrary(PChar(FRuntimeLib))函数无法很好地加载库,尽管它有一个有效的句柄。 (我还尝试了SafeLoadLibrary(FRuntimeLib); 或者GetProcedAddress(…)有一些问题。(顺便说一下,我也试过GetProcedureAddress)

我还尝试了其他jvm库,所以这不是问题所在

谁知道这里出了什么问题


提前感谢

需要考虑的一些事情:

  • 使用单位cmem,使pascal和C内存统一
  • 也许从最简单的功能开始,比如版本检查
  • JNI库在Linux和Windows上使用相同的调用约定吗?可能您的头文件仅限于Windows,并且包含stdcall
  • 我看到了很多@。如果您的库和调用代码来自不同的源,请非常小心。由于使用CONST或VAR参数,有些库可能会使用间接方法,请仔细检查它们是否匹配

谢谢,Marco,我在我的lpr文件中找到了关于cmem的信息:Now是第一个。这并不能解决问题。事实上,许多stdcall都需要初始化。Now{$IFDEF WIN32}stdcall;{$ENDIF}{$IFDEF LINUX}cdecl;{$ENDIF},cdecl都是活动的。我用@调用的函数,如CreateVM,都需要初始化。没有它们,一切都无法工作,(据我所知)。我不知道我是否正确使用了它们,我是按照代码的原始方式使用它们的。我不明白你的最后一句话,供你参考,我的代码和库在同一台计算机上。如果头源代码和你用来调用头的代码不是来自同一个源代码(而是用于不同的头或头服务器),那么您可能会遇到这样的风险:一个标头转换器将指针参数转换为VAR,而另一个转换器将其转换为pascal指针。您好,Marco,pascal loadLibrary和getProcAddress中没有使用标头,我们所做的只是使用库发布的名称。库本身必须已加载,句柄已变为非零。I通过故意错误设置路径进行检查,然后句柄变为零。因此,当库加载良好时,我认为,问题一定出在调用getProcAddress中。我还尝试加载另一个libjvm.So,结果相同。我认为这是FPC/Lazarus问题,但我不确定。我也在t上发布了它继承人邮件列表。对于感兴趣的人,讨论已在以下方面进行:
@CreateVM := getProcAddress(DLLHandle, 'JNI_CreateJavaVM');
~ > 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