我正在尝试使用 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/