What is the accepted solution for conditionnal compilation

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.

6 Likes

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 :frowning:

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.

5 Likes

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.

That is the suggested way.

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.

1 Like

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.