JNI 程序小结 02 :桥接至与 Java 无关的纯本地库
Java + JNI 桥接库 + 纯本地库 异构程序构建示例。上文: http://my.oschina.net/typhoon/blog/405527
本文为“加强版”。
-
编写 Java 程序:
[typhoon@localhost sandbox]$ ls
0_guide.txt
[typhoon@localhost sandbox]$ mkdir -p src/tfw/rsch/jni
[typhoon@localhost sandbox]$ ls
0_guide.txt src
[typhoon@localhost sandbox]$ vi src/tfw/rsch/jni/MainTest.java
[typhoon@localhost sandbox]$ vi src/tfw/rsch/jni/JniTest_01_Loader.java
[typhoon@localhost sandbox]$ vi src/tfw/rsch/jni/JniTest_01_Caller.java
[typhoon@localhost sandbox]$ vi src/tfw/rsch/jni/JniTest_02_LoadAndCall.java
[typhoon@localhost sandbox]$ vi src/tfw/rsch/jni/JniTest_03_ToPureLocal.java
[typhoon@localhost sandbox]$ ls src/tfw/rsch/jni
JniTest_01_Caller.java JniTest_01_Loader.java JniTest_02_LoadAndCall.java JniTest_03_ToPureLocal.java MainTest.java
[typhoon@localhost sandbox]$源代码:
- src/tfw/rsch/jni/MainTest.java,启动程序,启动用于测试 JNI 加载与调用的函数:
/** * This file is a component of FREE SOFTWARE.<br /> * <br /> * Any entity with self-awareness, or organization are allowed to use, modify or * redistribute this according to the second version of "GNU Public License".<br /> * <br /> * The goal of this distribution is that this software being useful and helpful, * FOR A PARTICULAR PURPOSE.<br /> */ package tfw.rsch.jni; import tfw.base.util.array.ArrayToolE; import tfw.base.util.text.TextToolE; /** * Main class, to run a test method of JNI loading and calling.<br /> * * @author Typhoon.Free.Wolf * @version 2015-06-25_18-33 */ public class MainTest { /** * Main method, to run a test of JNI loading and calling.<br /> * * @author Typhoon.Free.Wolf * @version 2015-04-09_15-54 * @param str1dCmdArgs * - Command line arguments.<br /> */ public static void main(String[] str1dCmdArgs) { new MainTest().test(str1dCmdArgs); } /** * General test method.<br /> * * @author Typhoon.Free.Wolf * @version 2015-06-25_18-29 * @param str1dArgs * - Arguments.<br /> */ private void test(String[] str1dArgs) { try { // [S] Pre-processing incoming arguments into a single string. String strArgText = ArrayToolE.arrayForConsole(str1dArgs); if (null == strArgText) { strArgText = ""; } else if ("null".equals(strArgText)) { strArgText = null; } // [E] Pre-processing incoming arguments into a single string. test_01(); test_02(strArgText); test_03(strArgText); } catch (Throwable t) { t.printStackTrace(); } } /** * Test 01: Basic loading and calling of the native library.<br /> * * @author Typhoon.Free.Wolf * @version 2015-05-26_16-26 */ private void test_01() { // Loading native library. new JniTest_01_Loader(); // Calling native method of native library. JniTest_01_Caller jt_01 = new JniTest_01_Caller(); jt_01.println(); jt_01.nativePrintln(); } /** * Test 02: <strong>Argument</strong> passing in and <strong>return * value</strong> retrieving.<br /> * * @author Typhoon.Free.Wolf * @version 2015-06-25_18-29 * @param strArgText * - Text argument to the native library.<br /> */ private void test_02(String strArgText) { // Loading native library during class initializing. JniTest_02_LoadAndCall jt_02 = new JniTest_02_LoadAndCall(); { String strMethodHead = TextToolE.concat("\tpublic String jt_02.javaManipulate(", ((null == strArgText) ? "null" : ("\"" + strArgText + "\"")) + ")\n\t{"); System.out.println(strMethodHead); // Calling the java method. String strRst = jt_02.javaManipulate(strArgText); String strMethodTail = TextToolE .concat("\t}\n\tGot Return Value: ", ((null == strRst) ? "null" : ("\"" + strRst + "\""))); System.out.println(strMethodTail); } System.out.println(); { String strMethodHead = TextToolE.concat( "\tpublic native String jt_02.nativeManipulate(", ((null == strArgText) ? "null" : ("\"" + strArgText + "\"")) + ")\n\t{"); System.out.println(strMethodHead); // Calling the native method, here! String strOut = jt_02.nativeManipulate(strArgText); String strMethodTail = TextToolE .concat("\t}\n\tGot Return Value: ", ((null == strOut) ? "null" : ("\"" + strOut + "\""))); System.out.println(strMethodTail); } } /** * Test 03: Calling to the <u><strong>pure local native library</strong> * that without any relationship to JNI or java</u> through the * <u><strong>native JNI-bridge library</strong></u>.<br /> * * @author Typhoon.Free.Wolf * @version 2015-06-25_18-29 * @param strArgText * - Text argument to the native library.<br /> */ private void test_03(String strArgText) { // Loading native library during class initializing. JniTest_03_ToPureLocal jt_03 = new JniTest_03_ToPureLocal(); { String strMethodHead = TextToolE.concat("\tpublic String jt_03.javaManipulate(", ((null == strArgText) ? "null" : ("\"" + strArgText + "\"")) + ")\n\t{"); System.out.println(strMethodHead); // Calling the java method. String strRst = jt_03.javaManipulate(strArgText); String strMethodTail = TextToolE .concat("\t}\n\tGot Return Value: ", ((null == strRst) ? "null" : ("\"" + strRst + "\""))); System.out.println(strMethodTail); } System.out.println(); { String strMethodHead = TextToolE.concat( "\tpublic native String jt_03.nativeManipulate(", ((null == strArgText) ? "null" : ("\"" + strArgText + "\"")) + ")\n\t{"); System.out.println(strMethodHead); // Calling the native method, here! String strOut = jt_03.nativeManipulate(strArgText); String strMethodTail = TextToolE .concat("\t}\n\tGot Return Value: ", ((null == strOut) ? "null" : ("\"" + strOut + "\""))); System.out.println(strMethodTail); } } }
- src/tfw/rsch/jni/JniTest_01_Loader.java,示例 01 - JNI 本地库加载:
/** * This file is a component of FREE SOFTWARE.<br /> * <br /> * Any entity with self-awareness, or organization are allowed to use, modify or * redistribute this according to the second version of "GNU Public License".<br /> * <br /> * The goal of this distribution is that this software being useful and helpful, * FOR A PARTICULAR PURPOSE.<br /> */ package tfw.rsch.jni; /** * Test 01:<br /> * This class loads the native library (shared object, or dynamic link library, * and so on) during class initializing.<br /> * * @author Typhoon.Free.Wolf * @version 2015-05-26_16-30 */ public class JniTest_01_Loader { /** * Make sure to run during class initializing.<br /> */ static { loadNativeLibrary(); } /** * Loads the native library (shared object, or dynamic link library, and so * on).<br /> * * @author Typhoon.Free.Wolf * @version 2015-05-26_15-56 */ private static void loadNativeLibrary() { // Loading native library file "libJniTest_01_ThisNameIsOK.so" (or // "JniTest_01_ThisNameIsOK.dll", and so on) according to the library // name "JniTest_01_ThisNameIsOK". String strNativeLibraryName = "JniTest_01_AnyNameIsOK"; System.out.println("Loading \"" + strNativeLibraryName + "\"..."); System.loadLibrary(strNativeLibraryName); // <== Loading, here! System.out.println("Loaded."); } }
- src/tfw/rsch/jni/JniTest_01_Caller.java,示例 01 - JNI 本地库调用:
/** * This file is a component of FREE SOFTWARE.<br /> * <br /> * Any entity with self-awareness, or organization are allowed to use, modify or * redistribute this according to the second version of "GNU Public License".<br /> * <br /> * The goal of this distribution is that this software being useful and helpful, * FOR A PARTICULAR PURPOSE.<br /> */ package tfw.rsch.jni; /** * Test 01:<br /> * This class provides an entrance to the native method in the native library * (shared object, or dynamic link library, and so on) for java calling.<br /> * * @author Typhoon.Free.Wolf * @version 2015-05-26_16-30 */ public class JniTest_01_Caller { /** * A java method, prints a message to the standard-out.<br /> * * @author Typhoon.Free.Wolf * @version 2015-04-11_14-09 */ public void println() { System.out.println("\tJava:\tWorks!"); } /** * Entrance to the native method in the native library (shared object, or * dynamic link library, and so on).<br /> * The corresponding native method is supposed to print a message to the * standard-out, just like what the java one above does.<br /> * * @author Typhoon.Free.Wolf * @version 2015-04-11_14-09 */ public native void nativePrintln(); }
- src/tfw/rsch/jni/JniTest_02_LoadAndCall.java,示例 02 - 加载和调用 JNI 本地库,进行控制台 IO 操作:
/** * This file is a component of FREE SOFTWARE.<br /> * <br /> * Any entity with self-awareness, or organization are allowed to use, modify or * redistribute this according to the second version of "GNU Public License".<br /> * <br /> * The goal of this distribution is that this software being useful and helpful, * FOR A PARTICULAR PURPOSE.<br /> */ package tfw.rsch.jni; import tfw.base.util.misc.MiscToolE; import tfw.base.util.text.TextToolE; /** * Test 02: This class<br /> * <ul> * <li>Loads the native library (shared object, or dynamic link library, and so * on) during class initializing;<br /> * </li> * <li>Provides an entrance to the native method in the native library.<br /> * </li> * </ul> * * @author Typhoon.Free.Wolf * @version 2015-06-25_18-38 */ public class JniTest_02_LoadAndCall { /** * Make sure to run during class initializing.<br /> */ static { loadNativeLibrary(); } /** * Loads the native library (shared object, or dynamic link library, and so * on).<br /> * * @author Typhoon.Free.Wolf * @version 2015-05-26_15-58 */ private static void loadNativeLibrary() { // Loading native library file "libJniTest_02.so" (or "JniTest_02.dll", // and so on) according to the library name "JniTest_02". String strNativeLibraryName = "JniTest_02"; System.out.println("Loading \"" + strNativeLibraryName + "\"..."); System.loadLibrary(strNativeLibraryName); // <== Loading, here! System.out.println("Loaded."); } /** * A java method.<br /> * Prints the incoming text string to the standard-out, then receives the * text string from the standard-input and finally returns it.<br /> * * @author Typhoon.Free.Wolf * @version 2015-06-25_18-36 * @param strText * - Incoming text string.<br /> * @return A text string from the standard-input, <strong>could be * null.</strong><br /> */ public String javaManipulate(String strText) { // Printing the received argument. String strReceiveText = TextToolE.concat("\t\tJava:\n\n\t\tArgument:\n\t\t\t", (null == strText) ? "null" : ("\"" + strText + "\"")); System.out.println(strReceiveText); // [S] Receiving a text string for standard input. System.out .print("\t\tUser Input (\"null\" would be considered as null):\n\t\t\t"); String strUserInputText = MiscToolE.getline(System.in); System.out.println("\t\tUser Input Received:\n\t\t\t" + ((null == strUserInputText) ? "null" : ("\"" + strUserInputText + "\""))); // [E] Receiving a text string for standard input. // [S] Printing the value which to be returned. String strReturnValue = "null".equals(strUserInputText) ? null : strUserInputText; System.out.println("\t\tReturns:\n\t\t\t" + ((null == strReturnValue) ? "null" : ("\"" + strReturnValue + "\""))); // [E] Printing the value which to be returned. // Returning. return strReturnValue; } /** * Entrance to the native method in the native library (shared object, or * dynamic link library, and so on).<br /> * The corresponding native method is supposed to print the incoming text * string to the standard-out, then receive the text string from the * standard-input and finally return it, just like what the java one above * does.<br /> * * @author Typhoon.Free.Wolf * @version 2015-04-11_14-10 * @param strText * - Incoming text string.<br /> * @return A text string actually returned from the native method, * <strong>could be null.</strong><br /> */ public native String nativeManipulate(String strText); }
- src/tfw/rsch/jni/JniTest_03_ToPureLocal.java,示例 03 - 通过加载和调用 JNI 本地库进一步调用一个与 Java 无关的纯本地库,进行控制台 IO 操作:
/** * This file is a component of FREE SOFTWARE.<br /> * <br /> * Any entity with self-awareness, or organization are allowed to use, modify or * redistribute this according to the second version of "GNU Public License".<br /> * <br /> * The goal of this distribution is that this software being useful and helpful, * FOR A PARTICULAR PURPOSE.<br /> */ package tfw.rsch.jni; import tfw.base.util.misc.MiscToolE; import tfw.base.util.text.TextToolE; /** * Test 03: This class<br /> * <ul> * <li>Loads the native library (shared object, or dynamic link library, and so * on) during class initializing;<br /> * </li> * <li>Provides an entrance to the native method in the <strong><u>native * JNI-bridge library</u></strong>.<br /> * </li> * <li>The <u><strong>native JNI-bridge library</strong></u> is to call another * <u><strong>pure, local native library</strong> that without any relationship * to JNI or java</u>.<br /> * </li> * </ul> * * @author Typhoon.Free.Wolf * @version 2015-06-25_18-40 */ public class JniTest_03_ToPureLocal { /** * Make sure to run during class initializing.<br /> */ static { loadNativeLibrary(); } /** * Loads the native library (shared object, or dynamic link library, and so * on).<br /> * * @author Typhoon.Free.Wolf * @version 2015-05-26_15-58 */ private static void loadNativeLibrary() { // Loading native library file "libJniTest_03.so" (or "JniTest_03.dll", // and so on) according to the library name "JniTest_03". String strNativeLibraryName = "JniTest_03"; System.out.println("Loading \"" + strNativeLibraryName + "\"..."); System.loadLibrary(strNativeLibraryName); // <== Loading, here! System.out.println("Loaded."); } /** * A java method.<br /> * Prints the incoming text string to the standard-out, then receives the * text string from the standard-input and finally returns it.<br /> * * @author Typhoon.Free.Wolf * @version 2015-06-25_18-36 * @param strText * - Incoming text string.<br /> * @return A text string from the standard-input, <strong>could be * null.</strong><br /> */ public String javaManipulate(String strText) { // Printing the received argument. String strReceiveText = TextToolE.concat("\t\tJava:\n\n\t\tArgument:\n\t\t\t", (null == strText) ? "null" : ("\"" + strText + "\"")); System.out.println(strReceiveText); // [S] Receiving a text string for standard input. System.out .print("\t\tUser Input (\"null\" would be considered as null):\n\t\t\t"); String strUserInputText = MiscToolE.getline(System.in); System.out.println("\t\tUser Input Received:\n\t\t\t" + ((null == strUserInputText) ? "null" : ("\"" + strUserInputText + "\""))); // [E] Receiving a text string for standard input. // [S] Printing the value which to be returned. String strReturnValue = "null".equals(strUserInputText) ? null : strUserInputText; System.out.println("\t\tReturns:\n\t\t\t" + ((null == strReturnValue) ? "null" : ("\"" + strReturnValue + "\""))); // [E] Printing the value which to be returned. // Returning. return strReturnValue; } /** * Entrance to the native method in the native library (shared object, or * dynamic link library, and so on).<br /> * The corresponding native method is supposed to print the incoming text * string to the standard-out, then receive the text string from the * standard-input and finally return it, just like what the java one above * does.<br /> * * @author Typhoon.Free.Wolf * @version 2015-04-11_14-10 * @param strText * - Incoming text string.<br /> * @return A text string actually returned from the native method, * <strong>could be null.</strong><br /> */ public native String nativeManipulate(String strText); }
- src/tfw/rsch/jni/MainTest.java,启动程序,启动用于测试 JNI 加载与调用的函数:
-
编译 Java 程序:
[typhoon@localhost sandbox]$ cp -a ../lib .
[typhoon@localhost sandbox]$ mkdir classes
[typhoon@localhost sandbox]$ ls
0_guide.txt classes lib src
[typhoon@localhost sandbox]$ ls lib # ← 上述源代码引用的工具类在这个文件夹里。
tfw-base.aij.jar tfw-base.v2.2.8_2014-12-22_22-00.longest_night.jre150.aij.jar
# ↑ ↖_ 工具类“ArrayToolE”、“MiscToolE”和“TextToolE”所在。
# `- 指向“tfw-base.v2.2.8_2014-12-22_22-00.longest_night.jre150.aij.jar”的符号链接。
[typhoon@localhost sandbox]$ javac -classpath lib/tfw-base.aij.jar -d classes src/tfw/rsch/jni/*.java
[typhoon@localhost sandbox]$ ls classes/tfw/rsch/jni
JniTest_01_Caller.class JniTest_01_Loader.class JniTest_02_LoadAndCall.class JniTest_03_ToPureLocal.class MainTest.class
[typhoon@localhost sandbox]$ -
生成 JNI 头文件:
[typhoon@localhost sandbox]$ vi build_jni.sh
[typhoon@localhost sandbox]$ ls
0_guide.txt build_jni.sh classes lib src
[typhoon@localhost sandbox]$ sh build_jni.sh
javah -classpath classes -o c_include/JniTest_01_Any_name_is_OK.h tfw.rsch.jni.JniTest_01_Caller;echo $?;
0
javah -classpath classes -o c_include/JniTest_02.h tfw.rsch.jni.JniTest_02_LoadAndCall;echo $?;
0
javah -classpath classes -o c_include/JniTest_03.h tfw.rsch.jni.JniTest_03_ToPureLocal;echo $?;
0
[typhoon@localhost sandbox]$ ls
0_guide.txt build_jni.sh c_include classes lib src
[typhoon@localhost sandbox]$ ls c_include
JniTest_01_Any_name_is_OK.h JniTest_02.h JniTest_03.h
[typhoon@localhost sandbox]$脚本 build_jni.sh 内容:
#!/bin/sh # JNI head file generating: CLAZZ="tfw.rsch.jni.JniTest_01_Caller"; OUTPUT="c_include/JniTest_01_Any_name_is_OK.h"; echo "javah -classpath classes -o $OUTPUT $CLAZZ;echo \$?;"; javah -classpath classes -o $OUTPUT $CLAZZ;echo $?; CLAZZ="tfw.rsch.jni.JniTest_02_LoadAndCall"; OUTPUT="c_include/JniTest_02.h"; echo "javah -classpath classes -o $OUTPUT $CLAZZ;echo \$?;"; javah -classpath classes -o $OUTPUT $CLAZZ;echo $?; CLAZZ="tfw.rsch.jni.JniTest_03_ToPureLocal"; OUTPUT="c_include/JniTest_03.h"; echo "javah -classpath classes -o $OUTPUT $CLAZZ;echo \$?;"; javah -classpath classes -o $OUTPUT $CLAZZ;echo $?;
头文件源代码:
- c_include/JniTest_01_Any_name_is_OK.h,示例 01 对应的头文件:
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class tfw_rsch_jni_JniTest_01_Caller */ #ifndef _Included_tfw_rsch_jni_JniTest_01_Caller #define _Included_tfw_rsch_jni_JniTest_01_Caller #ifdef __cplusplus extern "C" { #endif /* * Class: tfw_rsch_jni_JniTest_01_Caller * Method: nativePrintln * Signature: ()V */ JNIEXPORT void JNICALL Java_tfw_rsch_jni_JniTest_101_1Caller_nativePrintln (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
- c_include/JniTest_02.h,示例 02 对应的头文件:
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class tfw_rsch_jni_JniTest_02_LoadAndCall */ #ifndef _Included_tfw_rsch_jni_JniTest_02_LoadAndCall #define _Included_tfw_rsch_jni_JniTest_02_LoadAndCall #ifdef __cplusplus extern "C" { #endif /* * Class: tfw_rsch_jni_JniTest_02_LoadAndCall * Method: nativeManipulate * Signature: (Ljava/lang/String;)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_tfw_rsch_jni_JniTest_102_1LoadAndCall_nativeManipulate (JNIEnv *, jobject, jstring); #ifdef __cplusplus } #endif #endif
- c_include/JniTest_03.h,示例 03 对应的头文件:
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class tfw_rsch_jni_JniTest_03_ToPureLocal */ #ifndef _Included_tfw_rsch_jni_JniTest_03_ToPureLocal #define _Included_tfw_rsch_jni_JniTest_03_ToPureLocal #ifdef __cplusplus extern "C" { #endif /* * Class: tfw_rsch_jni_JniTest_03_ToPureLocal * Method: nativeManipulate * Signature: (Ljava/lang/String;)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_tfw_rsch_jni_JniTest_103_1ToPureLocal_nativeManipulate (JNIEnv *, jobject, jstring); #ifdef __cplusplus } #endif #endif
- c_include/JniTest_01_Any_name_is_OK.h,示例 01 对应的头文件:
-
编写本地库程序:
[typhoon@localhost sandbox]$ mkdir c_src
[typhoon@localhost sandbox]$ ls
0_guide.txt build_jni.sh c_include classes c_src lib src
[typhoon@localhost sandbox]$ vi c_src/JniTest_01_ANY_NAME_IS_OK.c
[typhoon@localhost sandbox]$ vi c_src/JniTest_02.c
[typhoon@localhost sandbox]$ vi c_src/JniTest_03.c
[typhoon@localhost sandbox]$ vi c_src/PureLocalNoJava.c
[typhoon@localhost sandbox]$ ls c_src
JniTest_01_ANY_NAME_IS_OK.c JniTest_02.c JniTest_03.c PureLocalNoJava.c
[typhoon@localhost sandbox]$源代码:
- c_src/JniTest_01_ANY_NAME_IS_OK.c,示例 01 将要调用的 JNI 本地库的源代码;仅仅打印文字以证明被调用了:
#include <jni.h> #include <stdio.h> #include <JniTest_01_Any_name_is_OK.h> JNIEXPORT void JNICALL Java_tfw_rsch_jni_JniTest_101_1Caller_nativePrintln (JNIEnv *env, jobject obj) { printf("\tJNI:\tWorks!\n"); return; }
- c_src/JniTest_02.c,示例 02 将要调用的 JNI 本地库的源代码;打印传入的参数、从控制台获取输入并打印和返回此输入:
#include <jni.h> #include <stdio.h> #include <JniTest_02.h> void interactiveGetLine(char *strBuff, int intBuffSize) { printf("\t\tvoid interactiveGetLine(char *strBuff, int [%d])\n\t\t{\n", intBuffSize); // Receiving a text string for standard input, without line breaker. printf("\t\t\tUser Input:\n\t\t\t\t"); fgets(strBuff, intBuffSize, stdin); printf("\t\t\tUser Input Received:\n\t\t\t\t\"%s\"\n", strBuff); // [S] Setting the value index of first line breaker as string ending. int intIdx = 0; for (; intIdx < intBuffSize; intIdx++) { if ('\r' == strBuff[intIdx] || '\n' == strBuff[intIdx]) { strBuff[intIdx] = '\0'; break; } } printf("\t\t\tLine Breaker Removed:\n\t\t\t\t\"%s\"\n", strBuff); // [E] Setting the value index of first line breaker as string ending. printf("\t\t}\n"); } JNIEXPORT jstring JNICALL Java_tfw_rsch_jni_JniTest_102_1LoadAndCall_nativeManipulate (JNIEnv *jniEnv, jobject jobj, jstring jstrArg) { // Printing the received argument. printf("\t\tJNI:\n\n\t\tOriginal Argument:\n\t\t\t"); printf((NULL == jstrArg) ? "%s\n" : "\"%s\"\n", jstrArg); // Converting the received argument into a C styled string, and printing. const char *strConvertedArg = (NULL == jstrArg) ? NULL : (*jniEnv)->GetStringUTFChars(jniEnv, jstrArg, 0); printf("\t\tConverted Argument:\n\t\t\t"); printf((NULL == strConvertedArg) ? "%s\n" : "\"%s\"\n", strConvertedArg); // Now the JNI argument is useless, release it. (*jniEnv)->ReleaseStringUTFChars(jniEnv, jstrArg, strConvertedArg); // Receiving a line of user input from standard input into buffer. int MEANINGFUL_LENGTH = 256; int intBuffSize = MEANINGFUL_LENGTH + 1; char ch1dUserInputBuff[intBuffSize]; interactiveGetLine(ch1dUserInputBuff, intBuffSize); // Printing the value which to be returned. printf("\t\tReturn Value (\"NULL\" is considered as null):\n\t\t\t"); const char *strToReturn = (0 == strcmp(ch1dUserInputBuff, "NULL")) ? NULL : ch1dUserInputBuff; printf((NULL == strToReturn) ? "%s\n" : "\"%s\"\n", strToReturn); // Converting the return value into java string, and printing. jstring jstrToReturn = (*jniEnv)->NewStringUTF(jniEnv, strToReturn); printf("\t\tConverted:\n\t\t\t"); printf((NULL == jstrToReturn) ? "%s\n" : "\"%s\"\n", jstrToReturn); // Returning. return jstrToReturn; }
- c_src/JniTest_03.c,示例 03 将要调用的 JNI 本地库的源代码;打印传入的参数;调用一个纯本地库以从控制台获取输入;打印并返回此输入:
#include <jni.h> #include <stdio.h> #include <JniTest_03.h> void checkString(char *strSrc, int intStartIdx, int intCheckCount) { int intIdx; int intFinalIdx = intStartIdx + intCheckCount; if (1 > intCheckCount) { printf("\nCheck count: %d From index %d Final index limit: %d.\nIndex:", intCheckCount, intStartIdx, intFinalIdx - 1); } printf("\nCheck count: [%d] From index [%d] to [%d]\nIndex:", intCheckCount, intStartIdx, intFinalIdx - 1); for (intIdx = 0; intIdx < intCheckCount; intIdx++) { printf("\t[%d]", intIdx); } printf("\nASCII:"); for (intIdx = 0; intIdx < intFinalIdx; intIdx++) { printf("\t[%d]", strSrc[intIdx]); } printf("\nChar:"); for (intIdx = 0; intIdx < intFinalIdx; intIdx++) { if ('\n' == strSrc[intIdx]) { printf("\t[\\n]"); } else { printf("\t[%c]", strSrc[intIdx]); } } printf("\n"); } void interactiveGetLine(char *strBuff, int intBuffSize) { printf("\t\tvoid interactiveGetLine(char *strBuff, int [%d])\n\t\t{\n", intBuffSize); printf("\t\t\tPure Local: Look Ma No Java!\n\n"); // Receiving a text string for standard input, without line breaker. printf("\t\t\tUser Input:\n\t\t\t\t"); fgets(strBuff, intBuffSize, stdin); printf("\t\t\tUser Input Received:\n\t\t\t\t\"%s\"\n", strBuff); // [S] Setting the value index of first line breaker as string ending. int intIdx = 0; for (; intIdx < intBuffSize; intIdx++) { if ('\r' == strBuff[intIdx] || '\n' == strBuff[intIdx]) { strBuff[intIdx] = '\0'; break; } } printf("\t\t\tLine Breaker Removed:\n\t\t\t\t\"%s\"\n", strBuff); // [E] Setting the value index of first line breaker as string ending. printf("\t\t}\n"); } JNIEXPORT jstring JNICALL Java_tfw_rsch_jni_JniTest_103_1ToPureLocal_nativeManipulate (JNIEnv *jniEnv, jobject jobj, jstring jstrArg) { // Printing the received argument. printf("\t\tJNI:\n\n\t\tOriginal Argument:\n\t\t\t"); printf((NULL == jstrArg) ? "%s\n" : "\"%s\"\n", jstrArg); // Converting the received argument into a C styled string, and printing. const char *strConvertedArg = (NULL == jstrArg) ? NULL : (*jniEnv)->GetStringUTFChars(jniEnv, jstrArg, 0); printf("\t\tConverted Argument:\n\t\t\t"); printf((NULL == strConvertedArg) ? "%s\n" : "\"%s\"\n", strConvertedArg); // Now the JNI argument is useless, release it. (*jniEnv)->ReleaseStringUTFChars(jniEnv, jstrArg, strConvertedArg); // Receiving a line of user input from standard input into buffer. int MEANINGFUL_LENGTH = 256; int intBuffSize = MEANINGFUL_LENGTH + 1; char ch1dUserInputBuff[intBuffSize]; interactiveGetLine(ch1dUserInputBuff, intBuffSize); // Printing the value which to be returned. printf("\t\tReturn Value (\"NULL\" is considered as null):\n\t\t\t"); const char *strToReturn = (0 == strcmp(ch1dUserInputBuff, "NULL")) ? NULL : ch1dUserInputBuff; printf((NULL == strToReturn) ? "%s\n" : "\"%s\"\n", strToReturn); // Converting the return value into java string, and printing. jstring jstrToReturn = (*jniEnv)->NewStringUTF(jniEnv, strToReturn); printf("\t\tConverted:\n\t\t\t"); printf((NULL == jstrToReturn) ? "%s\n" : "\"%s\"\n", jstrToReturn); // Returning. return jstrToReturn; }
- c_src/PureLocalNoJava.c,示例 03 将要通过 JNI 本地库桥接调用的、和 Java 完全无关的纯本地库的源代码;从控制台获取输入,打印并返回:
#include <stdio.h> void interactiveGetLine(char *strBuff, int intBuffSize) { printf("\t\tvoid interactiveGetLine(char *strBuff, int [%d])\n\t\t{\n", intBuffSize); printf("\t\t\tPure Local:\n\n"); // Receiving a text string for standard input, without line breaker. printf("\t\t\tUser Input:\n\t\t\t\t"); fgets(strBuff, intBuffSize, stdin); printf("\t\t\tUser Input Received:\n\t\t\t\t\"%s\"\n", strBuff); // [S] Setting the value index of first line breaker as string ending. int intIdx = 0; for (; intIdx < intBuffSize; intIdx++) { if ('\r' == strBuff[intIdx] || '\n' == strBuff[intIdx]) { strBuff[intIdx] = '\0'; break; } } printf("\t\t\tLine Breaker Removed:\n\t\t\t\t\"%s\"\n", strBuff); // [E] Setting the value index of first line breaker as string ending. printf("\t\t}\n"); }
- c_src/JniTest_01_ANY_NAME_IS_OK.c,示例 01 将要调用的 JNI 本地库的源代码;仅仅打印文字以证明被调用了:
-
编译本地库:
[typhoon@localhost sandbox]$ vi build_native.sh
[typhoon@localhost sandbox]$ ls
0_guide.txt build_jni.sh build_native.sh c_include classes c_src lib src
[typhoon@localhost sandbox]$ sh build_native.sh
gcc c_src/JniTest_01_ANY_NAME_IS_OK.c -fPIC -shared -I c_include -I /usr/lib/jvm/java-1.7.0-openjdk.x86_64/include -I /usr/lib/jvm/java-1.7.0-openjdk.x86_64/include/linux -o lib/libJniTest_01_AnyNameIsOK.so;echo $?;
0
gcc c_src/JniTest_02.c -fPIC -shared -I c_include -I /usr/lib/jvm/java-1.7.0-openjdk.x86_64/include -I /usr/lib/jvm/java-1.7.0-openjdk.x86_64/include/linux -o lib/libJniTest_02.so;echo $?;
0
gcc c_src/PureLocalNoJava.c -fPIC -shared -o lib/libPureLocalNoJava.so;echo $?;
0
gcc c_src/JniTest_03.c -fPIC -shared -I c_include -I /usr/lib/jvm/java-1.7.0-openjdk.x86_64/include -I /usr/lib/jvm/java-1.7.0-openjdk.x86_64/include/linux -L /ext/var/home.123/typhoon/work/Eclipse.Projects/java.tfw.jni_rsch/sandbox/lib -l PureLocalNoJava -o lib/libJniTest_03.so;echo $?;
0
chmod 644 lib/*.so;echo $?;
0
[typhoon@localhost sandbox]$ ls lib
libJniTest_01_AnyNameIsOK.so libJniTest_02.so libJniTest_03.so libPureLocalNoJava.so tfw-base.aij.jar tfw-base.v2.2.8_2014-12-22_22-00.longest_night.jre150.aij.jar
[typhoon@localhost sandbox]$脚本 build_native.sh 内容:
#!/bin/sh # Native library compiling: # JNI related: C_SOURCE_FILE="c_src/JniTest_01_ANY_NAME_IS_OK.c"; OUTPUT="lib/libJniTest_01_AnyNameIsOK.so"; echo "gcc $C_SOURCE_FILE -fPIC -shared -I c_include -I $JAVA_HOME/include -I $JAVA_HOME/include/linux $3 -o $OUTPUT;echo \$?;"; gcc $C_SOURCE_FILE -fPIC -shared -I c_include -I $JAVA_HOME/include -I $JAVA_HOME/include/linux $3 -o $OUTPUT;echo $?; # JNI related: C_SOURCE_FILE="c_src/JniTest_02.c"; OUTPUT="lib/libJniTest_02.so"; echo "gcc $C_SOURCE_FILE -fPIC -shared -I c_include -I $JAVA_HOME/include -I $JAVA_HOME/include/linux $3 -o $OUTPUT;echo \$?;"; gcc $C_SOURCE_FILE -fPIC -shared -I c_include -I $JAVA_HOME/include -I $JAVA_HOME/include/linux $3 -o $OUTPUT;echo $?; # Pure local: C_SOURCE_FILE="c_src/PureLocalNoJava.c"; OUTPUT="lib/libPureLocalNoJava.so"; echo "gcc $C_SOURCE_FILE -fPIC -shared -o $OUTPUT;echo \$?;"; gcc $C_SOURCE_FILE -fPIC -shared -o $OUTPUT;echo $?; # JNI related: C_SOURCE_FILE="c_src/JniTest_03.c"; OUTPUT="lib/libJniTest_03.so"; LIB_PATH="$(pwd)/lib"; LIB_NAME="PureLocalNoJava"; echo "gcc $C_SOURCE_FILE -fPIC -shared -I c_include -I $JAVA_HOME/include -I $JAVA_HOME/include/linux -L $LIB_PATH -l $LIB_NAME -o $OUTPUT;echo \$?;"; gcc $C_SOURCE_FILE -fPIC -shared -I c_include -I $JAVA_HOME/include -I $JAVA_HOME/include/linux -L $LIB_PATH -l $LIB_NAME -o $OUTPUT;echo $?; # Permission: echo "chmod 644 lib/*.so;echo \$?;"; chmod 644 lib/*.so;echo $?;
-
运行准备与检查:
[typhoon@localhost sandbox]$ alias jrun='java -classpath classes:lib/tfw-base.aij.jar -Djava.library.path=lib'
[typhoon@localhost sandbox]$ export LD_LIBRARY_PATH=LD_LIBRARY_PATH:$(pwd)/lib
[typhoon@localhost sandbox]$ echo $LD_LIBRARY_PATH
LD_LIBRARY_PATH:/home/typhoon/123/work/Eclipse.Projects/java.tfw.jni_rsch/sandbox/lib
[typhoon@localhost sandbox]$ ldd lib/libJniTest_03.so
ldd: 警告: 你没有执行权限 `lib/libJniTest_03.so'
linux-vdso.so.1 => (0x00007ffff51e5000)
libPureLocalNoJava.so => /home/typhoon/123/work/Eclipse.Projects/java.tfw.jni_rsch/sandbox/lib/libPureLocalNoJava.so (0x00007fc9d0cb9000)
libc.so.6 => /lib64/libc.so.6 (0x00007fc9d090d000)
/lib64/ld-linux-x86-64.so.2 (0x0000003132400000)
[typhoon@localhost sandbox]$ -
运行:
[typhoon@localhost sandbox]$ jrun tfw.rsch.jni.MainTest "一二三四五" "上山打老虎"
Loading "JniTest_01_AnyNameIsOK"...
Loaded.
Java: Works!
JNI: Works!
Loading "JniTest_02"...
Loaded.
public String jt_02.javaManipulate("一二三四五, 上山打老虎")
{
Java:
Argument:
"一二三四五, 上山打老虎"
User Input ("null" would be considered as null):
老虎没打到,打到小松鼠!
User Input Received:
"老虎没打到,打到小松鼠!"
Returns:
"老虎没打到,打到小松鼠!"
}
Got Return Value: "老虎没打到,打到小松鼠!"
public native String jt_02.nativeManipulate("一二三四五, 上山打老虎")
{
JNI:
Original Argument:
" 4��"
Converted Argument:
"一二三四五, 上山打老虎"
void interactiveGetLine(char *strBuff, int [257])
{
User Input:
NULL
User Input Received:
"NULL
"
Line Breaker Removed:
"NULL"
}
Return Value ("NULL" is considered as null):
(null)
Converted:
(null)
}
Got Return Value: null
Loading "JniTest_03"...
Loaded.
public String jt_03.javaManipulate("一二三四五, 上山打老虎")
{
Java:
Argument:
"一二三四五, 上山打老虎"
User Input ("null" would be considered as null):
null
User Input Received:
"null"
Returns:
null
}
Got Return Value: null
public native String jt_03.nativeManipulate("一二三四五, 上山打老虎")
{
JNI:
Original Argument:
" 4��"
Converted Argument:
"一二三四五, 上山打老虎"
void interactiveGetLine(char *strBuff, int [257])
{
Pure Local: Look Ma No Java!
User Input:
老虎没打到,打到小松鼠!
User Input Received:
"老虎没打到,打到小松鼠!
"
Line Breaker Removed:
"老虎没打到,打到小松鼠!"
}
Return Value ("NULL" is considered as null):
"老虎没打到,打到小松鼠!"
Converted:
"h��"
}
Got Return Value: "老虎没打到,打到小松鼠!"
[typhoon@localhost sandbox]$
来源:oschina
链接:https://my.oschina.net/u/1394318/blog/470904