Using LINKNLOAD to Call External Programs
The LINKNLOAD function provides simplified access to external routines in shareable images. LINKNLOAD calls a function in an external sharable object and returns a scalar value. Parameters are passed through PV‑WAVE to the specified external function by reference, thus allowing the external function to alter values of PV‑WAVE variables. It is the simplest method for attaching your own C code to PV‑WAVE. Unlike SPAWN, LINKNLOAD allows the sharing of binary data without duplication (transferal) overhead.
Usage
result = LINKNLOAD(object, symbol[, param1,..., paramn])
Parameters
object—A string specifying the filename, including the file path
(use ./<filename> if the file is in the current directory), of the sharable object file to be linked and loaded.
symbol—A string specifying the function name (symbol entry point) to be invoked in the shared object file.
parami—The data to be passed as a parameter to the function.
For more detailed information on the LINKNLOAD parameters and optional keywords see the discussion of LINKNLOAD in the PV‑WAVE Reference.
Discussion
LINKNLOAD lets you call a C function (or a FORTRAN function) from PV‑WAVE almost as if you were calling a PV‑WAVE function. The called function can obtain information from PV‑WAVE through passed parameters or by accessing PV‑WAVE’s variables directly (see
"Using wavevars() to Access PV-WAVE Variables").
Any PV‑WAVE data type can be passed as a parameter to a C or FORTRAN routine. By default, parameters are passed by reference (not by value), and thus it is up to the programmer whether or not the C or FORTRAN function alters the parameter’s value. Use the Value keyword to pass parameters by value. Parameters are passed in the traditional C fashion of argc and argv. The C function must know the type to expect for each parameter and must cast it to a C variable of the correct type.
For FORTRAN, since the parameters are passed as pointers, functions are provided to access their values. These functions are:
WLNL_GETBYTE WLNL_GETSHORT WLNL_GETINT32 WLNL_GETLONG WLNL_GETFLOAT WLNL_GETDOUBLE WLNL_GETCOMPLEX WLNL_GETSTRING WLNL_GETBYTE_ARRAY WLNL_GETSHORT_ARRAY WLNL_GETINT32_ARRAY WLNL_GETLONG_ARRAY WLNL_GETFLOAT_ARRAY WLNL_GETDOUBLE_ARRAY WLNL_GETCOMPLEX_ARRAY WLNL_GETSTRING_ARRAY For detailed information on these functions, see the file:
(UNIX) $WAVE_DIR/util/variables/README
note | Make sure the number, type, and dimension of the parameters passed to the external function match what the external function expects (this can most easily be done from within PV‑WAVE before calling LINKNLOAD). Furthermore, the length of string parameters must not be altered and multi-dimensional arrays are flattened to one-dimensional arrays. Because internal C longs are 8 bytes on 64-bit UNIX platforms, passing longs from FORTRAN applications requires an INTEGER*8 declaration. Note that with LINKNLOAD, pointers are used to get the value of a variable. For example: B = WLNL_GETBYTE(VAL(ARGP(1))) Here, the value of ARGP represents a pointer, which is the same size as a long integer. Thus, ARGP needs to be declared as an INTEGER*8 variable. |
Accessing the Data in PV-WAVE Variables
Two methods exist for accessing the results generated by PV‑WAVE in a user-written application called with LINKNLOAD.
Method 1: wavevars
The first method uses wavevars, a C function that can be invoked from code linked to PV‑WAVE (either statically or dynamically) to obtain data from PV‑WAVE’s data variable space.
The wavevars calling sequence is:
result = wavevars(&argc, &argv, &argp);
For detailed information about
wavevars, see
"Using wavevars() to Access PV-WAVE Variables".
The
wavevars function can only be used from a C function. It cannot be used from a FORTRAN function; however, a FORTRAN function could be used in conjunction with a C wrapper to accomplish the same task. See
"Example 4" for information on this technique.
Method 2: The Option Programming Interface
The second method involves using the Option Programming Interface (OPI), a C-callable or FORTRAN-callable programming interface that was developed to provide greater flexibility and control than wavevars. OPI differs from wavevars in the following ways:
Uses less memory than
wavevarsCan obtain information about a single PV‑WAVE variable at a time.
Can obtain a subset of the information normally returned by
wavevars.
For detailed information on OPI, see
Creating an OPI Option in the
PV-WAVE Programmer’s Guide. .
note | To use OPI effectively with C programs, you should be a C programmer, understand the difference between call-by-reference and call-by-value, and be able to use pointers and the C malloc() function. To use OPI with FORTRAN callable libraries, you should be a FORTRAN programmer, understand the difference between call-by-reference and call-by-value, and know how to use the LOC and VAL functions. |
Example 1: Calling a C Program
In this example, parameters are passed to the C external function using the conventional (argc, argv) UNIX strategy. argc indicates the number of data pointers which are passed from PV‑WAVE within the array of pointers called argv. The pointers in argv can be cast to the desired type as the following program demonstrates.
You can find the following listed file in:
$WAVE_DIR/demo/interapp/linknloadc/linknloadc.c
#include <stdio.h>
#include "wavevars.h"
#include "opi_devel.h" /* in wave/src/priv for OPI_long def */
OPI_long WaveParams(argc, argp)
int argc;
char *argp[];
{
char *b;
short *s;
int *i;
long *l;
float *f;
double *d;
COMPLEX *c;
char **str;
if (argc != 8) {
fprintf(stderr,"wrong # of parameters(%d)\n",argc);
return(0);
}
b = ((char **)argp)[0];
s = ((short **)argp)[1];
i = ((int **)argp)[2];
l = ((long **)argp)[3];
f = ((float **)argp)[4];
d = ((double **)argp)[5];
c = ((COMPLEX **)argp)[6];
str = ((char ***)argp)[7];
fprintf(stderr,"%d %d %d %ld %f %lf <%f,%fi> %s\n",
(int)b[0],(int)s[0],i[0],(long)l[0],f[0],d[0],c[0].r,c
[0].i,str[0]);
return(1);
}
Compiling the Example C Routine
See the example’s associated README.md for details on compiling/linking the example.
Accessing the External Function with LINKNLOAD
The following PV‑WAVE code demonstrates how the C function defined in this example could be invoked.
ln = LINKNLOAD('linknloadc.so', 'WaveParams', BYTE(1), 2, 23i, $
LONG(3), FLOAT(4), DOUBLE(5), COMPLEX(6,7), 'eight')
The resulting output is:
1 2 23 3 4 5 (6,7) 'eight'
Using the INFO command, you can see that LINKNLOAD returns the scalar value 1.
INFO, ln
; PV-WAVE prints: LN LONG = 1
The example program works with both scalars and arrays since the actual C program above only looks at the first element in the array and since PV‑WAVE collapses multi-dimensional arrays to one-dimensional arrays:
ln = LINKNLOAD('linknloadc.so','WaveParams', [BYTE(1)], $
[[2,3],[4,5]], [[2i,3],[4,5]], [LONG(3)], [FLOAT(4)], $
[DOUBLE(5)], [COMPLEX(6,7)], ['eight'])
The resulting output is:
1 2 2 3 4 5 (6,7) 'eight'
Example 2: Calling a FORTRAN Program
In this example, parameters are passed from PV‑WAVE to the FORTRAN external function. Variables from PV‑WAVE are passed as pointers to the FORTRAN function. In the FORTRAN function, the
wlnl_get* functions are used to retrieve the values of the variables. See
"Discussion" for more information on these functions.
You can find the following listed file in:
$WAVE_DIR/demo/interapp/linknloadfor/linknloadfor.f
INTEGER*4 FUNCTION WAVEPARAMS(ARGC, ARGP)
INTEGER*4 ARGC, ARGP(*)
BYTE B
INTEGER*2 S
INTEGER*4 I
INTEGER*4 L
REAL*4 F
DOUBLE PRECISION D
STRUCTURE /CMPLX/
REAL R,I
END STRUCTURE
RECORD /CMPLX/ C
INTEGER*4 RET
CHARACTER*80 STR
INTEGER*4 NCHAR
INTEGER*4 WLNL_GETLONG
INTEGER*4 WLNL_GETINT32
INTEGER*4 WLNL_GETSTRING
INTEGER*4 WLNL_GETCOMPLEX
INTEGER*2 WLNL_GETSHORT
BYTE WLNL_GETBYTE
REAL WLNL_GETFLOAT
DOUBLE PRECISION WLNL_GETDOUBLE
IF (LOC(ARGC) .NE. 8) THEN
PRINT *,'Wrong # of parameters',LOC(ARGC)
WAVEPARAMS = 0
RETURN
ENDIF
B = WLNL_GETBYTE(%VAL(ARGP(1)))
S = WLNL_GETSHORT(%VAL(ARGP(2)))
I = WLNL_GETINT32(%VAL(ARGP(3)))
L = WLNL_GETLONG(%VAL(ARGP(4)))
F = WLNL_GETFLOAT(%VAL(ARGP(5)))
D = WLNL_GETDOUBLE(%VAL(ARGP(6)))
RET = WLNL_GETCOMPLEX(%VAL(ARGP(7)),C.R,C.I)
NCHAR = WLNL_GETSTRING(%VAL(ARGP(8)),STR,%VAL(80))
PRINT 100,B,S,I,L,F
100 FORMAT(' BYTE=',I3,',SHORT=',I6,',INT32=',I8,',LONG=',I8,
+ ',REAL=',F10.5)
PRINT 200,D,C.R,C.I
200 FORMAT(' DOUBLE=',D15.5,',COMPLEX=[',F10.5,',',F10.5,']')
PRINT 300,STR,NCHAR
300 FORMAT(' STRING=',A80,',NCHAR=',I6)
WAVEPARAMS = 1
RETURN
END
Compiling the Example FORTRAN Routine
See the example’s associated README.md for details on compiling/linking the example.
Accessing the External Function with LINKNLOAD
The following PV‑WAVE code demonstrates how the FORTRAN function defined in this example could be invoked.
ln = LINKNLOAD('linknloadfor.so','waveparams', BYTE(1), 2, $
23i, LONG(3), FLOAT(4), DOUBLE(5), COMPLEX(6,7), 'eight')
The resulting output is:
BYTE= 1,SHORT= 2,INT32= 23,LONG= 3,REAL= 4.00000
DOUBLE= 0.50000D+01,COMPLEX=[ 6.00000, 7.00000]
STRING=eight ,NCHAR= 5
Using the INFO command, you can see that LINKNLOAD returns the scalar value 12345 as expected.
INFO, ln
; PV-WAVE prints: LN LONG = 12345
The example program works with both scalars and arrays since the actual FORTRAN program above only looks at the first element in the array and since PV‑WAVE collapses multi-dimensional arrays to one-dimensional arrays:
ln = LINKNLOAD('linknloadfor.so','waveparams', [BYTE(1)], $
[[2,3],[4,5]], [[2i,3],[4,5]], [LONG(3)], [FLOAT(4)], $
[DOUBLE(5)], [COMPLEX(6,7)], ['eight'])
The resulting output is:
BYTE= 1,SHORT= 2,INT32= 2,LONG= 3,REAL= 4.00000
DOUBLE= 0.50000D+01,COMPLEX=[ 6.00000, 7.00000]
STRING=eight ,NCHAR= 5
Example 3
In this example, the PV‑WAVE program calls the C function (via LINKNLOAD), passing it parameters. The C function modifies these parameters and also accesses PV‑WAVE’s variable data space directly. The C function then returns control to PV‑WAVE, passing to PV‑WAVE the result of the function.
This example contains two programs:
linknloadc_wavevars.pro—A PV‑WAVE main program that uses LINKNLOAD to call a C function. The PV‑WAVE program passes parameters to the C function, which modifies the parameters’ values. When control is returned to PV‑WAVE, the values of the PV‑WAVE variables which were passed as parameters are changed.
linknloadc_wavevars.c—The C function to be called by PV‑WAVE via LINKNLOAD.
The C and PV‑WAVE code described in this example is available online in the directory:
$WAVE_DIR/demo/interapp/linknloadc_wavevars
The C function must be compiled as a shareable object, as described in the example README.md. It is because the C function is linked shareable and shares the same data space with PV‑WAVE that the C function can access PV‑WAVE variables directly.
Running the Example Program
Enter PV‑WAVE and type the following at the WAVE> prompt:
.RUN linknloadc_wavevars
For some UNIX operating systems, you need to set the
LD_LIBRARY_PATH environment variable to the directory containing the file
linknloadc_wavevars.so. You must set this variable even if that file is in the current working directory. See your system administrator to determine the correct directory. Refer to
"Manipulating Environment Variables" for general information about environment variables and PV‑WAVE.
Example 4
In this example, the PV‑WAVE program calls a C wrapper function, passing it PV‑WAVE variables as parameters. The C wrapper calls the FORTRAN function, passing along the same parameters. The FORTRAN function modifies the values of the PV‑WAVE variables it receives as parameters. The FORTRAN function then returns control to PV‑WAVE, passing to PV‑WAVE the result of the function. The new values, assigned to the PV‑WAVE variables by the FORTRAN program, are accessible within PV‑WAVE upon return from the FORTRAN program.
This example contains three programs:
linknloadfor_wavevars.pro—A PV‑WAVE main program that uses LINKNLOAD to call a FORTRAN function. The PV‑WAVE program passes parameters to a C wrapper, which in turn calls the desired FORTRAN function to modify the PV‑WAVE parameters. When control is returned to PV‑WAVE, the values of the PV‑WAVE variables which were passed as parameters are changed.
linknloadfor_wrapper.c—A C function that is called by PV‑WAVE, via LINKNLOAD. This routine is a C wrapper that allows a PV‑WAVE program to pass parameters to and invoke a FORTRAN function. The FORTRAN function can modify the values of the PV‑WAVE variables passed as parameters and the modified values will be accurately reflected upon return to PV‑WAVE.
linknloadfor_wavevars.f—The FORTRAN function to be called by the C wrapper.
The Fortran, C, and PV-WAVE code described in this example is available online in the directory:
$WAVE_DIR/demo/interapp/linknloadfor_wavevars
The Fortran and C functions must be compiled as a shareable object, as described in the example README.md.
Running the Example Program
Enter PV‑WAVE and type the following at the WAVE> prompt:
.RUN linknloadfor_wavevars
If necessary, setting the LD_LIBRARY_PATH environment variable may vary depending on how your operating system was installed. See your system administrator to determine the correct directory. Refer to
"Manipulating Environment Variables" for general information about environment variables and PV‑WAVE.