java - 如何从 JNI 的现有 c 项目 (concorde) 创建 .dylib

标签 java c gcc makefile java-native-interface

我正在尝试使用 concorde在 Java 应用程序中 但我想不通。

我已经创建了 java 类如下:

package jconcorde;
public class TSP {

static {
    System.loadLibrary("tsp");
}
private native int[] getNNTour(String path);



public static void main(String[] args) {
    int [] a = new TSP().getNNTour("st70.tsp");
    for (int i = 0; i < a.length; i++) {
        System.out.println(a[i]);
    }
}
}

使用 javac -h 编译后 我得到以下文件:jconcorde_TSP.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class jconcorde_TSP */

#ifndef _Included_jconcorde_TSP
#define _Included_jconcorde_TSP
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     jconcorde_TSP
 * Method:    getNNTour
 * Signature: (Ljava/lang/String;)[I
 */
JNIEXPORT jintArray JNICALL Java_jconcorde_TSP_getNNTour
  (JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif

concorde 内部有一个名为 KDTREE 的文件夹,我已经从 kd_main.c 中复制了其中的一些到我的 jconcorde_TSP.c 中,如下所示:

#include <jni.h>        // JNI header provided by JDK
#include <stdio.h>      // C Standard IO Header
#include "jconcorde_TSP.h"   // Generated
#include "machdefs.h"
#include "util.h"
#include "kdtree.h"
#include <string.h>




static int norm = CC_EUCLIDEAN;
static int seed = 0;
static char *nodefile2 = (char *) NULL;



JNIEXPORT jintArray JNICALL Java_jconcorde_TSP_getNNTour(JNIEnv *env, jobject thisObj, jstring jstr) {
    const char *nodefile = (*env)->GetStringUTFChars(env, jstr, NULL);
    strcpy(nodefile2, nodefile);
    double val, szeit;
    CCdatagroup dat;
    int ncount;
    int *ttour = (int *) NULL, *tour2 = (int *) NULL;
    CCrandstate rstate;

    CCutil_init_datagroup (&dat);
    seed = (int) CCutil_real_zeit ();
    CCutil_sprand (seed, &rstate);
    CCutil_gettsplib (nodefile2, &ncount, &dat);
    CCutil_dat_getnorm (&dat, &norm);
    ttour = CC_SAFE_MALLOC (ncount, int);
    szeit = CCutil_zeit ();
    if (CCkdtree_nearest_neighbor_tour ((CCkdtree *) NULL, ncount,
            CCutil_lprand (&rstate) % ncount, &dat, ttour, &val, &rstate)) {
        fprintf (stderr, "Nearest neighbor failed\n");
    }

   jintArray outJNIArray = (*env)->NewIntArray(env, ncount);
   (*env)->SetIntArrayRegion(env, outJNIArray, 0 , ncount, ttour);

   return outJNIArray;
}

而KDTREE的原始Makefile如下:

# Generated automatically from Makefile.in by configure.
#
#   This file is part of CONCORDE
#
#   (c) Copyright 1995--1999 by David Applegate, Robert Bixby,
#   Vasek Chvatal, and William Cook
#
#   Permission is granted for academic research use.  For other uses,
#   contact the authors for licensing options.
#
#   Use at your own risk.  We make no guarantees about the
#   correctness or usefulness of this code.
#


SHELL = /bin/sh
SRCROOT = ..
BLDROOT = ..
CCINCDIR=$(SRCROOT)/INCLUDE

srcdir = .

CC = gcc
CFLAGS = -g -O3 -arch x86_64  -I$(BLDROOT)/INCLUDE -I$(CCINCDIR)
LDFLAGS = -g -O3 -arch x86_64 
LIBFLAGS = -lm 
RANLIB = ranlib

OBJ_SUFFIX = o
o = $(OBJ_SUFFIX)

THISLIB=kdtree.a
LIBSRCS=kdbuild.c kdnear.c   kdspan.c kdtwoopt.c
ALLSRCS=kd_main.c $(LIBSRCS)

LIBS=$(BLDROOT)/UTIL/util.a

all: kdtree $(THISLIB)

everything: all kdtree

kdtree: kd_main.$o $(THISLIB) $(LIBS)
    $(CC) $(LDFLAGS) -o $@ kd_main.$o $(THISLIB) $(LIBS) $(LIBFLAGS)

clean:
    -rm -f *.$o $(THISLIB) kdtree

OBJS=$(LIBSRCS:.c=.o)

$(THISLIB): $(OBJS)
    $(AR) $(ARFLAGS) $(THISLIB) $(OBJS)
    $(RANLIB) $(THISLIB)

.PHONY: $(BLDROOT)/concorde.a
$(BLDROOT)/concorde.a: $(OBJS)
    $(AR) $(ARFLAGS) $(BLDROOT)/concorde.a $(OBJS)
    $(RANLIB) $(BLDROOT)/concorde.a

include ../INCLUDE/Makefile.common

# DO NOT DELETE THIS LINE -- make depend depends on it.

I=$(CCINCDIR)
I2=$(BLDROOT)/INCLUDE

kd_main.$o:  kd_main.c  $(I)/machdefs.h $(I2)/config.h  $(I)/util.h     \
        $(I)/kdtree.h   
kdbuild.$o:  kdbuild.c  $(I)/machdefs.h $(I2)/config.h  $(I)/util.h     \
        $(I)/kdtree.h   $(I)/macrorus.h 
kdnear.$o:   kdnear.c   $(I)/machdefs.h $(I2)/config.h  $(I)/kdtree.h   \
        $(I)/util.h     $(I)/macrorus.h 
kdspan.$o:   kdspan.c   $(I)/machdefs.h $(I2)/config.h  $(I)/kdtree.h   \
        $(I)/util.h     $(I)/macrorus.h 
kdtwoopt.$o: kdtwoopt.c $(I)/machdefs.h $(I2)/config.h  $(I)/util.h     \
        $(I)/kdtree.h   $(I)/macrorus.h 

我已将 jconcorde_TSP.c 和 jconcorde_TSP.h 复制到 KDTREE 文件夹中

我需要做什么才能为 java 代码创建 libtsp.dylib? 我试过这个:

 gcc -g -O3 -arch x86_64  -I../INCLUDE -I../INCLUDE -I/Library/Java/JavaVirtualMachines/jdk-11.0.1.jdk/Contents/Home//include -I/Library/Java/JavaVirtualMachines/jdk-11.0.1.jdk/Contents/Home//include/darwin -c -dynamiclib -o libtsp.dylib jconcorde_TSP.c ../UTIL/util.a -lm

但是在我将 libtsp.dylib 复制到 java 项目后,我得到了这个异常:

Exception in thread "main" java.lang.UnsatisfiedLinkError: /Users/home_pc/NetBeansProjects/JConcorde/libtsp.dylib: dlopen(/Users/home_pc/NetBeansProjects/JConcorde/libtsp.dylib, 1): no suitable image found.  Did find:
    /Users/home_pc/NetBeansProjects/JConcorde/libtsp.dylib: mach-o, but wrong filetype
    /Users/home_pc/NetBeansProjects/JConcorde/libtsp.dylib: mach-o, but wrong filetype
    at java.base/java.lang.ClassLoader$NativeLibrary.load0(Native Method)
    at java.base/java.lang.ClassLoader$NativeLibrary.load(ClassLoader.java:2430)
    at java.base/java.lang.ClassLoader$NativeLibrary.loadLibrary(ClassLoader.java:2487)
    at java.base/java.lang.ClassLoader.loadLibrary0(ClassLoader.java:2684)
    at java.base/java.lang.ClassLoader.loadLibrary(ClassLoader.java:2649)
    at java.base/java.lang.Runtime.loadLibrary0(Runtime.java:829)
    at java.base/java.lang.System.loadLibrary(System.java:1867)
    at jconcorde.TSP.<clinit>(TSP.java:15)
/Users/home_pc/NetBeansProjects/JConcorde/nbproject/build-impl.xml:1328: The following error occurred while executing this line:
/Users/home_pc/NetBeansProjects/JConcorde/nbproject/build-impl.xml:948: Java returned: 1

我做错了什么?

最佳答案

在与@P.N.N 的评论中进行讨论后,找到了解决方案。 正确的编译命令是:

gcc -g -O3 -arch x86_64 -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/darwin" -L"../UTIL" -I"../INCLUDE" -I"../" -dynamiclib -o libtsp.dylib jconcorde_TSP.c ../UTIL/util.a kdtree.a

与原始命令相比,解决方案是在编译中添加一个添加-L"../UTIL" 的库路径,然后将缺少的静态库添加到命令kdtree。一个

关于java - 如何从 JNI 的现有 c 项目 (concorde) 创建 .dylib,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53499712/

相关文章:

java - java数据库中静态方法和单例的替代解决方案

用汇编函数编译 C 程序,反之亦然

c - 如何在 C ( android ) 中呈现文本?

c++ - 为什么那个模板函数不能编译?

c++ - 当格式包含非 ASCII 字符时 sprintf 不起作用

gcc - 为什么 GCC std::atomic 增量会产生低效的非原子组装?

java - 有没有办法将 "attach"Swing 框架相互转换?

java - 类图中的public、protection、private的作用是什么?有什么例子吗?

java - 使用 for 循环将英语翻译为莫尔斯电码

c - 我应该对网络命令使用#defines 还是枚举?