Running a Matlab compiled C library on a 64-bit Fedora 9

traderainΛογισμικό & κατασκευή λογ/κού

15 Αυγ 2012 (πριν από 4 χρόνια και 8 μήνες)

357 εμφανίσεις

1


Running a Matlab Compiled Library from Java

Bill Scuba 10/16/08


Overview
:

The Matlab compiler only compiles
a library

to be run from C/C++ code. To run the
library from Java, the Java Native Interface (JNI) is used to convert Java variables to and
from C
/C++ code. A C/C++ file is created to convert the Java variables into a form
usable by the Matlab library.



Java Variable

> C variable
-
> Matlab variable




Creating C/C++ library

The C/C++ code converts the Java variables t
o C variables, then the C variables to
Matlab variables (mxArray). There is a set of JNI methods which do the conversion to C
variables (1) and a set of Matlab methods which do the conversion to mxArray. Matlab
has only one variable type


mxArray


so a
ll C variables types are converted to that one
Matlab type (2).

All programs that call MATLAB Compiler generated shared libraries have roughly the
same structure

(*information obtained from the Matlab web site)
:

1.

Declare variables and process/validate input

arguments.



Java Object


C/C++ Library
-

C/C++
c
ode

to
convert data
passed from the
Java code into a
format used by
Matlab

(mxArray)


Matlab complied
library

-

takes
the
data in mxArray
format

and runs
the desired Matlab
function.


Matlab

2


2.

Call
mclInitializeApplication
, and test for success. This function sets up the
global MCR state and enables the construction of MCR instances.

3.

Call, once for each library,
<libraryname>Initialize
, to create the MCR instance
required by the libr
ary.

4.

Invoke functions in the library, and process the results. (This is the main body of
the program.)

Note


If your driver application displays MATLAB figure windows, you should
include a call to
mclWaitForFiguresToDie(NULL)

before calling the
Terminate

functions and
mclTerminateApplication

in the following two steps.

5.

Call, once for each library,
<libraryname>Terminate
, to destroy the associated
MCR.

6.

Call
mclTerminateApplication

to free resources associated with the global MCR
state.

7.

Clean up variables,
close files, etc., and exit.


The .h file created with the Matlab compiled library contains information about the
names of the allowable function calls.


References:

(1)

The Java Native Interface

by Sheng Liang

(2)

Matlab Compiler User’s Guide

(3)

See Appendix 1 for a

code example



Compiling a C/C++ driver library to run a Matlab compiled C library

-

Note: these instructions are for a 64
-
bit Fedora 9 core Linux machine

1.

Install the Matlab environment by running MCRInstaller.bin

o

MCRInstaller.bin file comes with the Matlab

Compiler

o

The MCRInstaller version we are using is missing the mclmcr.h file. To
fix the problem, replace the
.../MATLAB_Component_Runtime/v77/extern/include directory with the
same directory from the computer with the Matlab Compiler on it.

2.

Set up the en
vironmental variables

o

export
MATLAB_MCR_PATH=/opt/MATLAB/MATLAB_Component_Runtim
e/v77

o

export
LD_LIBRARY_PATH=$MATLAB_MCR_PATH/runtime/glnxa64:$MA
TLAB_MCR_PATH/sys/os/glnxa64:$MATLAB_MCR_PATH/sys/java/jr
e/glnxa64/jre1.6.0/lib/amd64/native_threads:$MATLAB_MC
R_PATH/sy
s/java/jre/glnxa64/jre1.6.0/lib/amd64/server:$MATLAB_MCR_PATH/sys
/java/jre/glnxa64/jre1.6.0/lib/amd64:./

o

export XAPPLRESDIR=$MATLAB_MCR_PATH/X11/app
-
defaults

3


3.

Compiler

o

Include Directories




/<Matlab MCR root>/runtime/glnxa64




/<Matlab MCR root>/sys/
os/glnxa64




