Issues and Examples: UNIX
Interactive IDL
Under UNIX, IDL_Main() implements IDL as seen by the interactive user. In the interactive version of IDL as shipped by ITT Visual Information Solutions, the actual main() function simply decodes its arguments to determine which options to specify and then calls IDL_Main() to do the rest. IDL_Main() calls exit() and does not return to its caller.
where:
init_options
The options value to be passed to IDL_Initialize() via the init_data argument to that function.
argc, argv
From main(). Arguments that correspond to options specified via the init_options argument should be removed and converted to init_options flags prior to calling this routine.
Compiling Programs That Call IDL
A complete discussion of the issues that arise when compiling and linking C programs is beyond the scope of this manual. The following is a brief list of basic concepts to consider when building programs that call IDL.
- Compilers for some languages add underscores at the beginning or end of user defined names. To check the naming convention employed by your compiler, use the UNIX
nm(1)command to list the symbols exported from an object file. - Every program starts execution at a known routine. In the C language, this routine is explicitly named main(). In Fortran, execution begins with the implicit main program. If you are using Callable IDL, you must provide a main() function for your program.
- When linking a C program, use the
cccommand instead of theldcommand.cccallsldto perform the link operation, and when necessary adds a directive toldthat causes the C runtime library to be used.
If you use only one language, naming details are handled transparently by the compiler, linker, and debugger. If you use more than one language, problems can arise if the different compilers use different naming conventions. For example, the Fortran compiler might add an underscore to the end of each name, while the C compiler does not. To call a Fortran routine from C, you must then include this underscore in your code (to call the function my_code, you would refer to it as my_code_). Note that you may also need to set a compiler flag to make case significant.
To determine whether your compilers use compatible naming conventions, consult your compiler documentation or experiment with small test programs using the compilers and the nm command.
If you don't use cc to link your program (if you are using ld directly or are using a Fortran compiler, for example) and you get "unsatisfied symbol" errors for symbols that are in the standard C library, try including the runtime library explicitly in your link command. Usually, adding the string -lc to the end of the command is all that is necessary.
See Compilation and Linking Details for advice on how to compile and link programs with the IDL libraries under various operating systems.
Example: Calling IDL From C
The program in the following figure is a simplified Unix-only version of calltest.c, found in the callable subdirectory of the external subdirectory of the IDL distribution. It demonstrates how to import data from a C program into IDL, execute IDL statements, and obtain data from IDL variables. It performs the following actions:
- Create an array of 10 floating point values with each element set to the value of its index. This is equivalent to the IDL command FINDGEN(10).
- Initialize Callable IDL.
- Import the floating point array into IDL as a variable named TMP.
- Have IDL print the value of TMP.
- Execute a short sequence of IDL statements from a string array:
- Set TMP to zero, causing IDL to release the pointer to the floating point array.
- Obtain a pointer to the data contained in TMP2. From examining the IDL statements executed to this point, we know that TMP2 is a scalar floating point value.
- From our C program, print the value of the IDL TMP2 variable.
- Execute a small widget program. Pressing the button allows the program to end:
a = widget_base() b = widget_button(a, value='Press When Done',xsize=300, ysize=200) widget_control, /realize, a dummy = widget_event(a) widget_control, /destroy, aSee Compilation and Linking Statements for details on compiling and linking this program.
Each line is numbered to make discussion easier. The line numbers are not part of the actual program.
Following is commentary on this program, by line number:
25
C equivalent to IDL command "F = FINDGEN(10)"
26–28
Prepare initialization data.
29
Initialize IDL
30–33
Import C array F into IDL as a FLTARR vector named TMP with 10 elements. Note use of the callback argument free_callback. This function will be called when IDL is finished with the array F, giving us a chance to properly clean up at that time.
34
Have IDL print the value of TMP.
35
Execute the commands contained in the C string array cmds defined on lines 16–17. These commands create a new IDL variable named TMP2 containing the sum of the elements of TMP, print its value, and plot the vector.
36–37
Set TMP to a new value. This will cause IDL to release the user supplied memory from lines 30–33 and call free_callback.
38–39
From C, get a reference to the IDL variable TMP2 and print its value. This should agree with the value printed by IDL on line 35. It is important to realize that the pointer to the variable or anything it points at can only be used until the next call to execute an IDL statement. After that, the pointer and the contents of the referenced IDL_VARIABLE may become invalid as a result of IDL's execution.
40
Run the simple IDL widget program contained in the array C string array cmds2 defined on lines 18–22.
41
Shut down IDL. The IDL_FALSE argument instructs IDL_Cleanup() to exit the process, so this call should not return.
44
This line should never be reached. If it is, return the UNIX failing status.
Example: Calling an IDL Math Function
This example demonstrates how to write a simple C wrapper function that allows calling IDL commands simply from another language. We implement a function named call_idl_fft() that calls the IDL FFT function operating on data imported from our C program. It returns TRUE on success, FALSE for failure:
data
A pointer to a linear array of complex data to be processed.
n
The number of data points contained in the array data.
dir
The direction of the FFT transform to take. Specify -1 for a forward transform, 1 for the reverse
The program is shown in the following figure. Each line is numbered to make discussion easier. These numbers are not part of the actual program.
Following is commentary on the above program, by line number:
7
The variable r holds the result from the function.
8
dim is used to import the data into IDL as an array.
9
A temporary buffer to format the IDL FFT command.
11–13
Import data into IDL as the variable TMP_FFT_DATA. We don't set up a free_callback because we will explicitly force IDL to release the pointer after the call to FFT.
14
Set the !ERROR_STATE system variable back to the "success" state so previous errors don't confuse our results.
15–16
Format an FFT command to IDL into buf. Note the use of the OVERWRITE keyword. This tells the IDL FFT function to place the results into the input variable rather than creating a separate output variable. Hence, the results end up in our data array without the need to obtain a pointer to the results and copy them out.
17
Have IDL execute the FFT statement. IDL_ExecuteStr() returns the value of !ERROR_STATE.CODE, which should be zero for success and non-zero in case of error. Hence, negating the result of IDL_ExecuteStr() yields the status value we require for the result of this function.
18
Set TMP_FFT_DATA to 0 within IDL. This causes IDL to release the data pointer imported previously.
20
If the call to IDL_ImportNamedArray() fails, we must report failure.
26
In order to test the call_idl_fft() function, this main program calls it twice. Taking numerical error into account the end result should be equal to the original data.
33
Set the real and imaginary part of each element to the index value.
34-36
Prepare initialization data.
37
Initialize Callable IDL.
38
Call call_idl_fft() to perform a forward transform.
39
Call call_idl_fft() to perform a reverse transform.
40–41
Print the results.
42
Shut down IDL and exit the process.
45
This line should never be reached. If it is, return the UNIX failing status.
Example: Calling IDL from Fortran
The program shown in the following figure (CALLTEST, found in the callable subdirectory of the external subdirectory of the IDL distribution) demonstrates how to import data from a Fortran program into IDL, execute IDL statements, and obtain data from IDL variables. See Compilation and Linking Statements for details on compiling and linking this program. The source code for this file can be found in the file calltest.f, located in the callable subdirectory of the external subdirectory of the IDL distribution.
Each line is numbered to make discussion easier. The line numbers are not part of the actual program:
1-27
In order to print variables returned from IDL, we must define a Fortran structure type for IDL_VARIABLE. This subroutine creates the IDL_VARIABLE structure and defines a way to print the floating-point value returned in the an IDL variable.
14-17
Define a Fortran structure equivalent to the floating-point portion of the C IDL_VARIABLE structure. Since we know our value is a floating-point number, only the floating-point portion of the structure is implemented. The structure is padded for the largest data type contained in the union. With some Fortran compilers, the combination of UNION and MAP can be used to implement the ALLTYPES union portion of the IDL_VARIABLE structure.
29-42
This subroutine is called when IDL releases the user-supplied memory.
44-164
This is the main Fortran program.
51-57
External definitions for IDL internal routines. These definitions may not be necessary with some Fortran compilers.
59-62
Define the argc and argv arguments required by IDL_Init().
66-67
Define constants equivalent to C IDL constants for the maximum array dimensions and type float.
69-77
Define parameters necessary for IDL_ImportNamedArray().
79-85
Define an array of IDL commands to be executed.
87-96
Define an array of IDL widget commands to be executed.
98-104
Null-terminate each of the command strings and store the address of each command to pass to IDL.
106-110
Initialize the floating-point array. This is the Fortran equivalent to the IDL command F=FINDGEN(10).
117-121
Initialize IDL.
125-126
Import the Fortran array F in the IDL as a 10-element FLTARR vector named TMP. Note the use of the callback argument FREE_CALLBACK(), which will be called when IDL is finished with the array F, giving us a chance to clean up at that time.
134
Execute the commands contained in the character array CMDS defined on lines 71-77. The address for each command is stored in the corresponding array element of CMD_ARGV.
139
Set the TMP variable to a new value. This causes IDL to release the user-supplied memory and call FREE_CALLBACK().
144
Get a reference to the IDL variable TMP2.
147
Call the routine PRINT_FLOAT to print the value of TMP2. This should agree with the value printed by line 130. Note that the address of the IDL variable TMP2, and its contents, can only be used until the next call to execute an IDL statement, since IDL may change the value of the referenced IDL_VARIABLE.
150-161
Execute the commands contained in the character array WIDGET_CMDS defined on lines 79-88.
163-168
Shut down IDL. The 0 argument instructs IDL_CLEANUP() to exit the process, so this call should not return.
Compilation and Linking Statements
Compilation and linking procedures used when calling IDL on a UNIX system are described in the file calltest_unix.txt in the callable subdirectory of the external subdirectory of the main IDL directory. Note that different UNIX systems have different compilation and link statements. Note also that the name of the entry point in the object may be different than that shown here, because compilers may add leading or trailing underscores to the name of the source routine.
Note
The Makefile in the architecture-specific subdirectory of the bin subdirectory of the IDL distribution contains a make rule for building the calltest application.