JNI代码无法在Linux上调用C函数,但不能在Windows上调用

问题描述 投票:2回答:1

我具有使用SWIG生成的以下Java代码。尽管使用SWIG来生成SWIG的代码知识,但不需要了解该问题]

面向用户的Java代码:

public class UuidUtil implements OCUuidUtilConstants {
  public static Uuid generateUuid() {
    long cPtr = UuidUtilJNI.generateUuid();
    return (cPtr == 0) ? null : new Uuid(cPtr, true);
  }
}

UuidUtilJNI.generateUuid()定义如下

调用JNI代码的Java代码

public class UuidUtilJNI {
  public final static native long generateUuid();
}

SWIG生成的JNI C包装代码uuid_wrap.c

uuid_t * jni_gen_uuid()
{
  printf("Inside jni_gen_uuid\n");
  uuid_t *value = (uuid_t *)malloc(sizeof(uuid_t));
  printf("Calling gen_uuid\n");
  gen_uuid(value);
  return value;
}

SWIGEXPORT jlong JNICALL Java_UuidUtilJNI_generateUuid(JNIEnv *jenv, jclass jcls) {
  jlong jresult = 0 ;
  uuid_t *result = 0 ;

  (void)jenv;
  (void)jcls;
  result = (uuid_t *)jni_gen_uuid();
  *(uuid_t **)&jresult = result; 
  return jresult;
}

gen_uuid(uuid_t *uuid)功能uuid.c的部分C代码

void gen_uuid(uuid_t *uuid)
{
  printf("Inside gen_uuid\n");
  /* code to set the uuid to type 4 UUID according to RFC4122 */
}

我正在如下测试:

@Test
public void generateAndConvert() {
    Uuid testUuid = UuidUtil.generateUuid();
    assertNotNull(testUuid);
    // other test code left out for readability
}

当测试在Windows上运行时,代码将按预期工作。

[当我尝试在Linux上运行相同的代码时,测试挂起。

它打印出代码中找到的3个打印状态中的2个。

Inside jni_gen_uuid
Calling gen_uuid

在Linux机器(Fedora 30)上运行测试时,永远不会调用Inside gen_uuid行。

我首先想到的是目标文件的输出中存在某种不匹配,从而导致在调用uuid代码时包装程序代码失败。我已经比较了用于构建uuid.cuuid_wrap.c代码的构建标志,并且它们使用相同的标志,不同之处在于针对包装器代码关闭了某些构建警告,因为警告是由工具生成的,而不是为了由我修改。

我真的不知道还能去哪里。

我已经使用nm和objdump检查了uuid.o文件,据我所知,它具有gen_uuid符号。

我无法将gdb正确地附加到正在运行的示例中,因此不确定是否可以提供任何有用的信息。

是否有任何有助于发现问题的建议?

java c java-native-interface swig
1个回答
0
投票

不幸的是,该解决方案非常针对我的代码。

当我写那个打印声明时>

printf("Inside gen_uuid\n");
/* code to set the uuid to type 4 UUID according to RFC4122 */ 

从来没有说过我错了。文本只是没有刷新到屏幕上。在print语句之后添加fflush(stdout);将表明确实在调用gen_uuid函数。

正如问题中指出的那样,此代码生成类型4 UUID,它是随机UUID。

生成随机数的代码是特定于操作系统的。在可以读取随机数之前,必须初始化随机数生成器。在Linux上,这是通过将文件描述符抓取到Windows上的/dev/urandom来完成的,这是通过在srand()函数中设置种子来完成的。

如果未调用random_init,则在生成随机数时Linux会出现段错误。另一方面,即使没有种子,Windows也会产生一个数字。

解决方案是在单元测试中调用randomInit()之前先调用generateUuid()

如果您是正在探索类似故障的开发人员,并且正在使用printf调试来检查是否已到达一行代码,那么请在确定未到达一行代码之前,确保将print语句刷新到屏幕上。

© www.soinside.com 2019 - 2024. All rights reserved.