[Openmcl-devel] Accessing foreign #define'd constants
gb at clozure.com
Wed Dec 22 19:13:54 EST 2004
On Wed, 22 Dec 2004, David Steuber wrote:
> On Dec 22, 2004, at 12:46 PM, Denis Bueno wrote:
> > The problem was that what I had assumed was a C constant was actually
> > a #define'd C macro ... so of course I couldn't call it.
> Right. #define is simply a text substitution. I don't know if I am
> comfortable calling them C macros ;-)
> > I know it's not the responsibility of the openmcl documentation to
> > teach people C, but, maybe a little note (in sec. 9.8?) about the
> > preferred way to have openmcl call C macros (like by making "glue" via
> > a my_macro_call.c file with a my_macro_call() function and calling
> > that function from openmcl, or something) would be helpful to anyone
> > who runs into this problem in the future. I'm certainly willing to
> > write it, if that is acceptable.
> The Carbon headers make a lot of use of enums for C constants. These
> have the advantage of being real constants that are also available via
> #$. What I hate though is the frequent practice of enums that are
> assigned like this:
> foo = 'ctrl',
> Joy! At least #$ works. When the same thing is a #define... Well
> then you have to figure out what the UInt32 that is.
Here's a little-known (perhaps because it's undocumented ...) fact:
if the reader token that follows #$ is a quoted string of length 4,
#$ produces an integer constant out of the char-codes, so:
Welcome to OpenMCL Version (Beta: Darwin) 0.14.2-p1!
? (format t "#x~x" *)
In most cases, #$ can be used to reference constants that were defined
#define <name> <expression>
whether or not this works generally has to do with how complicated the
C code in <expression> is. There's no requirement that the right-hand
part of the #define - what I'm calling the <expression> - is even well-
formed C code. If it looks like it is, OpenMCL's interface translator
will try to parse and evaluate it; it's able to do a fairly good job
of this in practice, but undoubtedly misses some things. It -does-
try to catch cases like:
#define FOO 1
#define BAR (FOO + 17)
and will make multiple passes to try to resolve forward references
#define BAR (FOO + 17)
#define FOO 1
C macros can also take parameters, as in:
#define MAX(a,b) (a) > (b) ? (a) : (b)
The interface translator ... um, assumes that this is some sort of
irritating line noise and skips over it (trying to translate arbitrary
parameterized C macros into "equivalent" Lisp macros is a hard problem).
The interface translator should do a very good job of making constants
defined as part of a C enumeration available to #$, and should catch
a lot of cases where constants are defined via '#define <name> <expr>';
its success in doing so generally depends on how much sense it can
make out of <expr>.
I'd be curious about cases where #$ doesn't find things; it's been a
while since I checked, but I think of the translator's miss rate as
being pretty low. (It's certainly possible that the Carbon headers
use C idioms that the translator doesn't understand, and - depending
on what they are - it might be possible to make it understand them.)
> Bottom line though is when you are using FFI to call into C (and having
> C call back!), it really does help to know some C.
That's certainly true. I -think- that it's true that the total number
of idioms you have to learn in order to translate a C example program
into OpenMCL's FFI is fairly small, but the learning curve could probably
be made less steep with a few examples.
More information about the Openmcl-devel