Using g95 with Scilab

Loading dlls with 'link()'

Scilab (www.scilab.org) is a free numerical computation package similar to Matlab. This page explains how to access Fortran procedures in Scilab 4.0. 

In Scilab Help, under the 'fort' keyword, the following Fortran subroutine is provided as an example:

 subroutine foof(c,a,b,n,m)
 integer n,m
 double precision a(*),b,c(*)
 do 10 i=1,m*n
   c(i) = sin(a(i))+b
 10 continue
 end

The working environment for the following commands is a Msys shell in Windows. Save the code as foof.f90, and compile it with g95:  
$ g95 -c foof.f90
To see how the subroutine name has been "decorated", type:
$ dlltool -z foof.def --export-all-symbols foof.o
$ cat foof.def
;c:\mingw\bin\dlltool.exe -z foof.def --export-all-symbols foof.o
EXPORTS
        foof_ @ 1

Note that a trailing underscore was added to the subroutine name. The subroutine entry point is "foof_". Scilab expects external procedure names to have a trailing underscore, and g95 adds these by default to non-module procedure names.

In Linux, Scilab 'link()' can handle object files, but on Windows systems, the object files need to be compiled as dlls in order to be used in Scilab. That is done with:
$ g95 -shared -mrtd -o foof.dll foof.o foof.def
Using a .def file is optional, but it was used here to illustrate how Fortran subroutines work in Scilab. The dll should be in the Scilab working directory. 

Results in Scilab

        ___________________________________________
                         scilab-4.0
                  Copyright (c) 1989-2006
              Consortium Scilab (INRIA, ENPC)
        ___________________________________________

Startup execution:
  loading initial environment
-->cd c:\work;
-->link("foof.dll","foof");
shared archive loaded
Link done
-->a=[1,2,3;4,5,6];b= %pi;
-->[m,n]=size(a);
-->// Inputs:
-->// a is in position 2 and double
-->// b                3     double
-->// n                4     integer
-->// m                5     integer
-->
-->// Outputs:
-->// c is in position 1 and double with size [m,n]
-->c=call("foof",a,2,"d",b,3,"d",n,4,"i",m,5,"i","out",[m,n],1,"d");
-->c
 c  =

    3.9830636    4.0508901    3.2827127
    2.3847902    2.1826684    2.8621772
-->     

Module Procedures

When module procedures are compiled with g95, trailing underscores are not added to procedure names. Some method of attaching trailing underscores to procedure names is required to get module procedures to work with g95. Several ways to do it and access module procedures in Scilab are outlined below.

1. Use bind(c) 

With bind(c), we can assign any name to a Fortran procedure. This provides an elegant, and standard conforming way to attach trailing underscores to the names of procedures that are loaded by Scilab.

module foo
contains
 subroutine foof(c,a,b,n,m)
   bind(c, name='foof_') :: foof
  integer n,m
  double precision a(*),b,c(*)
  do 10 i=1,m*n
   c(i) = sin(a(i))+b
  10 continue
 end subroutine
end module

With the bind(c) line added to the code, a module procedure can be loaded in Scilab and used in the same way as a non-module subroutine. The Scilab results for this example are the same as above.   

2. Use a .def file 

Save this code as 'foofm.f90'.

module foo
contains
subroutine foof(c,a,b,n,m)
  integer n,m
  double precision a(*),b,c(*)
  do 10 i=1,m*n
    c(i) = sin(a(i))+b
  10 continue
 end subroutine
end module foo

Compile the module:
$ g95 -c foofm.f90
Next we use dlltool to create a .def file:
$ dlltool -z foofm.def --export-all-symbols foofm.o
In the .def file we can control how symbols will be identified in a dll. Open the .def file in a text editor or do:
$ cat foofm.def
; c:\mingw\bin\dlltool.exe -z foofm.def --export-all-symbols foofm.o
EXPORTS
    foo_MP_foof @ 1

