Recommended way to conditionally compile modules?

I have a source base that contains a number of source files that use APIs that vary by platform: every platform provides select, most provide poll, BSDs provide kqueue, and Linux provides epoll. I already have autoconf tests for these functions, and I'd like to use the results of those autoconf checks to determine which modules to compile, but I am unable to figure out how to do this in my .cabal or .buildinfo file. (I *could* have explicit os conditionals in there, but that's ugly.) Right now, I'm just building all of the modules, and conditionally giving them bodies as follows: module System.Event.EPoll where #if defined(HAVE_EPOLL) ... #endif The trouble with this is twofold. I have to export everything in the module (because its contents vary depending on where I compile it), and the CPP macros there are ugly. Is there a better solution?

I have a source base that contains a number of source files that use APIs that vary by platform: every platform provides select, most provide poll, BSDs provide kqueue, and Linux provides epoll. I already have autoconf tests for these functions, and I'd like to use the results of those autoconf checks to determine which modules to compile, but I am unable to figure out how to do this in my .cabal or .buildinfo file. (I /could/ have explicit os conditionals in there, but that's ugly.)
Right now, I'm just building all of the modules, and conditionally giving them bodies as follows:
module System.Event.EPoll where #if defined(HAVE_EPOLL) ... #endif
The trouble with this is twofold. I have to export everything in the module (because its contents vary depending on where I compile it), and the CPP macros there are ugly. Is there a better solution? This means that modules with the same name have different set of functions, depending on OS? I think this is generally unsafe, because other packages would have to check what API to expect according to the OS. Whereever possible I try to use conditional Hs-Source-Dirs in Cabal for selecting OS specific modules, but all of the directories must contain
Bryan O'Sullivan schrieb: the same set of module names and modules with the same name must have the same interface. If modules have different APIs then I would give them different names and put them even in different packages. Then, say, presence of package poll-bsd means to the package user, that BSD functionality is available. Whether he is actually running BSD or whether the package simulates BSD functions doesn't matter.

Henning Thielemann wrote:
Bryan O'Sullivan schrieb:
I have a source base that contains a number of source files that use APIs
that vary by platform: every platform provides select, most provide poll, BSDs provide kqueue, and Linux provides epoll. I already have autoconf tests for these functions, and I'd like to use the results of those autoconf checks to determine which modules to compile, but I am unable to figure out how to do this in my .cabal or .buildinfo file. (I /could/ have explicit os conditionals in there, but that's ugly.)
Right now, I'm just building all of the modules, and conditionally giving them bodies as follows:
module System.Event.EPoll where #if defined(HAVE_EPOLL) ... #endif
The trouble with this is twofold. I have to export everything in the module (because its contents vary depending on where I compile it), and the CPP macros there are ugly. Is there a better solution?
This means that modules with the same name have different set of functions, depending on OS? I think this is generally unsafe, because other packages would have to check what API to expect according to the OS.
I agree. This definitely causes problems. In fact, I believe just such CPP results in difficulty using the network package with Happstack on the Mac by ifdef-ing out the IPv6 support. http://thread.gmane.org/gmane.comp.lang.haskell.cafe/64540 Whereever possible I try to use conditional Hs-Source-Dirs in Cabal for
selecting OS specific modules, but all of the directories must contain the same set of module names and modules with the same name must have the same interface. If modules have different APIs then I would give them different names and put them even in different packages. Then, say, presence of package poll-bsd means to the package user, that BSD functionality is available. Whether he is actually running BSD or whether the package simulates BSD functions doesn't matter.
Another option is to move the CPP to Haskell, so that all the functions are the same and the capability check is dynamic. This isn't necessarily better, of course. Regards, Sean

On Fri, Jan 15, 2010 at 11:36 PM, Bryan O'Sullivan
...I have to export everything in the module (because its contents vary depending on where I compile it)...
You could of course conditionally export symbols using CPP: module System.Event.EPoll ( #if defined(HAVE_EPOLL) ... #endif ) where #if defined(HAVE_EPOLL) ... #endif Bas
participants (4)
-
Bas van Dijk
-
Bryan O'Sullivan
-
Henning Thielemann
-
Sean Leather