/<Matlab MCR
root>/sys/java/jre/glnxa64/jre1.6.0/lib/amd64/native_threads




/<Matlab MCR
root>/sys/java/jre/glnxa64/jre1.6.0/lib/amd64/server




/<Matlab MCR
root>/sys/java/jre/glnxa64/jre1.6.0/lib/amd64




.




/<Matlab MCR root>/extern/include




/<M
atlab MCR root>/runtime/glnxa64

o

gcc
compiling c
ommand

(to be executed all on one line)



gcc
-
shared
-
c
-
g
-
I/opt/MATLAB/MATLAB_Component_Runtime/v77/runtime/glnxa64
-
I/opt/MATLAB/MATLAB_Component_Runtime/v77/sys/os/glnxa64
-
I/opt/MATLAB/MATLAB_Component_R
untime/v77/sys/java/jre/glnxa64/jre1.
6.0/lib/amd64/native_threads
-
I/opt/MATLAB/MATLAB_Component_Runtime/v77/sys/java/jre/glnxa64/jre1.
6.0/lib/amd64/server
-
I/opt/MATLAB/MATLAB_Component_Runtime/v77/sys/java/jre/glnxa64/jre1.
6.0/lib/amd64
-
I/opt/MATLAB/MAT
LAB_Component_Runtime/v77/extern/include
-
I/opt/MATLAB/MATLAB_Component_Runtime/v77/runtime/glnxa64
-
I/opt/jdk1.6.0_06/include/linux
-
I/opt/jdk1.6.0_06/include
-
I/home/user/filepath/Filename
-
fPIC
-
o build/Debug/GNU
-
Linux
-
x86/Filename.o Filename.c

o

Example
:



gcc
-
shared
-
c
-
g
-
I/opt/MATLAB/MATLAB_Component_Runtime/v77/runtime/glnxa64
-
I/opt/MATLAB/MATLAB_Component_Runtime/v77/sys/os/glnxa64
-
I/opt/MATLAB/MATLAB_Component_Runtime/v77/sys/java/jre/glnxa64/jre1.
6.0/lib/amd64/native_threads
-
I/opt/MATLAB/MATLA
B_Component_Runtime/v77/sys/java/jre/glnxa64/jre1.
6.0/lib/amd64/server
-
I/opt/MATLAB/MATLAB_Component_Runtime/v77/sys/java/jre/glnxa64/jre1.
6.0/lib/amd64
-
I/opt/MATLAB/MATLAB_Component_Runtime/v77/extern/include
-
I/opt/MATLAB/MATLAB_Component_Runtime/v77/r
untime/glnxa64
-
I/opt/jdk1.6.0_06/include/linux
-
I/opt/jdk1.6.0_06/include
-
I/home/wscuba/NetBeansProjects/DeutModelNative
-
fPIC
-
o
build/Debug/GNU
-
Linux
-
x86/DeutModelNative.o DeutModelNative.c

4.

Linker

o

Library directories to include:



/<Matlab MCR root>/run
time/glnxa64



/<Matlab MCR root>/bin/glnxa64

o

Libraries to include:



libmwmclmcrrt.so



<compiled C library from Matlab Compiler>

4


o

<Matlab MCR root> example:
/opt/MATLAB/MATLAB_Component_Runtime/v77

o

gcc
linking c
ommand

(to be executed all on one line):



gcc
-
pthr
ead
-
L.
-
shared
-
o libraryname.so
-
fPIC
build/Debug/GNU
-
Linux
-
x86/Filename.o
-
L/opt/MATLAB/MATLAB_Component_Runtime/v77/runtime/gln
xa64
-
L/opt/MATLAB/MATLAB_Component_Runtime/v77/bin/glnxa6
4
-
lmwmclmcrrt

lMatlabLibraryName

o

Example:



