Sometimes, one needs conditionnal compilation (either to hide/export internal functions, or make code works with different version). I understand traditionnal #ifdef
works but rely on CPP
(the C-processor) which its use is controversial. So is there a “correct” way to do so ?
I don’t really like CPP
. If you can, use what cabal
offers, e.g.:
if os(windows)
hs-source-dirs: platform-dep/windows
if !os(windows)
hs-source-dirs: platform-dep/non-win
More info in Cabal User’s Guide.
I don’t think anyone really likes CPP, but it’s really hard to avoid if you need conditional compilation at a finer-grained level than the module.
@f-a’s solution works great when you can just swap out particular modules depending on the platform. In principle I think it should always be sufficient. However, sometimes you just need to tweak one line in the middle of a big module depending on the platform, or the major version of a dependency, and then it’s very annoying to factor that out into a compatibility module.
I think it boils down to whether you can define an interface to your platform- or version-dependent stuff. If you can do that easily, then separating it out into a module is usually very nice. But if you can’t easily do that, then it’s hard to avoid CPP everywhere
For example, in HLS we are very exposed to the GHC API, which changes a lot with every version. Some things we can put into a separate module and either use @f-a’s approach or at least keep the CPP contained. But sometimes you just have a situation like “this random function takes an extra argument in newer versions”, and it’s easier to just CPP it.
I’m trying to not export internal functions (to minimize recompilation) yet I need to test some.
So I was thinking having the export section depends on a TEST flag. I could have an internal module, but that is what I am trying to avoid.
I understand containers
did what you plan to do (conditional export using CPP
) but not sure if they still are still using the same hack or plan to migrate.
I wasn’t aware of cabal internal libraries, thanks for the link. In my case is a bit of an overkill, I’m only talking about 1 or 2 functions to hide from a module. Not enough to make a module, let alone for a library.