Notice that g95 has added the prefix "foo_MP_" to the procedure name.

Now open the file foofm.def in a text editor and edit as follows to create an alias for the module procedure name, with a trailing underscore:

; 
EXPORTS
    foo_MP_foof@1
    foof_ = foo_MP_foof@1

When compiling the dll, include the new, edited version of foofm.def in the command line:
$ g95 -shared -mrtd -o foofm.dll foofm.o foofm.def
Defining an alias to a module procedure name in a .def file, the alias having a trailing underscore, and then compiling as a dll with g95, allows module procedures to be loaded in Scilab.

3. Add trailing underscores to procedure names

Another option is to add trailing undercores to procedure names in the Fortran source code. Compile the code to a dll, and call the procedure in Scilab with a name constructed from <module-name>_MP_<procedure-name>, minus the trailing underscore. The example code would be:

module foo
contains
subroutine foof_(c,a,b,n,m)
  integer n,m
  double precision a(*),b,c(*)
  do 10 i=1,m*n
    c(i) = sin(a(i))+b
  10 continue
 end subroutine
end module foo

Compile the module as before and access the subroutine in Scilab using the name "foo_MP_foof".  This is another, perhaps less elegant way to access module procedures compiled with g95 from within Scilab.

Interfacing with Fortran in Scilab

In the example below, another subroutine has been added to module 'foo', which is compiled as a dll with g95 and loaded in Scilab. The second subroutine outputs the real array c, (c1 in Scilab), along with the arguments 's' and 'ch'. The 's' argument is a real scalar and 'ch' has type character(len=4). 

module foo

contains
subroutine foof(c,a,b,n,m)
bind(c, name='foof_') :: foof
 integer n,m
 double precision a(*),b,c(*)
 do 10 i=1,m*n
   c(i) = sin(a(i))+b
 10 continue
 end subroutine

subroutine foofsum(c,a,b,n,m,s,ch)
bind(c, name='foofsum_') :: foofsum
 integer n,m
 character(len=4) :: ch
 real :: a(*),b,c(*),s
 s=0.0
 do 10 i=1,m*n
   c(i) = sin(a(i))+b
   s = s+c(i)
 10 continue
 ch = "done"
end subroutine 
end module foo

Save the above code as 'foo.f90'. Compile with:
g95 -c foo.f90
g95 -shared -mrtd -o foo.dll foo.o

Scilab results:

        ___________________________________________
                         scilab-4.0
                  Copyright (c) 1989-2006
              Consortium Scilab (INRIA, ENPC)
        ___________________________________________
Startup execution:
  loading initial environment
-->cd c:/work;
-->foosubs=[ "foof","foofsum" ];
-->link("foo.dll",foosubs);
shared archive loaded
Link done
-->a=[1,2,3;4,5,6];b= %pi;
-->[m,n]=size(a);
-->// In subroutine "foof",
-->// a is in position 2 and double
-->// b is in position 3 and double
-->// c is in position 1 and real with size [m,n]
-->//
-->c=call("foof",a,2,"d",b,3,"d",n,4,"i",m,5,"i","out",[m,n],1,"d");
-->c
 c  =

    3.9830636    4.0508901    3.2827127
    2.3847902    2.1826684    2.8621772

-->// In subroutine "foofsum",
-->// a is in position 2 and real
-->// b is in position 3 and real
-->// arguments following the "out" keyword in call statement are subroutine output
-->// c1 is in position 1 and real with size [m,n]
-->// s is in position 6 and real
-->// ch is in position 7 with type character(len=4)
-->//
-->[c1,s,ch] = call("foofsum",a,2,"r",b,3,"r",n,4,"i",m,5,"i", ...
--> "out",[m,n],1,"r",[1,1],6,"r",[1,4],7,"c");
-->c1
 c1  =

    3.9830637    4.05089      3.2827127
    2.3847902    2.1826684    2.8621771

-->s
 s  =

    18.746304

-->ch
 ch  =

 done

-->