gcc
-
pthread
-
L.
-
share
d
-
o deutmodel.so
-
fPIC build/Debug/GNU
-
Linux
-
x86/DeutModelNative.o
-
L/opt/MATLAB/MATLAB_Component_Runtime/v77/runtime/gln
xa64
-
L/opt/MATLAB/MATLAB_Component_Runtime/v77/bin/glnxa6
4
-
lmwmclmcrrt
-
ldeuterium_lsq_model

5.

Possible Additional Steps

o

libXP install



Some Fedora and RedHat core Linux machines will require the
install of libxp.x86_64



To install the package use 'sudo yum install libxp.x86_64’


Creating Java Class

The Java class can be a relatively simple class which calls the functions created in the
C
/C++ library using the Java Native Interface (JNI)
.


References:

(1)

The Java Native Interface

by Sheng Liang

(2)

See Appendix 2 for a code example

(3)

See Appendix 3 for instructions on setting up NetBeans to use JNI


Deploying Java class and C/C++ library on a new m
achine

1.

Move the following files to a directory on the new machine:

a.

<Matlab compiled library name>.so

b.

<

Matlab compiled library name >.cft

c.

<

Matlab compiled library name >.h

d.

<C/C++ library>.so

e.

Java Class

2.

Install the Matlab environment by running MCRInstalle
r.bin

a.

MCRInstaller.bin file comes with the Matlab Compiler

b.

The MCRInstaller version we are using is missing the mclmcr.h file. To
fix the problem, replace the
.../MATLAB_Component_Runtime/v77/extern/include directory with the
same directory from the compu
ter with the Matlab Compiler on it.

3.

Set up the environmental variables

5


a.

export
MATLAB_MCR_PATH=/opt/MATLAB/MATLAB_Component_Runtim
e/v77

b.

export
LD_LIBRARY_PATH=$MATLAB_MCR_PATH/runtime/glnxa64:$MA
TLAB_MCR_PATH/sys/os/glnxa64:$MATLAB_MCR_PATH/sys/java/jr
e/gln
xa64/jre1.6.0/lib/amd64/native_threads:$MATLAB_MCR_PATH/sy
s/java/jre/glnxa64/jre1.6.0/lib/amd64/server:$MATLAB_MCR_PATH/sys
/java/jre/glnxa64/jre1.6.0/lib/amd64:./

i.

Note: add the location of the .cft, .so and .h files to the
LD_LIBRARY_PATH variable if the p
rogram is being run in a
different directory

c.

export XAPPLRESDIR=$MATLAB_MCR_PATH/X11/app
-
defaults

4.

Possible additional steps:

a.

Recompile C/C++ library on new machine if library does not run properly

(see ‘Compiling a C/C++ driver library’ section)

5.

Notes:

a.

.cf
t file is unpacked on the first time the library is run into a directory


6


Appendix 1


/*==============================================================
===


*


* DeutModelNative.C


* Driver code that calls the libdeuterium_lsq_model.so shared libra
ry created


* using MATLAB Compiler from the Java Native Interface (JNI).


*


* This is the wrapper C code to call a shared library created


* using MATLAB Compiler.


*


* Bill Scuba 8/13/08


*====================================================
==========
===*/


/*


* Include the javah
-
generated header file and the library specific header file


* as generated by MATLAB Compiler.


*/

#include "DeutModelNative.h"

#include "libdeuterium_lsq_model.h"


/*


* Helper function to throw a java exception.


* This function takes the exception class name and


* message as input, then throws a Java exception.


*/

static void throw_java_exception(JNIEnv *env, const char* name, const char* msg)

{


jclass cls = (*env)
-
>FindClass(env, name);


if (cls != NULL)


{


(*env)
-
>ThrowNew(env, cls, msg);


(*env)
-
>DeleteLocalRef(env, cls);


}

}


/*


* Helper function to marshal a Java double matrix into an mxArray.


* This function assumes the input array is of type double[][].


* No check on the typ
e is done. Column dimension is obtained


* from size of first row.


*/

static mxArray* javamatrix_to_mxArray(JNIEnv* env, jobjectArray arr)

