-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathREADME
240 lines (170 loc) · 10.6 KB
/
README
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
NOTE: THIS IS NOT MY OWN WORK!!! I DO NOT CLAIM COPYRIGHT!!!
All modifications by me are in the public domain. Original downloaded from
http://www.csharp.com/javacfort.html
If you want to use this, please contact the original author.
Calling FORTRAN and C from Java
===============================
Much scientific programming is still performed in FORTRAN, and most of the
remainder is written in C or C++, which are also used for many business and
commercial programs. These programs have the advantage of being compiled into
the native machine code used by the processor, but have the disadvantage that
they are dependent on the platform. This is particularly the case if a
graphical user interface (GUI) is used. Code written in Java, including GUIs,
has the advantage of being, at least in principle, platform independent, thus
can run on Windows, Linux, Mac and many other systems, and a Java compiler has
the additional advantage of being downloadable from Sun's website at no charge.
As Java is not compiled to native code, it has the disadvantage of being slower
than FORTRAN or C/C++ if maximum speed is required. This document shows how we
can get the best of both worlds by calling FORTRAN and C from Java using the
Java Native Interface (JNI), moreover, by using a GUI in Java avoids having to
convert existing FORTRAN or C/C++ programs into Java.
The specific situation discussed here concerns FORTRAN 77, C and Java on a Linux
Red Hat 8.0 platform using a simple example. On other platforms such as
Windows, the principles should be similar, although the details of linking the
codes will be different. The JNI can be used to link Java and C, we also show
how to link C and FORTRAN, but as far as is known, there is no means of directly
linking Java and FORTRAN, so if this required, we have to use C as an interface
between Java and FORTRAN. In this discussion C is only used as a means of
calling FORTRAN, but of course it is applicable if only Java and C are working
together. The Java/C++ interface is very similar to the Java/C interface, so is
not discussed. As a GUI is outside the scope of this document, a simple example
is used to illustrate the principle involved by simulating a GUI.
When some Java code starts executing a GUI is opened. The user can interact
with the GUI to send data to a C program via the JNI, and from there on to
FORTRAN as follows:
GUI --> Java Code --> JNI --> C code --> FORTRAN code
The FORTRAN code can then do whatever it is asked to do, and on completing its
calculations, it can send graphical or text data back to the GUI as follows:
FORTRAN code --> C code --> JNI --> Java Code --> GUI
The JNI is documented by SUN at
http://java.sun.com/docs/books/tutorial/native1.1/index.html.
To call FORTRAN from C is quite easy. Functions and subbroutines can be called
as C functions, provided that parameters are called by reference, i.e. as
pointers, and not by value. Also note that arrays are offset by 1 in FORTRAN
but by 0 in C. Depending on the compiler, the function/subroutine name may
have to be appended by a "_", which is the case here.
To link Java and FORTRAN via C, proceed with the following steps:
(1) Write the Java code, see the test example JavaCode.java, where we generate a
10 element array.
1a) The Java code must contain a declaration for the method name of the C code.
In the example here it is sumsquaredc().
1b) The Java code must also contain a static call to the System.loadLibrary()
method. This must be the name of compiled and linked C/FORTRAN code in
a static library file, other than the prefix "lib" and the appended ".so".
In this example the filename is "libmycodeinc.so", so the name used is
"mycodeinc" in the Java code.
(2) Compile the Java program by typing "javac" followed by the filename of
the Java code. In this case it is:
javac JavaCode.java
which generates the ".class" file. In this case it will be
"JavaCode.class".
(3) Generate the JNI header file by typing "javah -jni" + Java code filename,
in this case it is:
javah -jni JavaCode
which will create a header file with the name of the Java code file
appended by ".h". In this case it is JavaCode.h, and will be used by the C
code. Do not edit this file.
(4) Write the C code, which will be the interface with FORTRAN, here it is
called CCode.c. Conditional compilation is discussed near the end of this
document.
4a) Put #include followed by the name of the header file at the top, in this
case it is #include "JavaCode.h". See the example in CCode.c.
4b) Take the prototype declaration from the header file and use it to name the
function of the C code that Java will call. This will replace main(), if
an existing code is being used.
4c) Insert the declaration of special pointers at the beginning of the C code,
and release them at the end.
(5) Compile the C code, in this case gcc with Linux 8.0 is invoked by typing:
gcc -c -D_REENTRANT -fPIC \
-I/home/csharp/java/j2sdk1.4.2_03/include \
-I/home/csharp/java/j2sdk1.4.2_03/include/linux -c CCode.c
which will generate the object file CCode.o with the JNI linked in.
In this case the Java 2 developer kit version 1.4.2 is in the path given.
(6) Take the existing FORTRAN program and turn the main program into a
function or subroutine that can be called from C. Any data that are
passed between C and FORTRAN are passed through the parameters. See
the test example in FortranCode.f.
(7) Compile the FORTRAN 77 program, in this case g77 with Linux Red 8.0 is
invoked by typing:
g77 -c FortranCode.f
which generates the object file "FortranCode.o".
(8) Now here is the tricky bit, the FORTRAN and C codes have to be linked
and a library created. With the filenames used here it is done with:
gcc -shared CCode.o FortranCode.o -lg2c -o libmycodeinc.so
which will create the library "libmycodeinc.so", called as "mycodeinc"
in the Java program. Note also that "-lg2c" is required in this
example as the FORTRAN code produces output. It is possible that other
libraries may be required in certain situations.
(9) With tcsh or csh type in this example:
setenv LD_LIBRARY_PATH /home/csharp/java
to set the environment variable to point to the path of the working
directory. If bash or ksh are used, instead type:
LD_LIBRARY_PATH=/home/csharp/java
export LD_LIBRARY_PATH
In our case the former is used.
(10)Run the program by typing "java" followed by the name of the Java code,
in this case type:
java JavaCode
which will produce this output on the console shell running on our computer
called "proteus".
What happens is as follows:
i) The main() method in JavaCode.java is invoked, a JavaCode object is
created, then a 10 element array is created and written to in order to
simulate a GUI.
ii) The sumsquaredc() method of JavaCode is then called, this invokes the
C function Java_JavaCode_sumsquaredc in CCode.c, and passes the array
to it. Note that the file JavaCode.h must be included.
iii) Pointers in the C code are set up and the FORTRAN code in FortranCode.f
is called as a C function, with the array passed as a parameter.
iv) The FORTRAN program now executes, calculating the squares of the
contents of the array elements, as well the sum of all the squares.
v) Control is passed back to the C program, which has to clear the JNI
pointers before returning control to Java.
vi) Control is returned to Java, which prints out the final values then
ends execution.
When each code is invoked or returns control to the code calling it, output
is generated as here to confirm that this has taken place.
(11)To help debugging we may want to test the C and FORTRAN codes before writing
the interface with Java. In that case the C code is an ordinary program
with the main() function and no JNI pointers. Once this has been tested
and debugged, the main() function is replaced with the special JNI function
with the JNI pointers added.
Another way to perform this, which also enables us to switch between the C
code operating as an ordinary C program and one called from Java is to set
up a conditional compilation version of CCode.c. On setting the flag JAVA
to 1, the C code is set up to be called from Java, when the flag is set to 0
the C code can be called directly by the user as an ordinary C program. The
example here is heavily commented, and a "j" or "c" is placed in column 1 to
indicate which sections of the code are specific to when it is called by
Java, or as an ordinary C code respectively. In the functional code the
"j" and "c" in column 1 must be removed with all the #define etc. directives
starting in column 1.
If the C code does some significant processing on its own, with or without
calling FORTRAN, rather than acting just as an interface between Java and
FORTRAN as here, it should be possible to write the code so that most of the
body of the code is common to Java and non-Java modes of operation, with
conditional compilation used only at the beginning and the end.
________________________________________________________________________________
To summarize, for the specific example the following is performed:
(1) Create "JavaCode.java" containing the class JavaCode (in this case) that
calls the C method sumsquaredc(). Declare sumsquaredc() as native and
call System.loadLibrary("mycodeinc").
(2) Type "javac JavaCode.java" to compile and create "JavaCode.class".
(3) Type "javah -jni JavaCode" to create "JavaCode.h" header file.
(4) Create "CCode.c", the C code interface, with the function name
Java_JavaCode_sumsquaredc().
(5) Type "gcc -c -D_REENTRANT -fPIC \
-I/home/csharp/java/j2sdk1.4.2_03/include \
-I/home/csharp/java/j2sdk1.4.2_03/include/linux -c CCode.c"
to compile CCode and link it with JNI, producing "CCode.o".
(6) Create or modify FortranCode.f.
(7) Type "g77 -c FortranCode.f" to generate "FortranCode.o".
(8) Type "gcc -shared CCode.o FortranCode.o -lg2c -o libmycodeinc.so" to
link the object files and create "libmycodeinc.so".
(9) Type "setenv LD_LIBRARY_PATH /home/csharp/java"
to set LD_LIBRARY_PATH to point to the working library.
(10)Type "java JavaCode" to run all the codes.
(11)Conditional compilation for "CCode.c" can be implemented for testing and
debugging the C and FORTRAN codes before linking to Java.
________________________________________________________________________________
Return to the Coding & Scripting main page.