Как создать .dylib из существующего c проекта (concorde) для JNI - PullRequest
0 голосов
/ 27 ноября 2018

Я пытаюсь использовать 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;
}

и оригинальный Makefile KDTREE выглядит следующим образом:

# 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

что мне нужно сделать, чтобы создать libtsp.dylib для кода Java?Я пробовал это:

 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

что я делаю неправильно?

1 Ответ

0 голосов
/ 27 ноября 2018

После обсуждения в комментариях с @PNN решение было найдено.Правильная команда компиляции:

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.a

...