如何从现有的C项目(concorde)为JNI创建.dylib

时间:2018-11-27 12:28:14

标签: java c gcc makefile java-native-interface

我正在尝试在Java应用中使用concorde 但我不知道。

我创建了如下的Java类:

pip install --upgrade django==1.11.6  # Upgrade to version 1.11.6

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

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]);
    }
}
}

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

/* 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

和KDTREE的原始Makefile如下:

#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;
}

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

我需要做什么才能为Java代码创建libtsp.dylib? 我已经尝试过了:

# 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 

但是在我将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

我在做什么错了?

1 个答案:

答案 0 :(得分:0)

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

 func setArray(){
 let classA = classA().getAllProperties()
    for i in 0..<deviceLogs.count{
        myArray.append(B(columnId: i, value: classA[i]) )
    }
}

与原始命令相比,解决方案是添加一个库路径,将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"