7


{


mxArray* px; /* mxArray to return */


int nRows; /* Number of rows */


int nCols;

/* Number of columns */


int inxRow,inxCol; /* Loop variables */


jdoubleArray row; /* Stores current row */



if (arr == NULL)


return NULL;




/* Get number of rows and columns */


nRows = (int)(*env)
-
>GetArrayLength(en
v, arr);


if ((row = (jdoubleArray)(*env)
-
>GetObjectArrayElement(env, arr, 0)) == NULL)


{


// if this is NULL the first element of arr is not an array so it should be a simple
array


//return javaArray_to_mxArray(env, arr);


ret
urn NULL;


}




nCols = (int)(*env)
-
>GetArrayLength(env, row);


(*env)
-
>DeleteLocalRef(env, row);


/* Create mxArray */


px = mxCreateDoubleMatrix(nRows, nCols, mxREAL);


/* Loop over rows */


for (inxRow=0; inxRow<nRows; inxRow++)


{


int subs[2]; /* Stores subscripts for mxArray indexing */


int offset; /* Offset in mxArray of value */


double* pval; /* Current value to copy */


subs[0] = inxRow;


row = (jdoubleArray)(*env)
-
>GetObjectArrayElement(env, arr, (jsize)inxRow);


/* Loop over columns */


for (inxCol=0; inxCol<nCols; inxCol++)


{


subs[1] = inxCol;


offset = mxCalcSingleSubscript(px, 2, subs);


pval = mxGetPr(px)

+ offset;


(*env)
-
>GetDoubleArrayRegion(env, row, (jsize)inxCol, 1, pval);


}


(*env)
-
>DeleteLocalRef(env, row);


}


return px;

}


/**

8



* Helper function to marshal a Java double array into an mxArray.


* This function assum
es the input array is of type double[].


* No check on the type is done.


* This function assumes we have a single dimension in our array


* as such we simply cycle through the array and set the values of the mArray


*/

static mxArray* javaarray_to_mxArra
y(JNIEnv* env, jdoubleArray arr)

{


mxArray *in1;


jdoubleArray arr2;


int nElements;




arr2 = (jdoubleArray)(*env)
-
> GetDoubleArrayElements(env, arr, 0); // get the data
from the Java variable


nElements = (int)(*env)
-
> GetArrayLength
(env, arr); // get the length of the array


in1 = mxCreateDoubleMatrix(nElements,1,mxREAL); // Create a blank mxarray data
of the proper size


memcpy(mxGetPr(in1), arr2, nElements*sizeof(jdouble)); // copy data to mxarray




return in1;

}


/**


* Helper function to marshal a Java string into an mxArray.

*/

static mxArray* javastring_to_mxArray(JNIEnv* env, jstring arr)

{


mxArray *in1;


const char* arr2 = (*env)
-
> GetStringUTFChars(env,arr, 0); // get data from java
variable


in1 = mxC
reateString(arr2); // copy data to mxArray


return in1;

}


/**


* Helper function to marshal a Java double into an mxArray.

*/

static mxArray* javadouble_to_mxArray(JNIEnv* env, jdouble arr)

{


mxArray *in1;


double arr2 = arr; // get data from ja
va variable


in1 = mxCreateDoubleScalar(arr2); // copy data to mxArray


return in1;

}


/*

9



* Helper function to marshal an mxArray into a Java double matrix.


* This function assumes that the input array is a 2D real double array


* and no check is m
ade on the type or complexity.


*/

static jobjectArray mxArray_to_javamatrix(JNIEnv* env, mxArray* px)

