Android NDK JNI C++ <2>

这一篇主要涉及是如何用swig转换C写的程序,发现网上还是书上都不会介绍swig的功能,但是实际根本没有傻乎乎的去写JString之类的云云....

现在步骤如下:

<1> 首先新建一个SwigSimpleC工程,然后在工程中新建一个jni文件夹.

<2> 我比较喜欢.h,.c两种文件都配到写,无论是否使用,都会写,习惯问题.

example.h:

#ifndef _EXAMPLE_HEADER_H_
#define _EXAMPLE_HEADER_H_

int gcd(int x,int y);

#endif

example.c:在这里还定义了一个常量,等下转换后就会有一个getFoo()的方法返回这个值,已提供给应用层使用

#include "example.h"

double Foo = 3.0;

int gcd(int x, int y) {

    int g;
    g = y;
    while (x > 0) {
        g = x;
        x = y % x;
        y = g;
    }

    return g;

}

<3> 要让swig工具转换,同样要写一个swig能够识别的脚本:

%module example
%inline %{
extern int gcd(int x,int y);
extern double Foo;
%}

从上面可以看到,和cpp不一样,cpp直接导出.h,不过我等下也用.h导出这个.
<4> : 编写好了上面的脚本,我还会写一个help.txt文件,这个文件包含了运行所需要的信息,包括文件名和路径之类,方便一个后使用.sh(shell编程所需)的开发,

help.txt如下:其实相当于一个帮助文档.

<a> : under project direction , input following command to terminal
swig -java -package org.swig.cls -outdir src/org/swig/cls -o jni/example_wrap.c jni/example.i

<b> : under jni direction , input following command to terminal
swig -c++ -java -package org.swig.cls -outdir src/org/swig/cls -o example_wrap.cpp example.i

<5> : 这个里面要注意<a>显示jni/example.i,那么终端切换路径到和jni同级目录下就可以执行了(或者工程根目录下),<b>最后一个参数显示example.i,那么就要将路径切换到jni目录下,上面的outdir是用绝对路径,所以没关系.在执行之前首先要新建org.swig.cls的包,因为等下执行.i脚本后,输出将会直接输出到指定的包下.

将<a>的信息复制到终端里面,不出意外,就会输出各种文件了,这里面输出的文件中example_wrap.c文件非常重要,打开看看:

/* ----------------------------------------------------------------------------
 * This file was automatically generated by SWIG (http://www.swig.org).
 * Version 2.0.4
 * 
 * This file is not intended to be easily readable and contains a number of 
 * coding conventions designed to improve portability and efficiency. Do not make
 * changes to this file unless you know what you are doing--modify the SWIG 
 * interface file instead. 
 * ----------------------------------------------------------------------------- */

#define SWIGJAVA

/* -----------------------------------------------------------------------------
 *  This section contains generic SWIG labels for method/variable
 *  declarations/attributes, and other compiler dependent labels.
 * ----------------------------------------------------------------------------- */

/* template workaround for compilers that cannot correctly implement the C++ standard */
#ifndef SWIGTEMPLATEDISAMBIGUATOR
# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560)
#  define SWIGTEMPLATEDISAMBIGUATOR template
# elif defined(__HP_aCC)
/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */
/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */
#  define SWIGTEMPLATEDISAMBIGUATOR template
# else
#  define SWIGTEMPLATEDISAMBIGUATOR
# endif
#endif

/* inline attribute */
#ifndef SWIGINLINE
# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__))
#   define SWIGINLINE inline
# else
#   define SWIGINLINE
# endif
#endif

/* attribute recognised by some compilers to avoid 'unused' warnings */
#ifndef SWIGUNUSED
# if defined(__GNUC__)
#   if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
#     define SWIGUNUSED __attribute__ ((__unused__)) 
#   else
#     define SWIGUNUSED
#   endif
# elif defined(__ICC)
#   define SWIGUNUSED __attribute__ ((__unused__)) 
# else
#   define SWIGUNUSED 
# endif
#endif

#ifndef SWIG_MSC_UNSUPPRESS_4505
# if defined(_MSC_VER)
#   pragma warning(disable : 4505) /* unreferenced local function has been removed */
# endif 
#endif

#ifndef SWIGUNUSEDPARM
# ifdef __cplusplus
#   define SWIGUNUSEDPARM(p)
# else
#   define SWIGUNUSEDPARM(p) p SWIGUNUSED 
# endif
#endif

/* internal SWIG method */
#ifndef SWIGINTERN
# define SWIGINTERN static SWIGUNUSED
#endif

/* internal inline SWIG method */
#ifndef SWIGINTERNINLINE
# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE
#endif

/* exporting methods */
#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
#  ifndef GCC_HASCLASSVISIBILITY
#    define GCC_HASCLASSVISIBILITY
#  endif
#endif

#ifndef SWIGEXPORT
# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
#   if defined(STATIC_LINKED)
#     define SWIGEXPORT
#   else
#     define SWIGEXPORT __declspec(dllexport)
#   endif
# else
#   if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY)
#     define SWIGEXPORT __attribute__ ((visibility("default")))
#   else
#     define SWIGEXPORT
#   endif
# endif
#endif

/* calling conventions for Windows */
#ifndef SWIGSTDCALL
# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
#   define SWIGSTDCALL __stdcall
# else
#   define SWIGSTDCALL
# endif 
#endif

/* Deal with Microsoft's attempt at deprecating C standard runtime functions */
#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
# define _CRT_SECURE_NO_DEPRECATE
#endif

/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */
#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE)
# define _SCL_SECURE_NO_DEPRECATE
#endif



