(octave.info)Calling External Code from Oct-Files


Next: Allocating Local Memory in Oct-Files Prev: Calling Octave Functions from Oct-Files Up: Oct-Files
Enter node , (file) or (file)node

A.1.9 Calling External Code from Oct-Files
------------------------------------------

Linking external C code to Octave is relatively simple, as the C
functions can easily be called directly from C++.  One possible issue is
that the declarations of the external C functions may need to be
explicitly defined as C functions to the compiler.  If the declarations
of the external C functions are in the header ‘foo.h’, then the tactic
to ensure that the C++ compiler treats these declarations as C code is

     #ifdef __cplusplus
     extern "C"
     {
     #endif
     #include "foo.h"
     #ifdef __cplusplus
     }  /* end extern "C" */
     #endif

   Calling Fortran code, however, can pose more difficulties.  This is
due to differences in the manner in which compilers treat the linking of
Fortran code with C or C++ code.  Octave supplies several macros that
allow consistent behavior across a number of compilers.

   The underlying Fortran code should use the ‘XSTOPX’ function to
replace the Fortran ‘STOP’ function.  ‘XSTOPX’ uses the Octave exception
handler to treat failing cases in the Fortran code explicitly.  Note
that Octave supplies its own replacement BLAS ‘XERBLA’ function, which
uses ‘XSTOPX’.

   If the code calls ‘XSTOPX’, then the ‘F77_XFCN’ macro should be used
to call the underlying Fortran function.  The Fortran exception state
can then be checked with the global variable
‘f77_exception_encountered’.  If ‘XSTOPX’ will not be called, then the
‘F77_FCN’ macro should be used instead to call the Fortran code.

   There is no great harm in using ‘F77_XFCN’ in all cases, except that
for Fortran code that is short running and executes a large number of
times, there is potentially an overhead in doing so.  However, if
‘F77_FCN’ is used with code that calls ‘XSTOP’, Octave can generate a
segmentation fault.

   An example of the inclusion of a Fortran function in an oct-file is
given in the following example, where the C++ wrapper is

     #include <octave/oct.h>
     #include <octave/f77-fcn.h>
     
     extern "C"
     {
       F77_RET_T
       F77_FUNC (fortransub, FORTSUB)
         (const F77_INT&, F77_DBLE*, F77_CHAR_ARG_DECL F77_CHAR_ARG_LEN_DECL);
     }
     
     DEFUN_DLD (fortrandemo, args, , "Fortran Demo")
     {
       if (args.length () != 1)
         print_usage ();
     
       NDArray a = args(0).array_value ();
     
       double *av = a.fortran_vec ();
       octave_idx_type na = a.numel ();
     
       OCTAVE_LOCAL_BUFFER (char, ctmp, 128);
     
       F77_XFCN (fortransub, FORTSUB,
                 (na, av, ctmp F77_CHAR_ARG_LEN (128)));
     
       return ovl (a, std::string (ctmp));
     }

and the Fortran function is

           subroutine fortransub (n, a, s)
           implicit none
           character*(*) s
           real*8 a(*)
           integer*4 i, n, ioerr
           do i = 1, n
             if (a(i) .eq. 0d0) then
               call xstopx ('fortransub: divide by zero')
             else
               a(i) = 1d0 / a(i)
             endif
           enddo
           write (unit = s, fmt = '(a,i3,a,a)', iostat = ioerr)
          $       'There are ', n,
          $       ' values in the input vector', char(0)
           if (ioerr .ne. 0) then
             call xstopx ('fortransub: error writing string')
           endif
           return
           end

   This example demonstrates most of the features needed to link to an
external Fortran function, including passing arrays and strings, as well
as exception handling.  Both the Fortran and C++ files need to be
compiled in order for the example to work.

     mkoctfile fortrandemo.cc fortransub.f
     [b, s] = fortrandemo (1:3)
     ⇒
       b = 1.00000   0.50000   0.33333
       s = There are   3 values in the input vector
     [b, s] = fortrandemo (0:3)
     error: fortrandemo: fortransub: divide by zero


automatically generated by info2www version 1.2.2.9