2017-11-09 15 views
1

でいないライブラリファイルには、私はそれがrtm_simple.cに肉付けされnative方法を持っている場合、この不満のリンクエラー:java.library.pathに

. 
--compile_c.sh 
--compile_java.sh 
--config.sh 
--execute_java.sh 
--run.sh 
--src 
    --ccode 
    --jnitest_SimpleJNITest.h 
    --rtm_simple.c 
    --jnitest 
    --SimpleJNITest.java 
--lib 
    --rtm_simple.so 
--classes 
    --SimpleJNITest.class 

のようなディレクトリ構造がどのように私が正しくSimpleJNITestを実行するのですか?

現在、私は

config.sh

targetDir="classes" 
libDir="lib" 
srcDir="src" 
MainPackage="jnitest" 
Main="SimpleJNITest" 

ccodeDir="ccode" 
cFileName="rtm_simple" 

jdkDir="/home/user/local/java/jdk1.7.0_65" 

mkdir -p "$targetDir" 
mkdir -p "$libDir" 

を定義していると

run.sh

#!/bin/bash 

source compile_java.sh 

javah -d "${srcDir}/${ccodeDir}" -cp "$targetDir" -jni "${MainPackage}.${Main}" 

source compile_c.sh 

source execute_java.sh 

を実行しようとしています

compile_java.sh

#!/bin/bash 

source config.sh 

javac -d "$targetDir" -sourcepath "$srcDir" -cp "${targetDir}:${libDir}/*" "${srcDir}/${MainPackage}/${Main}.java" 

compile_c.sh

#!/bin/bash 

source config.sh 

cFile="${srcDir}/${ccodeDir}/${cFileName}.c" 
soFile="${libDir}/${cFileName}.so" 

gcc -g -shared -fpic -I "${jdkDir}/include" -I "${jdkDir}/include/linux" $cFile -o $soFile 

execute_java.sh

#!/bin/bash 
source config.sh 

export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${libDir}" 

java -cp "${targetDir}:${libDir}/*" "${MainPackage}.${Main}" 

(これもを試し)

出力

$ ./run.sh 
Exception in thread "main" java.lang.UnsatisfiedLinkError: no rtm_simple in java.library.path 
     at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1867) 
     at java.lang.Runtime.loadLibrary0(Runtime.java:870) 
     at java.lang.System.loadLibrary(System.java:1122) 
     at jnitest.SimpleJNITest.main(SimpleJNITest.java:17) 

コード:

SimpleJNITest.java

package jnitest; 

public class SimpleJNITest{ 

    public static final int NOF_ITERATIONS = 100000; 

    public native int nofAborts(int nofTransactions); 

    public void test(){ 

     int nofAborts = nofAborts(NOF_ITERATIONS); 
     System.out.println(String.format("successfully completed %d transactions and had to retry %d times",nofAborts)); 
    } 


    public static void main(String[] args) { 
     System.loadLibrary("rtm_simple"); 
     new SimpleJNITest().test(); 
    } 
} 

(も)System.loadLibary("rtm_simple.so");を使用してみました

ファイル名を指定したい場合は jnitest_SimpleJNITest.h

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

#ifndef _Included_jnitest_SimpleJNITest 
#define _Included_jnitest_SimpleJNITest 
#ifdef __cplusplus 
extern "C" { 
#endif 
#undef jnitest_SimpleJNITest_NOF_ITERATIONS 
#define jnitest_SimpleJNITest_NOF_ITERATIONS 100000L 
/* 
* Class:  jnitest_SimpleJNITest 
* Method: nofAborts 
* Signature: (I)I 
*/ 
JNIEXPORT jint JNICALL Java_jnitest_SimpleJNITest_nofAborts 
    (JNIEnv *, jobject, jint); 

#ifdef __cplusplus 
} 
#endif 
#endif 

rtm_simple.cは

#include <jni.h> 
#include "jnitest_SimpleJNITest.h" 

JNIEXPORT jint JNICALL 
Java_jnitest_SimpleJNITest_nofAborts(JNIEnv* env, jobject obj, jint nof_iterations){ 
    volatile int abort_counter = 0; 
    volatile int i = 0; 
    while (i < nof_iterations) { 
     __asm__ __volatile__ (
      "xbegin 1f" /*1f: local label 1, look forward to find first*/ 
       :"+rm"(i) /*artificial dependency to prevent re-ordering*/ 
     ); 

     ++i; 

     __asm__ __volatile__ (
      "xend\n\t" 
      "jmp 2f\n" /*not aborted ==> jump to local label 2*/ 
      "1:\n\t" /*local label 1 (jumped to when transaction is aborted)*/ 
      :"+rm"(abort_counter) /*artificial dependency*/ 
      :"rm"(i) /*artificial dependency*/ 
     ); 

     ++abort_counter; 

     __asm__ __volatile__ (
      "2:" /*local label 2 (jumped to when transactoin is NOt aborted)*/ 
      :"+rm"(abort_counter) /*artificial dependency*/ 
      :"rm"(i) /*artificial dependency*/ 
     ); 
    } 

    if(i != nof_iterations) return -1; 
    return abort_counter; 
} 
+0

@mkoありがとうございます。しかし、それは私が従おうとしたチュートリアルと同じように '' cc''を使っています。https://www.java-tips.org/other-api-tips-100035/148-jni/1378-simple- example-of-java-native-interface.htmlを使用してください。私は '' gcc''を使用していますが、gccは '' -G''フラグを持っていません。あなたが私の投稿を読んでいれば、実際にあなたがリンクしたページが示唆している '' -Djava.library.path''の方法を試したことに気づくでしょう。 – User1291

+0

@mko ''エラー:メインクラスのレシピを見つけることができませんでした.No001.HelloWorld'' – User1291

答えて

2

、あなたはSystem.load(String)、およびないSystem.loadLibrary(String)メソッドを使用する必要があります。 loadLibraryは、指定された名前をプラットフォームに依存した方法で変換します。お使いのシステムでは、lib接頭辞と.so接尾辞が追加されている可能性がありますが、loadLibraryの呼び出しにかかわらず、rtm_simple.soというファイルを読み込むことはできません。言い換えれば、loadLibraryを使用する場合は、ファイルの名前をlibrtm_simple.soに変更する必要があります。

strace -fFの下でJVMを実行すると、そのパスが表示されます。

+0

'' System.load''は絶対パスが必要なので使いたくありません。しかし、あなたは '' lib''という接頭辞について正しくありました。だから私が '' compile.sh'' s.tを変更したら。 '' soFile = "$ {libDir}/lib $ {cFileName} .so" ''、それは動作します。ありがとうございました。この情報をより明示的に含めるように答えを適用したいですか? – User1291

+0

ウェルが見つかりました;) – mko

0

System.loadLibrary()をSimpleJNITestクラスの静的ブロックに配置することをお勧めします。 mainでSimpleJNITestオブジェクトを作成すると、より明示的にする必要があります。

public class SimpleJNITest{ 
public static final int NOF_ITERATIONS = 100000; 
    static { 
       System.loadLibrary("rtm_simple"); 
      } 
    <blah blah blah> 

    public static void main(String[] args) { 
     SimpleJNITest simple = new SimpleJNITest(); 
     simple.text(); 
    } 
}