JNI Kickstart 小结 02 :桥接至与 Java 无关的纯本地库

你离开我真会死。 提交于 2020-02-28 23:44:41

JNI 程序小结 02 :桥接至与 Java 无关的纯本地库

Java + JNI 桥接库 + 纯本地库 异构程序构建示例。
上文: http://my.oschina.net/typhoon/blog/405527
本文为“加强版”。

  1. 编写 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]$

    源代码:

    1. 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);
      		}
      	}
      
      }

    2. 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.");
      	}
      
      }

    3. 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();
      
      }

    4. 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);
      
      }

    5. 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);
      
      }


  2. 编译 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]$

  3. 生成 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 $?;

    头文件源代码:

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

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

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

  4. 编写本地库程序:

    [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]$

    源代码:

    1. 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;
      }

    2. 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;
      }

    3. 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;
      }

    4. 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");
      }

  5. 编译本地库:

    [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 $?;

  6. 运行准备与检查:

    [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]$

  7. 运行:

    [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]$

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!