/* Fix for jlong on some versions of gcc on Windows */
#if defined(__GNUC__) && !defined(__INTEL_COMPILER)
  typedef long long __int64;
#endif

/* Fix for jlong on 64-bit x86 Solaris */
#if defined(__x86_64)
# ifdef _LP64
#   undef _LP64
# endif
#endif

#include <jni.h>
#include <stdlib.h>
#include <string.h>


/* Support for throwing Java exceptions */
typedef enum {
  SWIG_JavaOutOfMemoryError = 1, 
  SWIG_JavaIOException, 
  SWIG_JavaRuntimeException, 
  SWIG_JavaIndexOutOfBoundsException,
  SWIG_JavaArithmeticException,
  SWIG_JavaIllegalArgumentException,
  SWIG_JavaNullPointerException,
  SWIG_JavaDirectorPureVirtual,
  SWIG_JavaUnknownError
} SWIG_JavaExceptionCodes;

typedef struct {
  SWIG_JavaExceptionCodes code;
  const char *java_exception;
} SWIG_JavaExceptions_t;


static void SWIGUNUSED SWIG_JavaThrowException(JNIEnv *jenv, SWIG_JavaExceptionCodes code, const char *msg) {
  jclass excep;
  static const SWIG_JavaExceptions_t java_exceptions[] = {
    { SWIG_JavaOutOfMemoryError, "java/lang/OutOfMemoryError" },
    { SWIG_JavaIOException, "java/io/IOException" },
    { SWIG_JavaRuntimeException, "java/lang/RuntimeException" },
    { SWIG_JavaIndexOutOfBoundsException, "java/lang/IndexOutOfBoundsException" },
    { SWIG_JavaArithmeticException, "java/lang/ArithmeticException" },
    { SWIG_JavaIllegalArgumentException, "java/lang/IllegalArgumentException" },
    { SWIG_JavaNullPointerException, "java/lang/NullPointerException" },
    { SWIG_JavaDirectorPureVirtual, "java/lang/RuntimeException" },
    { SWIG_JavaUnknownError,  "java/lang/UnknownError" },
    { (SWIG_JavaExceptionCodes)0,  "java/lang/UnknownError" }
  };
  const SWIG_JavaExceptions_t *except_ptr = java_exceptions;

  while (except_ptr->code != code && except_ptr->code)
    except_ptr++;

  (*jenv)->ExceptionClear(jenv);
  excep = (*jenv)->FindClass(jenv, except_ptr->java_exception);
  if (excep)
    (*jenv)->ThrowNew(jenv, excep, msg);
}


/* Contract support */

#define SWIG_contract_assert(nullreturn, expr, msg) if (!(expr)) {SWIG_JavaThrowException(jenv, SWIG_JavaIllegalArgumentException, msg); return nullreturn; } else


extern int gcd(int x,int y);
extern double Foo;


#ifdef __cplusplus
extern "C" {
#endif

SWIGEXPORT jint JNICALL Java_org_swig_cls_exampleJNI_gcd(JNIEnv *jenv, jclass jcls, jint jarg1, jint jarg2) {
  jint jresult = 0 ;
  int arg1 ;
  int arg2 ;
  int result;
  
  (void)jenv;
  (void)jcls;
  arg1 = (int)jarg1; 
  arg2 = (int)jarg2; 
  result = (int)gcd(arg1,arg2);
  jresult = (jint)result; 
  return jresult;
}


SWIGEXPORT void JNICALL Java_org_swig_cls_exampleJNI_Foo_1set(JNIEnv *jenv, jclass jcls, jdouble jarg1) {
  double arg1 ;
  
  (void)jenv;
  (void)jcls;
  arg1 = (double)jarg1; 
  Foo = arg1;
}


SWIGEXPORT jdouble JNICALL Java_org_swig_cls_exampleJNI_Foo_1get(JNIEnv *jenv, jclass jcls) {
  jdouble jresult = 0 ;
  double result;
  
  (void)jenv;
  (void)jcls;
  result = (double)Foo;
  jresult = (jdouble)result; 
  return jresult;
}


#ifdef __cplusplus
}
#endif


看到上面的内容坑爹吧,如果没有swig,上面的内容都要我们开发,为了实现一个功能,要写一堆,累死猿人呀.

如果熟悉jni开发,可以大致看看,没啥子难度.


<6> 生成.so,是需要example_wrap.c的文件,要生成.so,有需要写一个脚本Android.mk,这个脚本的结构都是差不多的.

#
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    :=example
LOCAL_SRC_FILES    :=example_wrap.c example.c

include $(BUILD_SHARED_LIBRARY)

<7> 让后进入jni该目录(准确说是进入Android.mk目录),然后ndk-build就可以看见生成examplelib.so的文件了.

<8> Android工程那边,因为在swig转换时候,已经生成了接口java,所以只要在主工程中加载so库就可以使用:

package org.swig.simple;

import org.swig.cls.example;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.TextView;
import android.widget.Toast;

public class SwigSimple extends Activity {

    static{
        System.loadLibrary("example");
    }
    
    private TextView mText;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_swig_simple);
        
        mText=(TextView)findViewById(R.id.textview1);
        
        mText.setText("gcd : "+example.gcd(3, 5));
        
        Toast.makeText(this, "Foo : "+example.getFoo(), Toast.LENGTH_SHORT).show();
        
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.swig_simple, menu);
        return true;
    }

}


<9> 运行结果............

 

<10> 最终结果目录应该是这样的:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2014-04-20 16:01  MMLoveMeMM  阅读(406)  评论(0)    收藏  举报