ifdef based on which OS you're on

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? AfC Sydney

Andrew Cowie
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?
You can know the OS and arch without even resorting to CPP; see System.Info (http://hackage.haskell.org/packages/archive/base/latest/doc/html/System-Info...), which defines `os` and `arch`.

That's interesting. But are there standard values for those functions? I'm guessing not, seeing a how they're String and not an ADT.
AfC
Sydney
Artyom Kazak
You can know the OS and arch without even resorting to CPP; see System.Info which defines `os` and `arch`.
-- Andrew Frederik Cowie Operational Dynamics

Well, for sure you can in define that in .cabal file: if !os(windows) CC-Options: "-DWINDOWS" or something. See: http://www.haskell.org/cabal/users-guide/developing-packages.html#configurat... On Fri, Feb 15, 2013 at 3:05 PM, 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?
AfC Sydney
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Fri, 2013-02-15 at 15:16 +0100, Krzysztof Skrzętnicki wrote:
See: http://www.haskell.org/cabal/users-guide/developing-packages.html#configurat...
That link says os(): "Tests if the current operating system is name. The argument is tested against System.Info.os on the target system. There is unfortunately some disagreement between Haskell implementations about the standard values of System.Info.os. Cabal canonicalises it so that in particular os(windows) works on all implementations. If the canonicalised os names match, this test evaluates to true, otherwise false. The match is case-insensitive." So this approach is back to relying on System.Info.os either way. What worries me is the "Cabal canonicalises it", which seems to indicate that there are actually many values that show up in 'os' that need to be regularized. Anyone have any idea if the Cabal library exposes this somewhere? AfC Sydney

On Sat, 16 Feb 2013 01:57:14 +0100, Andrew Cowie
Anyone have any idea if the Cabal library exposes this somewhere?
See: http://hackage.haskell.org/packages/archive/Cabal/1.16.0.3/doc/html/Distribu... Regards, Henk-Jan van Tuyl -- http://Van.Tuyl.eu/ http://members.chello.nl/hjgtuyl/tourdemonad.html Haskell programming --

On Sat, 2013-02-16 at 08:18 +0100, Henk-Jan van Tuyl wrote:
Anyone have any idea if the Cabal library exposes this somewhere?
See...
I blogged about my solution using Krzysztof and Henk's suggestions here: http://blogs.operationaldynamics.com/andrew/software/haskell/config-dot-h-an... Cheers everyone, AfC Sydney

On Sun, Feb 24, 2013 at 5:28 PM, Andrew Cowie < andrew@operationaldynamics.com> wrote:
On Sat, 2013-02-16 at 08:18 +0100, Henk-Jan van Tuyl wrote:
Anyone have any idea if the Cabal library exposes this somewhere?
See...
I blogged about my solution using Krzysztof and Henk's suggestions here:
http://blogs.operationaldynamics.com/andrew/software/haskell/config-dot-h-an...
Cheers everyone,
I read your blog post and I'm afraid I don't see the point: you write some code to tap into a pre-existing library that figures out what platform you are on so that you can write out a 'config.h' that #define's the platform you are on so that you can then use the C preprocessor to pick a particular code path via conditional compilation. Why go to all that bother? Why not just write code that writes out the path you want to take and link against it? - Dan C.

On Mon, 2013-02-25 at 00:28 -0500, Dan Cross wrote:
Why go to all that bother? Why not just write code that writes out the path you want to take and link against it?
{shrug} You could do that too. I spent a decade doing work in Java-land, a language where by design we *didn't* have #ifdefs. Write once, run everywhere, they said. Yeah, right. It was a royal pain in the ass, especially when writing language bindings to native libraries. Portability is part of it, but including coverage (or not) of features based on whether dependencies were present was a biggie, too. So I'm a fan. To your point about generating code and then having only one version at compile time, that's a fair approach too. I would choose against it only because I'd prefer (as in this example) the relevant lines be in the source file where they belong, rather than having three definitions of that function somewhere else (or worse, meta). In the case I showed it's only one #define and one code block. But in a case where you had to make decisions across a code base, then I think #include "config.h" would be a workable choice. Anyway, I thought it was cool, and as figuring it out took a bit of doing I wanted to write it up. AfC Sydney

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.

On 02/15/2013 02:05 PM, Andrew Cowie wrote:
all very nice (this being necessary because apparently the non-free operating systems don't store their certs in a reliably discoverable place; bummer).
Sorry the answer is out of topic, but this is not true. Windows certificate and macos X certificate are stored in a reliably discoverable place. That openssl provide no way to get to it is a different story and one reason to have tls. -- Vincent

On Fri, 2013-02-15 at 15:12 +0000, Vincent Hanquez wrote:
Sorry the answer is out of topic
That's ok.
Windows certificate and macos X certificate are stored in a reliably discoverable place. That openssl provide no way to get to it is a different story and one reason to have tls.
Is talking to the Windows and Mac OS certificate stores something that you wrote for the tls library [in Haskell]? If so, is it something that could be ported for other people to use? [I assume we can "just look at tls's source" but I'd certainly welcome a pointer as to where to look] AfC Sydney

On 02/16/2013 12:51 AM, Andrew Cowie wrote:
Windows certificate and macos X certificate are stored in a reliably discoverable place. That openssl provide no way to get to it is a different story and one reason to have tls. Is talking to the Windows and Mac OS certificate stores something that you wrote for the tls library [in Haskell]? If so, is it something that could be ported for other people to use?
It's not much but it's available in the certificate package. https://github.com/vincenthz/hs-certificate/tree/master/System/Certificate/X... The mac os certificates are trivially available throught the "security" executable, but there's also documentation on the keychain format readily available. The windows certificate implementation is not finished. The certificate are easy to find, however the format is slightly complicated (basically a dump of C like structure with ASN1 marshalled data in the dump). The windows certificate is sadly not finished, as no windows user of tls (if any) is {interested-in/know-how-to} implementing it, and as I boot windows once every moon ... if someone want to sponsor the feature, come talk to me ;) That remind me that i've got pending patches to win32 to send .. -- Vincent

__WIN32__
use mingw32_HOST_OS
__MACOSX__
darwin_HOST_OS
On Sat, 16 Feb 2013 01:05:13 +1100 Andrew Cowie
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?
AfC Sydney

As counterpoint to Vincent Hanquez' note about the certificate store on MacOS & Windows, I'd like to cast some doubt on the notion that you can reliably find the cert store here on Linux or the *BSDs. So, if my experience with platforms like that is any guide, you'd rather not "hard code" this value in any case. I suppose that means application needs a configuration file.
#else SSL.contextSetCADirectory ctx "/etc/ssl/certs" SSL.contextSetVerificationMode ctx $ SSL.VerifyPeer True True Nothing #endif
On the bright side, a configuration file makes operational parameters like this very transparent for a sys admin who needs to work with it but wasn't in on the original install. Assuming the config file is easy to find in the first place. Donn
participants (8)
-
Andrew Cowie
-
Artyom Kazak
-
Dan Cross
-
Donn Cave
-
Henk-Jan van Tuyl
-
Krzysztof Skrzętnicki
-
kudah
-
Vincent Hanquez