John Goerzen | 27 Jul 20:27

Suggestions for #defines with FFI

Hi,

I'm writing a Haskell interface to a library that #defines about 100
constants corresponding to numeric exit codes.  It also defines hundreds
of contants, over the same numbering ranges, for other purposes.  The
exit codes are non-contiguous as well.

So my question is: is there a nice way I can represent this in Haskell,
preferably without having to key in all 100 constants?  Or will I just
have to list all the options and give up type checking to differentiate
one purpose of a constant from another?

Thanks,

-- John
Dimitry Golubovsky | 27 Jul 20:57

RE: Suggestions for #defines with FFI

John,

Could you please give an example of such constant definitions? Is it
possible to look at the include file?

--

-- 
Dimitry Golubovsky

Anywhere on the Web
John Goerzen | 27 Jul 22:48

Re: Suggestions for #defines with FFI

On Wed, Jul 27, 2005 at 03:01:18PM -0400, Dimitry Golubovsky wrote:
> John,
> 
> Could you please give an example of such constant definitions? Is it
> possible to look at the include file?

Sure.  I'm writing an interface to OpenLDAP.  So, from ldap.h, we see:

#define LDAP_OPT_SUCCESS        0
..
#define LDAP_SUCCESS                            0x00
#define LDAP_OPERATIONS_ERROR           0x01
#define LDAP_PROTOCOL_ERROR                     0x02
#define LDAP_TIMELIMIT_EXCEEDED         0x03
#define LDAP_SIZELIMIT_EXCEEDED         0x04
#define LDAP_COMPARE_FALSE                      0x05
...
#define LDAP_LOOP_DETECT                        0x36
#define LDAP_UPDATE_ERROR(n)    LDAP_RANGE((n),0x40,0x47) /* 64-69,71 */
#define LDAP_NAMING_VIOLATION           0x40
...
#define LDAP_MOD_ADD            (0x0000)
#define LDAP_MOD_DELETE         (0x0001)
#define LDAP_MOD_REPLACE        (0x0002)
#define LDAP_MOD_BVALUES        (0x0080)
John Goerzen | 27 Jul 22:52

Re: Suggestions for #defines with FFI

On Wed, Jul 27, 2005 at 03:01:18PM -0400, Dimitry Golubovsky wrote:
> John,
> 
> Could you please give an example of such constant definitions? Is it
> possible to look at the include file?

Incidentally, I looked at hsffig.  There were a couple issues with using
it for this:

1) It didn't declare types for the imported constants, so Haddock
wouldn't generate a list over it.

2) It included all sorts of other #defined items, from other headers
(stdio.h maybe), making it unsuitable to re-export directly to the user.
(I'd have to re-key everything anyway)

3) It tried to list some of the GCC internal conditionals as constants,
making the .hsc not compile unless I manually removed some of them.

I really like the idea, though.  Autodetecting these is great, since
they could vary somewhat from implementation to implementation.

Right now, I'm using hsc2hs, and writing something like this:

#enum LDAPInt, , LDAP_PORT, LDAPS_PORT, LDAP_API_VERSION, LDAP_VENDOR_NAME, \
      LDAP_OPT_API_INFO, LDAP_OPT_DESC, LDAP_OPT_DEREF, \
      LDAP_OPT_SIZELIMIT, LDAP_OPT_TIMELIMIT, LDAP_OPT_REFERRALS, \
      LDAP_OPT_RESTART, LDAP_OPT_PROTOCOL_VERSION, LDAP_OPT_SERVER_CONTROLS, \

That boils down to this:
(Continue reading)

Donn Cave | 27 Jul 23:15

Re: Suggestions for #defines with FFI

On Wed, 27 Jul 2005, John Goerzen wrote:
...
> Right now, I'm using hsc2hs, and writing something like this:
> 
> #enum LDAPInt, , LDAP_PORT, LDAPS_PORT, LDAP_API_VERSION, LDAP_VENDOR_NAME, \
>       LDAP_OPT_API_INFO, LDAP_OPT_DESC, LDAP_OPT_DEREF, \
>       LDAP_OPT_SIZELIMIT, LDAP_OPT_TIMELIMIT, LDAP_OPT_REFERRALS, \
>       LDAP_OPT_RESTART, LDAP_OPT_PROTOCOL_VERSION, LDAP_OPT_SERVER_CONTROLS, \
> 
> That boils down to this:
> 
> ldapPort :: LDAPInt
> ldapPort =  389
> ldapsPort :: LDAPInt
> ldapsPort =  636
> 
> So I still lack typechecking, and have to manually key in all the
> identifiers, but at least the system pulls their values and types in for
> me.

