I can remember hitting several issues with Delphi, that might be applicable to other languages too. From simple to complicated (in Delphi), these are: how to write a DLL and export procedures (easy). how to declare parameters (VAR or pointers to arrays; pretty simple). how arrays of >1 dimension map to R arrays (easy). what call mode to use for procedures (i.e. stack order and removal of parameters; I had always used STDCALL with S and R, and then found I was getting bugs with R 1.6.1. So in desperation I eventually changed this at random to C-CALL, and things started working again in R-- and continued to work in S. To my continued puzzlement, actually.) how to handle & return character strings (The only way I've found to return a string of unknown length, was to call a Delphi function twice; the first time it merely returns the number of characters in the string. Then create a string of spaces of the correct length in R, and explicitly put that string in a .C call to the Delphi function, which this time can fill in the actual characters.) how to get the Delphi debugger to work on a DLL being called by R. This is incredibly easy in S but rather difficult in R, because of a quirk to do with starting directories. Then there are one or two tricks I've sometimes used: e.g. how to return a Delphi pointer to R so that a "persistent" Delphi object can be created with one call to a Delphi function from R, then accessed again on a subsequent call. Useful even with simple things like returning a string, and essential with really complex structures. All languages will have their own tricks, which are well worth some informal documentation somewhere. And then there is the business of turning the R headers into Delphi equivalents-- a work in progress. cheers Mark ******************************* Mark Bravington CSIRO (CMIS) PO Box 1538 Castray Esplanade Hobart TAS 7001 phone (61) 3 6232 5118 fax (61) 3 6232 5012 Mark.Bravington@csiro.au #-----Original Message----- #From: Duncan Murdoch [mailto:murdoch@stats.uwo.ca] #Sent: Tuesday, 3 December 2002 1:15 AM #To: ripley@stats.ox.ac.uk #Cc: r-devel@stat.math.ethz.ch #Subject: Re: [Rd] Samples of external code with various compilers? # # #On Mon, 2 Dec 2002 08:07:19 +0000 (GMT), you wrote in message #<Pine.LNX.4.31.0212020753570.1625-100000@gannet.stats>: # #>I think there is information and lots of examples already for #Fortran. # #I was thinking of two additions: # # 1. Rewriting the samples in sections 4.2 and/or 4.5 in Fortran, #Delphi, etc. I might make them a little more elaborate, e.g. showing #how to return a character string. # # 2. Write up the details of how to do it in various specific #compilers. For example, if you're using Microsoft Visual Fortran, how #do you create a DLL, how do you set the exported entry points, what #bugs do you need to work around. # #>Base R has only interfaces for C and Fortran (and that via C-style #>linkage): SJava adds .Java. So is the issue how to write in other #>languages to use a C interface? `how to dyn.load functions' #is easy: you #>just create an appropriate compiled object, a shared library, #a DLL or (on #>MacOS X as I understand it) a module. The issues seem to be #to export the #>symbols correctly, and even more to import ones from R correctly. # #Yes, that's the main issue. There are also issues even with C: if #you're using some compiler other than gcc, you probably won't compile #using R SHLIB, so what do you need to do? # #Duncan # #______________________________________________ #R-devel@stat.math.ethz.ch mailing list #http://www.stat.math.ethz.ch/mailman/listinfo/r-devel #
Samples of external code with various compilers?
4 messages · Mark Bravington, Duncan Murdoch, Brian Ripley
On Tue, 3 Dec 2002 Mark.Bravington@csiro.au wrote:
I can remember hitting several issues with Delphi, that might be applicable to other languages too. From simple to complicated (in Delphi), these are:
(Most of these are Windows-specific.)
how to write a DLL and export procedures (easy). how to declare parameters (VAR or pointers to arrays; pretty simple). how arrays of >1 dimension map to R arrays (easy). what call mode to use for procedures (i.e. stack order and removal of parameters; I had always used STDCALL with S and R, and then found I was getting bugs with R 1.6.1. So in desperation I eventually changed this at random to C-CALL, and things started working again in R-- and continued to work in S. To my continued puzzlement, actually.)
Well, that *is* documented. For R in readme.packages under `Using other compilers and languages' which is quite a short section. So if people don't read what is already there, is there any point in expanding it? It's also documented for S-PLUS (if that is what you mean by `S': it reflects a lot of work by Insightful on top of Lucent S4). [...]
Brian D. Ripley, ripley@stats.ox.ac.uk Professor of Applied Statistics, http://www.stats.ox.ac.uk/~ripley/ University of Oxford, Tel: +44 1865 272861 (self) 1 South Parks Road, +44 1865 272860 (secr) Oxford OX1 3TG, UK Fax: +44 1865 272595
On Tue, 3 Dec 2002 10:01:08 +1100 , Mark.Bravington@csiro.au wrote:
what call mode to use for procedures (i.e. stack order and removal of parameters; I had always used STDCALL with S and R, and then found I was getting bugs with R 1.6.1. So in desperation I eventually changed this at random to C-CALL, and things started working again in R-- and continued to work in S. To my continued puzzlement, actually.)
The difference between stdcall and cdecl is that in the former, the routine removes parameters from the stack, whereas in the latter, the caller does. R uses cdecl. When the routine used stdcall, the parameters would be removed twice. My guess about why this worked was that the "do_dotCode" routine had enough redundant locals that having some of them removed from the stack didn't cause obvious problems. In 1.6, do_dotCode was modified, and now it messes up if you steal its locals. Most other Windows programs use stdcall. Using the stdcall convention to call a cdecl routine means that the parameters won't be removed from the stack by either the caller or the routine. However, S-PLUS is probably like R, and only makes one call to your routine from the function that calls it. When it returns, the extra junk on the stack is removed. Since stdcall is the Windows standard, and R uses cdecl, I've been thinking lately about whether it would be worth putting in stdcall as an option to .C and .Fortran. Possibly we could just switch to stdcall, and rely on the behaviour in the paragraph above to handle cdecl routines, but that sounds pretty ugly to me. Duncan Murdoch
On Tue, 3 Dec 2002, Duncan Murdoch wrote:
On Tue, 3 Dec 2002 10:01:08 +1100 , Mark.Bravington@csiro.au wrote:
what call mode to use for procedures (i.e. stack order and removal of parameters; I had always used STDCALL with S and R, and then found I was getting bugs with R 1.6.1. So in desperation I eventually changed this at random to C-CALL, and things started working again in R-- and continued to work in S. To my continued puzzlement, actually.)
The difference between stdcall and cdecl is that in the former, the routine removes parameters from the stack, whereas in the latter, the caller does. R uses cdecl. When the routine used stdcall, the parameters would be removed twice. My guess about why this worked was that the "do_dotCode" routine had enough redundant locals that having some of them removed from the stack didn't cause obvious problems. In 1.6, do_dotCode was modified, and now it messes up if you steal its locals. Most other Windows programs use stdcall. Using the stdcall convention to call a cdecl routine means that the parameters won't be removed from the stack by either the caller or the routine. However, S-PLUS is probably like R, and only makes one call to your routine from the function that calls it. When it returns, the extra junk on the stack is removed.
S-PLUS 2000 was like R. S-PLUS 6 is cleverer and tries to figure out (from the decoration on the symbol, I believe) if stdcall or cdecl is required, but it defaults to stdcall.
Since stdcall is the Windows standard, and R uses cdecl, I've been thinking lately about whether it would be worth putting in stdcall as an option to .C and .Fortran. Possibly we could just switch to stdcall, and rely on the behaviour in the paragraph above to handle cdecl routines, but that sounds pretty ugly to me.
You can't because of callbacks into R from the compiled code. That's where the problems arise with S-PLUS 6: such callbacks have to be stdcall there. stdcall requires that all the calls have the right number and type of parameters. That's really difficult to check with Fortran code (or with C code with incomplete headers). Working with S-PLUS 6 has been much more error-prone precisely because of the use of stdcall, and I don't see it as a way forward.
Brian D. Ripley, ripley@stats.ox.ac.uk Professor of Applied Statistics, http://www.stats.ox.ac.uk/~ripley/ University of Oxford, Tel: +44 1865 272861 (self) 1 South Parks Road, +44 1865 272860 (secr) Oxford OX1 3TG, UK Fax: +44 1865 272595