{


jobjectArray arr; /* Java array to return */


int m; /* Number of rows */


int n; /* Number of columns */


int

i,j; /* Loop variables */


jclass ArrCls; /* Double array class */



if (px == NULL)


return NULL;


/* Get number of riws and columns */


m = mxGetM(px);


n = mxGetN(px);


if ((ArrCls = (*env)
-
>FindClass(env, "[D")
) == NULL)


return NULL;


if ((arr = (*env)
-
>NewObjectArray(env, m, ArrCls, NULL)) == NULL)


return NULL;


/* Loop over rows */


for (i=0; i<m; i++)


{


jdoubleArray darr; /* Stores one row of the array */


int subs
[2]; /* Stores subscripts for mxArray indexing */


int offset; /* Offset in mxArray of value */


double* pval; /* Current value to copy */


subs[0] = i;


if ((darr = (*env)
-
>NewDoubleArray(env, n)) == NULL)


return NULL;


/* Loop over columns */


for (j=0; j<n; j++)


{


subs[1] = j;


offset = mxCalcSingleSubscript(px, 2, subs);


pval = mxGetPr(px) + offset;


(*env)
-
>SetDoubleArrayRegi
on(env, darr, (jsize)j, 1, (jdouble*)pval);


}


(*env)
-
>SetObjectArrayElement(env, arr, i, darr);


(*env)
-
>DeleteLocalRef(env, darr);


}


(*env)
-
>DeleteLocalRef(env, ArrCls);


return arr;

}


10


/* Application level initialization

*/

JNIEXPORT

void JNICALL Java_deutmodel_DeutModel_applicationInitialize(JNIEnv *env, jclass
cls)

{


(void)env;


(void)cls;


if (!mclInitializeApplication(NULL, 0))


{


throw_java_exception(env,


"java/lang/RuntimeException",


"Could not initialize the application.");


}

}


/* Library level initialization */

JNIEXPORT

void JNICALL Java_deutmodel_DeutModel_libInitialize(JNIEnv *env, jclass cls)

{


(void)env;


(void)cls;


if (!libdeuterium_lsq_modelInitial
ize())


{


throw_java_exception(env,


"java/lang/RuntimeException",


"Could not initialize the library.");


}

}


/* Call the library function */

JNIEXPORT jobjectArray JNICALL Java_deutmodel_DeutModel_runDeutModelNative



(JNIEnv *env,


jclass cls,


jdoubleArray pepstarts,


jdoubleArray pepstops,



jdoubleArray deuterium,


jstring protein,


jdouble probparam,


jdouble conf_limit,



jdouble numiter,


jdouble dmin,


jdouble dmax)

{




mxArray* in1 = NULL;


mxArray* in2 = NULL;

11



mxArray* in3 = NULL;


mxArray* in4 = NULL;


//mxArray *in1,
*in2, *in3, *in4, *in5, *in6, *in7, *in8, *in9; /* Define input
parameters */


mxArray *in5, *in6, *in7, *in8, *in9;


mxArray *out = NULL;/* and output parameters to be passed to the library functions
*/


jobjectArray jout = NULL; // output variab
le to be returned to Java code



/* Process input arrays */


// pepstarts


if ((in1 = javaarray_to_mxArray(env, pepstarts)) == NULL)


goto EXIT;


// pepstops


if ((in2 = javaarray_to_mxArray(env, pepstops)) == NULL)


goto EXIT;


// deuterium


if ((in3 = javaarray_to_mxArray(env, deuterium)) == NULL)


goto EXIT;


// protein


in4 = javastring_to_mxArray(env, protein);


// parameters


//double probparam2 = probparam;


in5 = javadouble_to_mxArray(env, pro
bparam);


in6 = javadouble_to_mxArray(env, conf_limit);


in7 = javadouble_to_mxArray(env, numiter);


in8 = javadouble_to_mxArray(env, dmin);


in9 = javadouble_to_mxArray(env, dmax);



// test code


//double pepstarts2[] = {1,3,5};


//d
ouble pepstops2[] = {4,6,8};


//double deuterium2[] = {1.1,2.2,3.5};


//char protein2[] = "ENLYFQGMQYYSYNYRER";


//double probparam2 = .33;


//double conf_limit2 = .9;


//double numiter2 = 10;


//double dmin2 = 0;


//double dmax2 = 1;




/* Call the library function */


mlfDeuterium_lsq_model_forlib(1, &out, in1, in2, in3, in4, in5, in6, in7, in8, in9);


/*process output array*/


jout = mxArray_to_javamatrix(env, out);


/* Display the return value of the l
ibrary function */


//printf("From C the value of added matrix is:
\
n");

12



//display2(out);



EXIT:


if (in1 != NULL)


mxDestroyArray(in1);


if (in2 != NULL)


mxDestroyArray(in2);


if (in3 != NULL)


mxDestroyArray(in3);


if (in4 != NULL)


mxDestroyArray(in4);


if (in5 != NULL)


mxDestroyArray(in5);


if (in6 != NULL)


mxDestroyArray(in6);


if (in7 != NULL)


mxDestroyArray(in7);


if (in8 != NULL)


mxDestroyArray(in8);


i
f (in9 != NULL)


mxDestroyArray(in9);




return jout;

}


