\documentclass{article} \usepackage{noweb}% \usepackage{times}% \input nowebmargins% \pagestyle{noweb}% \begin{document} \title{Dynamic Loading on an SGI in \texttt{Splus}} \author{B. Narasimhan\\ Department of Statistics\\ Stanford University\\ Stanford, CA 94305} \date{Version of \today} \maketitle \tableofcontents \begin{abstract} This little note tells you how to dynamically load \texttt{Fortran} and \texttt{C} programs in \texttt{Splus} on our SGI server where shared libraries are used. \end{abstract} \section{The Problem} \label{sec:prob} Consider the following fortran subroutine that takes three arguments, an array $x$, an integer $n$ that indicates the length of the array and a storage area [[result]] where it should return the sum of the elements in the array. <>= subroutine sumvec(x,n,sum) real x(n), sum integer n sum = 0.0 do 10 i=1,n sum = sum + x(i) 10 continue return end @ %def sumvec @ How can one call such a function from \texttt{Splus}? Perform the following steps. <>= <> <> <> <> @ \subsection{Compiling the Fortran routine} \label{sec:comp} Assuming that the fortran program is stored in the file \texttt{foo.f} do the following. <>= rgmiller> f77 -c foo.f @ %def foo.o @ \subsection{Creating the shared library} \label{sec:creat} Let us called the shared library \texttt{libfoo.so}. Create the shared library as follows. <>= rgmiller> Splus SHLIB -o libfoo.so foo.o @ %def libfoo.so @ \subsection{Shortcut} \label{sec:shortcut} In recent versions of \texttt{Splus}, the two steps mentioned above can be combined into one. <>= rgmiller> Splus SHLIB -o libfoo.so foo.f @ \subsection{Loading the shared library} \label{sec:load} Load the shared library into \texttt{Splus} as follows. <>= > dyn.load.shared("./libfoo.so") @ \subsection{Invoking the routine.} \label{sec:invoke} The function can now be invoked from \texttt{Splus}. However a few words of warning before we illustrate the use. \texttt{Splus} stores its variables in its own format and they must be coerced into a format palatable to fortran. One uses the \texttt{storage.mode} function of \texttt{Splus} for this purpose. Table~\ref{tab:corres} from Venables and Ripley\cite{vena:ripl:1994} below shows the correspondence between \texttt{Splus}, \texttt{C} and \texttt{Fortran} variables. \begin{table}[htbp] \begin{center} \leavevmode \begin{tabular}{lll} \multicolumn{1}{l}{\textbf{\texttt{Splus} storage mode}} & \multicolumn{1}{l}{\textbf{\texttt{C}}} & \multicolumn{1}{l}{\textbf{\texttt{Fortran}}}\\ \texttt{"logical"} & \texttt{long *} & \texttt{LOGICAL}\\ \texttt{"integer"} & \texttt{long *} & \texttt{INTEGER}\\ \texttt{"single"} & \texttt{float *} & \texttt{REAL}\\ \texttt{"double"} & \texttt{double *} & \texttt{DOUBLE PRECISION}\\ \texttt{"character"} & \texttt{char **} & \texttt{CHARACTER (*)}\\ \texttt{"complex"} & \texttt{struct \{} & \texttt{DOUBLE COMPLEX}\\ & \multicolumn{1}{c}{\texttt{ double re, im;\}*}} &\\ \texttt{"list"} & \texttt{void **} &\\ \end{tabular} \caption{Data type correspondence between \texttt{Splus}, \texttt{C} and \texttt{Fortran}} \label{tab:corres} \end{center} \end{table} So here is an example invocation. <>= > dyn.load.shared("./libfoo.so", symbols=symbol.F(sumvec)) > x <- 1:10 > storage.mode(x) <- "single" > n <- as.integer(length(x)) > y <- 0 > storage.mode(y) <- "single" > .Fortran("sumvec", x, n, result = y) @ %def x n @ The result is a list with all the arguments you passed. You can refer to the result as usual via \verb+$result+. Note carefully how the storage modes are coerced to match the single precision reals that fortran expects. If some variables are double precision and others single precision, make sure that you coerce the storage modes appropriately. \section{Tips} \label{sec:tips} \begin{itemize} \item Debug your \texttt{Fortran} or \texttt{C} programs \emph{before} calling them from \texttt{Splus}. As statisticians, we would like to avoid confounding! \item You cannot use \texttt{print} statements in your \texttt{Fortran} routines without some hacks (and hacks they really are). See the next section for more information. This restriction does not apply to \texttt{C} programs. (No, \texttt{f2c} will not help here.) \item Note how subroutines rather than functions are used. \end{itemize} \section{Troubleshooting} \label{sec:troubleshooting} Most errors are likely to be due to lax attention to storage aspects. So the first question you should ask yourself is whether you've coerced the storage modes of your arguments correctly. \paragraph{Frequently Asked Questions} \begin{enumerate} \item I get an error message such as: \begin{verbatim} Error in .C("S_QPE_shobjlist_load",: Can't load (dlopen) library ./libfoo.so: 21859:/usr/local/lib/S-PLUS/cmd/Sqpe: rld: Fatal Error: unresolvable symbol in ./libfoo.so: bar \end{verbatim} This is due to the fact that your program references other functions or routines that could not be found. Make sure that you have all of them available. In the above example, the function \texttt{bar} could not be located. If the file \texttt{bar.c} contains that function, compile it and put both \texttt{foo.o} and \texttt{bar.o} into the library. The short way to do this is of course to use: \begin{verbatim} rgmiller> Splus SHLIB -o libfoo.so foo.c bar.c \end{verbatim} \item I get an error message such as: \verb+Error in .C("S_QPE_shobjlist_load",:...)+, even when I see that there is a file \texttt{libfoo.so} in my directory. Use the full pathname of the file such as \texttt{dyn.load.shared("./libfoo.so")}. One can set environment variables like \verb+LD_LIBRARY_PATH+ but I have good reasons to maintain that the former is the easiest and cleanest solution. \item A friend gave me his Fortran code for doing \emph{blah}. I want to call the routine from \texttt{Splus}. If I do the straightforward thing, I get errors. How should I proceed? Follow these steps. \begin{enumerate} \item Is the code giving you a function or a subroutine? If the former, convert it into the latter. This is trivial to do if you know fortran. \item Is the routine using \texttt{print} or \texttt{write} statements? If so, comment them out. If the program is small enough, this is usually easy to do. However, such statements might provide important diagnostic information. In other situations, the program might be so large that it might be impossible to comment all of them out safely without clobbering the program. Then you must use the routines \texttt{DBLEPR}, \texttt{REALPR}, or \texttt{INTPR} described in \cite{vena:ripl:1994} for printing the output. If the \texttt{print} or \texttt{write} statements provide no useful information that can be obtained otherwise, you can trick \texttt{Splus} by writing some dummy routines. Again, refer to \cite{vena:ripl:1994}. \end{enumerate} \item I made a change to my file \texttt{foo.c}, recompiled and reloaded the dynamic library using \texttt{dyn.load.shared} and yet my program behaves exactly as if the old version of \texttt{foo.c} is in effect. What gives? Read the help page for \texttt{dyn.load.shared} carefully. Use the symbols argument to force \texttt{dyn.load.shared} to read in the redefined routines. The dynamic loading mechanism loads the definition of a symbol by first checking if it is already defined. If so, no loading of the symbol is done. Thus, if you repeatedly load a shared library using the bare \texttt{dyn.load.shared} function, you'll be effectively doing nothing. The \texttt{symbols} argument forces reloading of the symbol definition. \emph{It is therefore prudent to use the \texttt{symbols} argument until you have completely debugged your dynamically loaded routines.} \end{enumerate} \section{Remarks} \label{sec:remarks} In my opinion, the whole issue of dynamic loading is made unnecessarily complicated in \texttt{Splus} by having functions like \texttt{dyn.load}, \texttt{dyn.load2}, and \texttt{dyn.load.shared}. There should be one function called \texttt{dyn.load} that does the appropriate thing for the platform. For example, \texttt{Lisp-Stat}\cite{tier:1990}, which borrowed some of the dynamic concepts ideas from \textsl{S} has done this very thing: just one function called \texttt{dyn-load} does different things on different platforms. I hope this gets cleaned up soon. Dynamically loading \texttt{C} routines is really no different, except that the symbols can be specified to the \texttt{dyn.load.shared} function via \texttt{symbol.C} instead of \texttt{symbol.F}. \section{Indices} \label{sec:index} \subsection{Code Chunks} \label{sec:code-chunks} This index is generated automatically. The numeral is that of the first definition of the chunk. \nowebchunks \subsection{Index of Identifiers} \label{sec:identifiers} Here is a list of the identifiers used, and where they appear. Underlined entries indicate the place of definition. This index is generated automatically. \nowebindex \bibliographystyle{plain} \bibliography{dynload} \end{document}