Tech Tip: Using the NAG DLLs with the Lahey Compiler

Earlier technical tips have described how the NAG DLLs may be used by a wide variety of compilers and environments. These include the NAGWare compiler, Excel, Visual Basic, Microsoft C, .NET and Delphi. A previous article described in more detail how the NAG Fortran DLLs may be used with the Absoft compilers.
This article continues in the same vein by detailing the use of the DLLs with Lahey compiler. The advice has been tested using Lahey Fortran version 7.1.

  1. Code changes

    There are a few simple changes that must be made to a standard Fortran program to allow the NAG DLLs to be used by Lahey Fortran:

    • For each NAG routine called directly insert a DLL_IMPORT statement in the calling program or subprogram e.g.
            DLL_IMPORT D02CJF
      
    • For each NAG routine passed as an argument to a routine in the DLL insert a DLL_IMPORT statement in the calling program or subprogram e.g.
            DLL_IMPORT D02CJW
      
    • For each user-supplied subroutine or function used as an argument to a routine in the DLL insert a DLL_IMPORT statement in the calling program or subprogram e.g.
            DLL_IMPORT OUT
      
      and in the user-supplied subroutine or function insert a DLL_EXPORT statement i.e..
            DLL_EXPORT OUT
      
      should be inserted in subroutine OUT.

    Remember to declare all these subroutines and functions as EXTERNAL and also to declare the type of any functions used. The names of imported functions are case sensitive; this means that NAG names must be in upper case.

    The second family of changes concern the treatment of character arguments which must be adjusted to suit the convention used by the NAG DLLs.
    Character arguments must be stripped of the hidden length argument that Lahey places at the end of all the arguments; this is accomplished by passing the value of the address of the argument as follows: VAL(POINTER(char_arg)). Then, to conform to the NAG DLL standard, the length argument needs to be added immediately following the character argument. Both arguments are passed by value. Here is an example:

          CALL D02CJF (X, XEND2, N, Y, FCN, TOL, VAL(POINTER('Default')),
         + VAL(LEN('Default')), OUT, G, W, IFAIL)
    
  2. Compilation and Linking

    Use the compiler switch “-ml bc” to compile all routines in the program. The Lahey compiler uses this switch to specify that the stdcall calling convention be used.

    The import library file for the DLL should be in a location specified in the LIB environment variable. Alternatively, the programmer can specify the location using the -LIBPATH linker option. Specifying the location of the library on the compiler line is a third possibility i.e.

          lf95 d02cjfe.f <inst_dir>\DLL20DD.lib <inst_dir>\DLL20DDS.lib" -ml bc
    

    where <inst_dir> is the location of the NAG libraries

  3. Execution

    As ever, make sure that the DLLs are on the PATH.

    When all of these changes are applied to the NAG example program for D02CJF the program becomes:

*     D02CJF Example Program Text
*     Mark 14 Revised.  NAG Copyright 1989.
*     .. Parameters ..
      INTEGER          NOUT
      PARAMETER        (NOUT=6)
      INTEGER          N, IW
      PARAMETER        (N=3,IW=21*N+28)
*     .. Scalars in Common ..
      DOUBLE PRECISION H, XEND, XEND2
      INTEGER          K
*     .. Local Scalars ..
      DOUBLE PRECISION PI, TOL, X
      INTEGER          I, IFAIL, J
*     .. Local Arrays ..
      DOUBLE PRECISION W(IW), Y(N)
*     .. External Functions ..
      DOUBLE PRECISION D02CJW, G, X01AAF
      EXTERNAL         D02CJW, G, X01AAF
*     .. Lahey Import Declaration ..
      DLL_IMPORT       D02CJW, G, X01AAF                                  !
*     .. External Subroutines ..
      EXTERNAL         D02CJF, D02CJX, FCN, OUT
*     .. Lahey Import Declaration ..
      DLL_IMPORT       D02CJF, D02CJX, FCN, OUT                           !
*     .. Intrinsic Functions ..
      INTRINSIC        DBLE
*     .. Common blocks ..
      COMMON           XEND, H, K
*     .. Executable Statements ..
      WRITE (NOUT,*) 'D02CJF Example Program Results'
      XEND = 10.0D0
      XEND2 = XEND
      PI = X01AAF(0.0D0)
      WRITE (NOUT,*)
      WRITE (NOUT,*) 'Case 1: intermediate output, root-finding'
      DO 20 J = 4, 5
         TOL = 10.0D0**(-J)
         WRITE (NOUT,*)
         WRITE (NOUT,99999) ' Calculation with TOL =', TOL
         X = 0.0D0
         Y(1) = 0.5D0
         Y(2) = 0.5D0
         Y(3) = PI/5.0D0
         K = 4
         H = (XEND-X)/DBLE(K+1)
         WRITE (NOUT,*) '     X         Y(1)         Y(2)         Y(3)'
         IFAIL = 0
*
         CALL D02CJF(X,XEND2,N,Y,FCN,TOL,VAL(POINTER('Default')),         !
     +               VAL(LEN('Default')),OUT,G,W,IFAIL)                   !
*
         WRITE (NOUT,99998) '  Root of Y(1) = 0.0 at', X
         WRITE (NOUT,99997) '  Solution is', (Y(I),I=1,N)
   20 CONTINUE
      WRITE (NOUT,*)
      WRITE (NOUT,*)
      WRITE (NOUT,*) 'Case 2: no intermediate output, root-finding'
      DO 40 J = 4, 5
         TOL = 10.0D0**(-J)
         WRITE (NOUT,*)
         WRITE (NOUT,99999) ' Calculation with TOL =', TOL
         X = 0.0D0
         Y(1) = 0.5D0
         Y(2) = 0.5D0
         Y(3) = PI/5.0D0
         IFAIL = 0
