Friday Jun 22, 2007
|
We are the Solaris Developer Information Products Team:
Richard Friedman, David Lindt, Kami Shahi, Jyothi Srinath, Paul Echeverri, Ann Rice, Alta Elstad, Susan Morgan, Frank Jennings
Today's Page Hits: 39
Friday Jun 22, 2007
|
The Fortran language, both the standard language adhered to by all vendors and the extended language offered to Sun customers, contains several different models for how to call library functions. Confusion can result if you aren't clear about which model you should use for the particular library function you are calling. In this paper we try to describe the different models and provide examples of what might go wrong.
In general, any function found in a library can be called from Fortran. (Subroutines are rarer; for convenience we'll consistently refer to functions in this article where we should properly say function/subroutine). Here's a recipe for how to do it, which contains several specific recommendations for good coding practices.
To start , gather the following information:
Depending on what you find, there are 5 different models determining how to properly call this function:
Lets look at each situation in detail.
COS(x) ) This means that the Fortran standard defines the spelling of the function name, and prescribes what it should do. The function will be spelled the same way and work the same way on any standard-conforming Fortran compiler.
In this case, do not declare the function return type. And, for maximum portability,
you should declare the function an intrinsic with an INTRINSIC statement:
Read the man page for the function (3F) and call the function with correctly typed arguments.
INTRINSIC COS
Example:
INTRINSIC COS
PRINT *, COS(0.01D0)
END
INTRINSIC FOO
PRINT *, FOO(0.01D0)
END
% f95 t.f
INTRINSIC FOO
^ "t.f", Line = 1, Column = 12: ERROR: "FOO" is not an intrinsic routine.The error message will be more obscure if you didn't include the
INTRINSICstatement, which is one reason for recommending it.
CBRT(x) )The Fortran standard permits processors to define additional intrinsics beyond those prescribed in the standard. They behave much the same way as standard intrinsics, except that they are not guaranteed to be portable to or from other Fortran compilers.
In this case, again, do not declare the function return type. And, for
maximum portability, you should include declare the function an intrinsic
with an INTRINSIC statement:
Example:
INTRINSIC CBRT
PRINT *, CBRT(27.0)
END
You can tell that this is a non-standard intrinsic by compiling with the -ansi flag:
% f95 t.f -ansi
PRINT *, CBRT(27.0)
^ "t.f", Line = 2, Column = 18: ANSI: Intrinsic "CBRT" is an extension to the Fortran standard.
INTRINS
IC FOO
PRINT *, FOO(0.01D0)
END
% f95 t.f1, Column = 12: ERROR: "FOO" is not an intrinsic routine.
INTRINSIC FOO
^ "t.f", Line =The error message will be even more obscure if you didn't include the
INTRINSICstatement, which is one reason for recommending it.
-xknown_lib or -xia flag is
required.
INTRINSIC SDOT
REAL X(3), Y(3)
DATA X /1.,1.,1./
DATA Y /2.,2.,2./
PRINT *, SDOT(3, X, 1, Y, 1)
END
% f95 t.f -xknown_lib=blas1
% a.out
6.0
DRAND(n) )In this case, include the correct declaration of the function return type. For
maximum portability, you should declare the function with an EXTERNAL statement:
EXTERNAL DRAND
Read the man page for the function (3F) and call the function with correctly typed arguments.
Example:
EXTERNAL DRAND
REAL*8 DRAND
PRINT *, 'Random number between 0.0 and 1.0: ',DRAND(1)
END
EXTERNAL DRAND
PRINT *, 'Random number between 0.0 and 1.0: ',DRAND(1)
END
% a.out
Random number between 0.0 and 1.0: 1.7437383 ! WRONG number out of range
SDOT(n,X,nx,Y,ny) Sometimes we say that such a function "has a Fortran binding".
In this case, include a correct declaration of the function return type.
For maximum portability, you should declare the function with an EXTERNAL statement:
EXTERNAL SDOT
Read the man page for the function and call the function with correctly typed
arguments. Explicitly Link the program with the library containing the function.
Example:
EXTERNAL SDOT
REAL X(3), Y(3)
DATA X /1.,1.,1./
DATA Y /2.,2.,2./
PRINT *, SDOT(3, X, 1, Y, 1)
END
% f95 t.f -lsunperf
% a.out
6.0Note that because this is documented as being a Fortran callable function, there was no need to worry about spelling issues such as trailing underscores in the linker name of the function. This was done by the library provider.
libsunperfis not normally one of the Fortran run-time libraries, and you must take extra steps to link with it.Note that SDOT is a bit of a chameleon; it can be used as an intrinsic function if you use the
-xknown_libflag. But that is somewhat unusual; what is described here is the standard model for how to call Fortran-callable functions outside the Fortran run-time.
For the above program, if
libsunperfis not linked into the program, you will get
% f95 t.f
Undefined first referenced
symbol in file
sdot_ t.o
ld: fatal: Symbol referencing errors. No output written to a.out
X and Y are misdeclared as REAL*8
X(3), Y(3) in the preceding
example, the program may print a different value from 6.0:% a.out
7.5Sometimes including complete interface blocks is advisable. It is easiest if the API supplier gives you a file to include which contains the recommended interface blocks.
ELF_VERSION(n))Nonetheless, the function can be called from Fortran, but extra steps must be taken. You should also worry about whether the function is committed to be part of future architectures you will be building under. (Sometimes this is called the "stability level" of the interface.)
In this case, include a correct declaration of the function return type,
and declare the function with the BIND(C) attribute. Include an
actual interface block for the function. In addition to letting you accommodate
C/Fortran differences using BIND(C), you will be able to describe
the expected calling sequence. Explicitly link the program with the library
containing the function.
Example:
USE, INTRINSIC :: ISO_C_BINDING
INTERFACE
FUNCTION ELF_VERSION(VER)
USE, INTRINSIC :: ISO_C_BINDING
INTEGER(C_INT), BIND(C) :: ELF_VERSION
INTEGER(C_INT), VALUE :: VER
END FUNCTION
END INTERFACE
INTEGER(C_INT), PARAMETER :: EV_NONE = 0
PRINT *, 'You linked with elf version ',ELF_VERSION(EV_NONE)
END
% f95 t.f -lelf
% ldd a.out | grep elf
libelf.so.1 => /usr/lib/libelf.so.1
% a.out
You linked with elf version 1
Note that a function interface had to be manually constructed to correspond
to the documented API for elf_version in the elf_version(3ELF) man
page:
unsigned elf_version(unsigned ver);
At that, the correspondence is imperfect; C_INT is made to stand in since
C_UNSIGNED is not defined by the standard. Note that the standard syntax (BIND(C))
replaces previously recommended ways to call functions without a Fortran binding.
Functions do occasionally move between the various categories, usually upward (to models earlier in this list) since the models are given in order of increasing fussiness.