在 Linux FPC/Lazarus 中使用 JNI

Using JNI in FPC/Lazarus on Linux

我找到了一个很好的 JNI 实现: https://sites.google.com/site/aminer68/jni-wrapper-for-delphi-and-freepascal

版本是2.85,对应的文字是2016年3月写的,不过是为Windows写的。

但是我没有遇到任何问题skipping/removing 所有 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 := [=12=]010008;
   GetDefaultArgs(@vmargs2);
end;

你看,我在 Linux 中根据需要加载了 jvm 库。 libHandle 变为非零,所以我认为它加载得很好(如果我在库名称中创建拼写错误,libHandle 保持为零。)

procadresses 的查找似乎失败了。 @CreateVM: >

CreateVM 的一些背景知识:

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

(顺便说一下,cdecl 处于活动状态,stdcall 在 Lazarus 编辑器中是灰色的)

我尝试在函数中这样调用一个 TJavaRuntime.GetVM

点赞

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

它没有转到异常,而是引发了另一个异常: 项目 jtest1 引发异常 class 'External: SIGSEGV'。在地址 7FFFE62582B4

我在某处读到 SIGSEGV 正在进入内存位置,这是非法内存访问的错误。 这让我回到以这种方式检索 CreateVM 地址的代码:

@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

所以调用 getProcAddress(.....) 不会导致有效地址。 可能是 LoadLibrary(PChar(FRuntimeLib)) 函数没有很好地加载库,尽管它有一个有效的句柄。 (我也试过 SafeLoadLibrary(FRuntimeLib); 或者 getProcAddress(.....) 有一些问题。 (顺便说一句,我也尝试了GetProcedureAddress)。

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

谁知道这里出了什么问题?

提前致谢

需要考虑的一些事项:

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