What is the best way to adapt to type changes in the Cabal library without CPP?

I want to increase flycheck-haskell support for automatically configuring flycheck from your .cabal file.

For this autoconfiguration, flycheck uses an auxiliary file whose original strategy was to read the .cabal file and use it flattenPackageDescription. It was simple, but did not take into account conditional expressions that might cause problems, for example, not required bytestring-builderwhen using a newer version of the package bytestring.

The appropriate interface to use will look like finalizePackageDescription. This works ... but its type signature has changed between 1.20 and 1.22 --- now instead of accepting CompilerId, now it takes a value CompilerInfo. However, I would like to provide consistent support in this API change.

While the solution for this usually uses macros CPP, these macros are provided by ourselves Cabal, and flycheckjust calls the auxiliary file with runhaskell, so we do not have access to them.

The only option I can think of is to create another helper to get the version information first Cabaland then build the appropriate parameters CPPfor our call runhaskellso that we can do this. This should work, but it looks like a hack.

So, I am looking for other options that would allow me to support both versions of the interface without resorting to CPP.

This code is a call Distribution.PackageDescription.Configuration.finalizePackageDescription, for example:

case finalizePackageDescription [] (const True) buildPlatform buildCompilerId [] genericDesc' of
  Left e -> putStrLn $ "Issue with package configuration\n" ++ show e
  Right (pkgDesc, _) -> print (dumpPackageDescription pkgDesc cabalFile)

The problem is that the fourth parameter buildCompilerIdchanged the type from CompilerIdto CompilerInfo.

What I implemented, although I would be happy to consider a more autonomous option --- this is an assistant that spits out -DuseCompilerInfo(like s-expr, since we are dealing with Emacs) if this is the latest version of Cabal enough:

import Data.Version (Version (Version))
import Distribution.Simple.Utils (cabalVersion)

main :: IO ()
main =
  putStrLn $ if cabalVersion >= Version [1,22] []
             then "(\"-DuseCompilerInfo\")"
             else "()"

Then the source helper starts with the flag and conditionally imports the new structures, and also has the following conditional code immediately before the argument above:

#ifdef useCompilerInfo
      buildCompilerId = unknownCompilerInfo (CompilerId buildCompilerFlavor compilerVersion) NoAbiTag
#else
      buildCompilerId = CompilerId buildCompilerFlavor compilerVersion
#endif

It is not beautiful, but it works.

+4

All Articles