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.