I wanted them to be enumerated types in Haskell where appropriate,
and the only thing I could think of was

  data LDAPOpt = LDAP_OPT_X_TLS
        | LDAP_OPT_X_TLS_REQUIRE_CERT
        | LDAP_OPT_PROTOCOL_VERSION
        | LDAP_OPT_DEBUG_LEVEL
  fromLDAPOpt LDAP_OPT_X_TLS = (#const LDAP_OPT_X_TLS)
  fromLDAPOpt LDAP_OPT_X_TLS_REQUIRE_CERT = (#const LDAP_OPT_X_TLS_REQUIRE_CERT)
  fromLDAPOpt LDAP_OPT_PROTOCOL_VERSION = (#const LDAP_OPT_PROTOCOL_VERSION)
(Continue reading)

Dimitry Golubovsky | 28 Jul 06:08

Re: hsffig issues (was: Suggestions for #defines with FFI)

John Goerzen wrote:

> Incidentally, I looked at hsffig.  There were a couple issues with using
> it for this:
> 
> 1) It didn't declare types for the imported constants, so Haddock
> wouldn't generate a list over it.

I never tried to make hsffig output documentable: the whole idea is just 
to write "import FOO_H" in Haskell as one would write "#include <foo.h>" 
in C.

> 2) It included all sorts of other #defined items, from other headers
> (stdio.h maybe), making it unsuitable to re-export directly to the user.
> (I'd have to re-key everything anyway)

I mentioned this in the Tutorial: hsffig gives the Haskell compiler the 
same look at information about the library to import as the C compiler 
would have. It is hard to separate such things: your header file that 
you include may include ten other headers, five of them related to the 
library, and the rest from /usr/include

And you do not need to reexport because wherever you need the bindings, 
you just import them there. You still have to have some library 
interface layer in your application, but you do not focus on type 
signatures of foreign functions.

> 3) It tried to list some of the GCC internal conditionals as constants,
> making the .hsc not compile unless I manually removed some of them.

(Continue reading)

John Goerzen | 28 Jul 14:57

Re: hsffig issues (was: Suggestions for #defines with FFI)

On Thu, Jul 28, 2005 at 12:08:11AM -0400, Dimitry Golubovsky wrote:
> >1) It didn't declare types for the imported constants, so Haddock
> >wouldn't generate a list over it.
> 
> I never tried to make hsffig output documentable: the whole idea is just 
> to write "import FOO_H" in Haskell as one would write "#include <foo.h>" 
> in C.

Yeah, I understand.  I'm just trying to push it a bit ;-)

I'd rather be able to directly re-export all that again, saving me
having to key it all in manually.  Or perhaps declare my own transformer
over it (a plugin of sorts, perhaps, so I could work nicely with
enums-from-macros in the scenario I've described)

> I mentioned this in the Tutorial: hsffig gives the Haskell compiler the 
> same look at information about the library to import as the C compiler 
> would have. It is hard to separate such things: your header file that 
> you include may include ten other headers, five of them related to the 
> library, and the rest from /usr/include

I think, though, that it shouldn't be too hard to filter the data coming
back from gcc.  For instance, you could just look for stuff after a line
ilke:

# 1 "/usr/include/ldap.h"

and start ignoring when you see a reference to any other file.

> >3) It tried to list some of the GCC internal conditionals as constants,
(Continue reading)

Tomasz Zielonka | 27 Jul 22:52

Re: Suggestions for #defines with FFI

On Wed, Jul 27, 2005 at 01:28:38PM -0500, John Goerzen wrote:
> I'm writing a Haskell interface to a library that #defines about 100
> constants corresponding to numeric exit codes.  It also defines hundreds
> of contants, over the same numbering ranges, for other purposes.  The
> exit codes are non-contiguous as well.
> 
> So my question is: is there a nice way I can represent this in Haskell,
> preferably without having to key in all 100 constants?

Did you consider hsc2hs?

Best regards
Tomasz
John Goerzen | 28 Jul 14:12

Re: Suggestions for #defines with FFI

On Wed, Jul 27, 2005 at 10:52:41PM +0200, Tomasz Zielonka wrote:
> On Wed, Jul 27, 2005 at 01:28:38PM -0500, John Goerzen wrote:
> > I'm writing a Haskell interface to a library that #defines about 100
> > constants corresponding to numeric exit codes.  It also defines hundreds
> > of contants, over the same numbering ranges, for other purposes.  The
> > exit codes are non-contiguous as well.
> > 
> > So my question is: is there a nice way I can represent this in Haskell,
> > preferably without having to key in all 100 constants?
> 
> Did you consider hsc2hs?

Yes.  That's what I'm using now.  It does pull in the values for the
consts, but that's about it.  I still have to key everything in
manually.

-- John
Malcolm Wallace | 28 Jul 15:02

Re: Suggestions for #defines with FFI

John Goerzen <jgoerzen <at> complete.org> writes:

> On Wed, Jul 27, 2005 at 10:52:41PM +0200, Tomasz Zielonka wrote:
> > On Wed, Jul 27, 2005 at 01:28:38PM -0500, John Goerzen wrote:
> > > I'm writing a Haskell interface to a library that #defines about 100
> > > constants corresponding to numeric exit codes.  It also defines hundreds
> > > of contants, over the same numbering ranges, for other purposes.  The
> > > exit codes are non-contiguous as well.
> > > 
> > > So my question is: is there a nice way I can represent this in Haskell,
> > > preferably without having to key in all 100 constants?
> > 
> > Did you consider hsc2hs?
> 
> Yes.  That's what I'm using now.  It does pull in the values for the
> consts, but that's about it.  I still have to key everything in
> manually.

I don't know whether this will be a helpful suggestion or not,
because it still requires to key in all constants, but nhc98 uses the
following configuration technique to grab the "errno.h" constants into
an enumerated Haskell datatype, with instances of Eq, Ord, and Enum.

There is a little haskell program, GenerateErrNo.hs, which is run
to generate a C program, which is then run to generate the Haskell
module I require.  The source code is attached.  Maybe you can adapt
it for your purposes.

Another suggestion for an FFI tool specifically designed for this
kind of problem is c2hs:
(Continue reading)


Gmane