/* Library level termination */

JNIEXPORT

void JNICALL Java_deutmodel_DeutModel_libTerminate(JNIEnv *env, jclass cls)

{


(void)env;


(void)cls;


libdeuterium_lsq_modelTerminate(
);

}


/* Application level termination */

JNIEXPORT

void JNICALL Java_deutmodel_DeutModel_applicationTerminate(JNIEnv *env, jclass
cls)

{


(void)env;


(void)cls;


mclTerminateApplication();

}


/*DISPLAY This function will display the double matrix

stored in an mxArray.


* This function assumes that the mxArray passed as input contains double

13



* array.


*/

void display2(const mxArray* in)

{


int i=0, j=0; /* loop index variables */


int r=0, c=0; /* variables to store the row and column length

of the matrix */


double *data; /* variable to point to the double data stored within the mxArray */



/* Get the size of the matrix */


r = mxGetN(in);


c = mxGetM(in);


/* Get a pointer to the double data in mxArray */


data = mxGetPr(
in);




/* Loop through the data and display the same in matrix format */


for( i = 0; i < c; i++ ){


for( j = 0; j < r; j++){


printf("%4.2f
\
t",data[j*c+i]);


}


printf("
\
n");


}


printf("
\
n");

}



14


Appendix
2


/*


* Java wrapper class to run deutmodel.so 'C' library which runs the
deuterium_lsq_model.so Matlab library


*


package deutmodel;


/**


* @author Bill Scuba


*/

public class DeutModel {


static {


System.load("/home/wscuba/NetBeansProjects
/DeutModelNative/deutmodel.so");


}



public static double[][] runDeutModel(double[] pepstarts, double[] pepstops, double[]
deuterium,


String protein, double probparam, double conf_limit,



double numiter, double dmin, double dmax) {




/* Call the application intialization routine. */


applicationInitialize();


/* Call the libra
ry intialization routine. */


libInitialize();


/* Call the Matlab library function */


double[][] deutmodeldata = runDeutModelNative(pepstarts, pepstops, deuterium,
protein, probparam,


conf_limit, numiter, dmin, dmax)
;


/* Call the library termination routine. */


libTerminate();


/* Call the application termination routine. */


applicationTerminate();




return deutmodeldata;


}




public static native double[][] ru
nDeutModelNative(double[] pepstarts, double[]
pepstops, double[] deuterium,


String protein, double probparam, double conf_limit,


double numiter, double dmin, d
ouble dmax);


public static native void applicationInitialize();


public static native void libInitialize();


public static native void libTerminate();


public static native void applicationTerminate();}

15


Appendix 3


Beginning JNI with NetBeans

C/C++ Pack 6.0, Linux

Contributed and maintained by
Amit Kumar Saha

Amit Kumar Saha

.

This tutorial takes you through the creation of a sample application that use
s Java
TM

Native Interface
(JNI) code written in the C programming language. For the part of the application written in the
Java
TM

programming language, you will use NetBeans IDE 6.0; for the part written in the C
programming language, you will use NetBeans

C/C++ Pack 6.0.

You will start off by creating a simple Java project, adding a native method to it, and then
implementing this method in C using NetBeans C/C++ Pack 6.0.

Contents





Requirements



Exercise 0: Installing and Configuring the Tutorial Environment



Exercise 1: Setting Up the General Java Application Project



Exercise 2: Setting Up the C/C++ Dynamic Library Project



Exercise 3: Buildi
ng and Running the Application

Prerequisites


This tutorial assumes you have some basic knowledge of, or programming experience with, the
following technologies:



Java programming language




C programming language




NetBeans IDE

Notations Used in Tutorial




<JAVA_HOME>

-

the JDK installation directory



<PROJECTS_ROOT>

-

directory that contains the Java project you create

16


Requirements

To follow this tutor
ial, you need the following software and resources.


Software or Resource

Version Required

NetBeans IDE

version 6.0 or version 6.1 with NetBeans C/C++ pack

Java Development Kit (JDK)

version 6

or version 5

Exercise 0: Installing and Configuring the Tutorial Environment

This exercise will guide you through the process of performing required configuration changes that
should be ap
plied to your system prior to starting the tutorial.

Configuring the System
: Append the paths to the directories that contain the gcc and make
utilities to your PATH environment variable.

Running the Software
: Start the NetBeans IDE.

Exercise 1: Setting

Up the General Java Application Project

The goal of this exercise is to create and configure the Java part of the JNI application you will be
developing. You will create a new Java application project, initialize its main class, and add a native
method to

this class.

Creating the General Java Application Project

1.

Choose File > New Project. Under Categories, select Java. Under Projects, select Java
Application. Click Next.

2.

In the Project Name field, type
JNIDemoJava
.

3.

Change the Project Location to any dir
ectory on your computer. (Hereinafter, this directory
is referred to as
<PROJECTS_ROOT>
.)

4.

Leave the Create Main Class checkbox selected and accept the default value for the
corresponding text field.

5.

Leave the Set as Main Project checkbox selected. Then c
lick Finish.

The IDE creates the
<PROJECTS_ROOT>/JNIDemoJava

project folder.

17




Editing the Main Class Source

1.

To open the Main class sou
rce in the editor, right
-
click the Main class node and choose
Open.

2.

Replace the body of the
main

method with the following:

3.

new Main().nativePrint();

4.

Modify the body of the
nativePrint()

method by deleting its contents and inserting the
native keyword in
to the method signature as follows:

5.

private native void nativePrint();

The native keyword indicates that the method has an implementation located in an external
native library, thus the code is going to compile correctly. However, at runtime the library
l
ocation is not clear.

6.

Press Ctrl
-
F11 to clean and build the project. The project should build successfully.

Creating the Native Library Header File

1.

In a terminal window, navigate to the
<PROJECTS_ROOT<>

directory.

2.

Type the following:

3.

<PROJECTS_ROOT> ja
vah
-
o JNIDemoJava.h
-
classpath
JNIDemoJava/build/classes jnidemojava.Main

4.


A
JNIDemoJava.h

C header file is generated. This file is required to provide a correct
function declaration for the native implementation of the
nativePrint()

method.

18


5.

Switch back t
o the NetBeans IDE window.

Summary


In this exercise you created a new General Java Application Project, specified its location, and
defined the package and name of the main class of the project. You also added a new method to the
main class and marked it

as a method having a native implementation. As a final step, you created
a C header file, which is required later for the native library compilation.

Exercise 2: Setting Up a New C/C++ Dynamic Library Project

This exercise will lead you though the process

of creating the native part of the sample application.
You will create the C++ Dynamic Library project and configure it to be able to build JNI code.

After you have set up the project, you will create the implementation for the native method you
declared

earlier in the Java part of the application.

Creating New C/C++ Dynamic Library Project

1.

Choose File > New Project. Under Categories, select C/C++. Under Projects, select C/C++
Dynamic Library. Click Next.



2.

In the Project Name field, type
JNIDemoCdl
-
1
.

3.

In the Project Location field, type the same location as you entered for the General Java
Application project,
<PROJECTS_ROOT>
. The loca
tion should be already there as the default
value.

19


4.

Accept the defaults for all other fields.

5.

Leave the Set as Main Project checkbox selected. Then click Finish.

The IDE creates the
<PROJECTS_ROOT>/JNIDemoCdl
-
1

project folder.



Setting Project Properties

1.

Right
-
click the project node and choose Properties.

2.

In the Properties dialog box, expand the C/C++ node and the GNU C Compiler node,
and
select the General node. Edit the value of the Include Directories property. Set it to
<JAVA_HOME>/include
,
<JAVA_HOME>/include/linux
.



20


These settings are required to enable references to the Java
jni.h

library from your C
code.

3.

Select the Command Line node. Edit the value of the Additional Options property. Set it to
-
shared
-
m32
.



The
-
shared

option tells the compiler to generate a dynamic library.

-
m32

tells the compiler to create a 32
-
bit binary. By default on 64
-
bit systems the compiled
binaries are 64
-
bit, wh
ich causes a lot of problems with 32
-
bit JDKs.

4.

Expand the Linker node and select the General node.

21




The goal of this step is to simpli
fy the path of the resulting
.so

file, to make referencing it
from Java easier for you.

5.

Click OK. The defined settings are saved.

Adding a Header File

1.

Copy the generated
<PROJECTS_ROOT>/JNIDemoJava.h

header file to the C/C++ Library
project directory,
<P
ROJECTS_ROOT>l/JNIDemoCdl
-
1
.

2.

In the Projects window, right
-
click the Source Files node of the
JNIDemoCdl
-
1

project and
choose Add Existing Item. Select the
HelloWorldNative.h

file. The
JNIDemoJava.h

file
appears under Source Files.



22


Implementing a Method

1.

Right
-
click the Source Files node and choose New >l Add Empty C File. Type
JNIDemo

in
the File Name field, and click Finish. The editor

opens the
JNIDemo.c

file.

2.

Edit the
HelloWorldNative.c

file by typing the following code:

3.

>

4.

#include

5.

#include

6.

#include "HelloWorldNative.h"

7.


8.

JNIEXPORT void JNICALL Java_helloworld_Main_nativePrint

9.


(JNIEnv *env, jobject obj)

10.

{

11.


12.


printf("
\
nHel
lo World from C
\
n");

13.


14.

}

15.

Right
-
click the
JNIDemoCdl
-
1

project node and choose Build Project. The Output window
displays
Build successful. Exit value 0.


Summary

In this exercise you created a new C/C++ Dynamic Library, specified its location, and configured

it
to be able to build a JNI implementation of your Java method. You added the generated header file
for the native method you declared in the Java application, and implemented it.

Exercise 3: Building and Running the Application

In this exercise, you wi
ll perform some final alterations to the Java part of the application. These
changes are required to ensure the Java part properly loads the native library you compiled in the
previous exercise. After that you will compile and run the resulting application
.

Configuring the Java Project

1.

Open the
Main.java

file in the editor.

2.

Add the following initialization code:

3.

static {

4.


System.load("
PROJECTS_ROOT
/JNIDemoCdl/dist/JNIDemoCdl.so");

23


5.


}

Running the Application

1.

To set the
JNIDemoJava

Java projec
t as the main project, right
-
click the project node and
choose Set As Main Project.

2.

Press F6 to run the application. The program should execute correctly and the Output
window should display:

3.

>

4.

Hello World from C

5.

BUILD SUCCESSFUL (total time: 0 seconds)


Summary

In this exercise you made some final configuration steps and ran the application to verify that the
implementation of the nativ
e method comes from the native C library.