On Fri, Feb 15, 2013 at 9:05 AM, Andrew Cowie <andrew@operationaldynamics.com> wrote:
I've got a piece of code that looks like this:

        baselineContextSSL :: IO SSLContext
        baselineContextSSL = do
            ctx <- SSL.context
            SSL.contextSetDefaultCiphers ctx
        #if defined __MACOSX__
            SSL.contextSetVerificationMode ctx SSL.VerifyNone
        #elif defined __WIN32__
            SSL.contextSetVerificationMode ctx SSL.VerifyNone
        #else
            SSL.contextSetCADirectory ctx "/etc/ssl/certs"
            SSL.contextSetVerificationMode ctx $
                SSL.VerifyPeer True True Nothing
        #endif
            return ctx

all very nice (this being necessary because apparently the non-free
operating systems don't store their certs in a reliably discoverable
place; bummer).

That, however, is not the problem. After all, this sort of thing is what
#ifdefs are for. The problem is needing to get an appropriate symbol
based on what OS you're using defined.

I naively assumed there would be __LINUX__ and __MACOSX__ and __WIN32__
defined by GHC because, well, that's just the sort of wishful thinking
that powers the universe.

So my question is: what's an appropriate Haskell mechanism for building
code that is OS / arch  / distro specific? It's not like I have autoconf
running generating me a config.h I could #include, right?

This feels simple and an appropriate use of CPP; even the symbol names
look just about like what I would have expected; stackoverflow said so,
must be true. Just need to get the right symbol defined at build time.

Any suggestions?

Things like this have been the bane of Unix programmers for decades; the C pre-processor has always been kind of a hack, mostly because of things like #ifdef and the huge messes they create.  For more on why this is so bad from the Unix side of the house, see: http://static.usenix.org/publications/library/proceedings/sa92/spencer.pdf

A better solution is to define a standard interface called by your code and a per-system module that implements that interface and does the things you need, then simply include one for the appropriate system at compile time.  E.g., a Darwin and Win32 modules that provide a function that calls 'SSL.contextSetVerificationMode ctx SSL.VerifyNone', and some kind of Generic module that provides a function that does the rest.

        - Dan C.