4

我想增强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将类型从 更改CompilerIdCompilerInfo

我已经实现的——尽管我很乐意考虑一个更独立的选项——-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

它不漂亮,但它有效。

4

0 回答 0