*
         CALL D02CJF(X,XEND,N,Y,FCN,TOL,VAL(POINTER('Default')),          !
     +               VAL(LEN('Default')),D02CJX,G,W,IFAIL)                !
*
         WRITE (NOUT,99998) '  Root of Y(1) = 0.0 at', X
         WRITE (NOUT,99997) '  Solution is', (Y(I),I=1,N)
   40 CONTINUE
      WRITE (NOUT,*)
      WRITE (NOUT,*)
      WRITE (NOUT,*) 'Case 3: intermediate output, no root-finding'
      DO 60 J = 4, 5
         TOL = 10.0D0**(-J)
         WRITE (NOUT,*)
         WRITE (NOUT,99999) ' Calculation with TOL =', TOL
         X = 0.0D0
         Y(1) = 0.5D0
         Y(2) = 0.5D0
         Y(3) = PI/5.0D0
         K = 4
         H = (XEND-X)/DBLE(K+1)
         WRITE (NOUT,*) '     X         Y(1)         Y(2)         Y(3)'
         IFAIL = 0
*
         CALL D02CJF(X,XEND,N,Y,FCN,TOL,VAL(POINTER('Default')),         !
     +               VAL(LEN('Default')),OUT,D02CJW,W,IFAIL)             !
*
   60 CONTINUE
      WRITE (NOUT,*)
      WRITE (NOUT,*)
      WRITE (NOUT,*)
     +'Case 4: no intermediate output, no root-finding ( integrate to XE
     +ND)'
      DO 80 J = 4, 5
         TOL = 10.0D0**(-J)
         WRITE (NOUT,*)
         WRITE (NOUT,99999) ' Calculation with TOL =', TOL
         X = 0.0D0
         Y(1) = 0.5D0
         Y(2) = 0.5D0
         Y(3) = PI/5.0D0
         WRITE (NOUT,*) '     X         Y(1)         Y(2)         Y(3)'
         WRITE (NOUT,99996) X, (Y(I),I=1,N)
         IFAIL = 0
*
         CALL D02CJF(X,XEND,N,Y,FCN,TOL,VAL(POINTER('Default')),         !
     +               VAL(LEN('Default')),D02CJX,D02CJW,W,IFAIL)          !
*
         WRITE (NOUT,99996) X, (Y(I),I=1,N)
   80 CONTINUE
      STOP
*
99999 FORMAT (1X,A,D8.1)
99998 FORMAT (1X,A,F7.3)
99997 FORMAT (1X,A,3F13.5)
99996 FORMAT (1X,F8.2,3F13.5)
      END
*
      SUBROUTINE OUT(X,Y)
*     .. Lahey Export Declaration ..
*     .. This is done so function can be called from DLL ..
      DLL_EXPORT OUT                                                     !
*     .. Parameters ..
      INTEGER        NOUT
      PARAMETER      (NOUT=6)
      INTEGER        N
      PARAMETER      (N=3)
*     .. Scalar Arguments ..
      DOUBLE PRECISION X
*     .. Array Arguments ..
      DOUBLE PRECISION Y(N)
*     .. Scalars in Common ..
      DOUBLE PRECISION H, XEND
      INTEGER        I
*     .. Local Scalars ..
      INTEGER        J
*     .. Intrinsic Functions ..
      INTRINSIC      DBLE
*     .. Common blocks ..
      COMMON         XEND, H, I
*     .. Executable Statements ..
      WRITE (NOUT,99999) X, (Y(J),J=1,N)
      X = XEND - DBLE(I)*H
      I = I - 1
      RETURN
*
99999 FORMAT (1X,F8.2,3F13.5)
      END
*
      SUBROUTINE FCN(T,Y,F)
*     .. Lahey Export Declaration ..
*     .. This is done so function can be called from DLL ..
      DLL_EXPORT FCN                                                     !
*     .. Parameters ..
      INTEGER        N
      PARAMETER      (N=3)
*     .. Scalar Arguments ..
      DOUBLE PRECISION T
*     .. Array Arguments ..
      DOUBLE PRECISION F(N), Y(N)
*     .. Intrinsic Functions ..
      INTRINSIC      COS, TAN
*     .. Executable Statements ..
      F(1) = TAN(Y(3))
      F(2) = -0.032D0*TAN(Y(3))/Y(2) - 0.02D0*Y(2)/COS(Y(3))
      F(3) = -0.032D0/Y(2)**2
      RETURN
      END
*
      DOUBLE PRECISION FUNCTION G(T,Y)
*     .. Lahey Export Declaration ..
*     .. This is done so function can be called from DLL ..
      DLL_EXPORT G                                                       !
*     .. Parameters ..
      INTEGER                     N
      PARAMETER                   (N=3)
*     .. Scalar Arguments ..
      DOUBLE PRECISION            T
*     .. Array Arguments ..
      DOUBLE PRECISION            Y(N)
*     .. Executable Statements ..
      G = Y(1)
      RETURN
      END

This program compiles and runs correctly under Lahey 7.1 Fortran using the NAG Fortran DLL.

For information on NAG's DLLs please visit http://www.nag.co.uk/numeric/NAGFortranDLLs.asp


For specific technical advice in using NAG's products, please contact our technical experts.

Return to Technical Tips & Hints index page.

Website Feedback

If you would like to see any changes on the current page, feel free to leave us a message.

(If you're a human, don't change the following field)
Your first name.
CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
Image CAPTCHA
Enter the characters shown in the image.