我想增强flycheck-haskell对从 .cabal 文件自动配置 flycheck 的支持。
为了进行这种自动配置,flycheck 使用了一个帮助文件,其最初的策略是读取 .cabal 文件并使用flattenPackageDescription
. 这很简单,但不尊重条件表达式,这可能会导致问题,例如bytestring-builder
在使用较新版本的bytestring
包时不需要。
使用的适当接口似乎是finalizePackageDescription
. 这确实有效......但它的类型签名在 1.20 和 1.22 之间发生了变化——现在,CompilerId
它不再采用 a ,而是采用CompilerInfo
. 然而,我想在此 API 更改中提供一致的支持。
虽然解决方案通常是使用CPP
宏,但这些宏是由Cabal
自身提供的,并且flycheck
只是使用 调用帮助文件runhaskell
,因此我们无权访问它们。
我能想到的唯一选择是创建另一个帮助程序以首先获取Cabal
版本信息,然后CPP
为我们的调用构造适当的设置,runhaskell
以便我们可以这样做。这应该有效,但似乎是一个黑客。
所以我在这里寻找其他选项,让我能够支持两个版本的界面,而不必求助于CPP
.
有问题的代码是对 的调用Distribution.PackageDescription.Configuration.finalizePackageDescription
,如下所示:
case finalizePackageDescription [] (const True) buildPlatform buildCompilerId [] genericDesc' of
Left e -> putStrLn $ "Issue with package configuration\n" ++ show e
Right (pkgDesc, _) -> print (dumpPackageDescription pkgDesc cabalFile)
问题是第四个参数,buildCompilerId
将类型从 更改CompilerId
为CompilerInfo
。
我已经实现的——尽管我很乐意考虑一个更独立的选项——-DuseCompilerInfo
如果它是一个足够新的版本,它是一个吐出的助手(作为一个 s-expr,因为我们正在处理 Emacs)阴谋集团:
import Data.Version (Version (Version))
import Distribution.Simple.Utils (cabalVersion)
main :: IO ()
main =
putStrLn $ if cabalVersion >= Version [1,22] []
then "(\"-DuseCompilerInfo\")"
else "()"
然后使用标志运行原始助手,并有条件地导入新结构,并在上面的 case 语句之前具有以下条件代码:
#ifdef useCompilerInfo
buildCompilerId = unknownCompilerInfo (CompilerId buildCompilerFlavor compilerVersion) NoAbiTag
#else
buildCompilerId = CompilerId buildCompilerFlavor compilerVersion
#endif
它不漂亮,但它有效。