如何为名称中包含非字母字符的库定义MIN_VERSION_宏?

时间:2018-04-26 09:44:57

标签: haskell c-preprocessor versioning ghc cabal

Cabal或more recently GHC itself预先定义了CPP宏,允许检查使用哪个版本的库。它可以在简单的例子中轻松工作,比如

#if MIN_VERSION_base(4,0,0)
... code that works with base-4 ...
#else
... code that works with base-3 ...
#endif

但是,CPP宏名称比Cabal包名称更受限制,因此以下内容不起作用:

#if !MIN_VERSION_quickcheck-instances(0,3,17)
instance Arbitrary SBS.ShortByteString where arbitrary = fmap SBS.pack arbitrary
#endif
     error: missing binary operator before token "("
     #if !MIN_VERSION_quickcheck-instances(0,3,17)
     ^
   |
18 | #if !MIN_VERSION_quickcheck-instances(0,3,17)
   | ^
`gcc' failed in phase `C pre-processor'. (Exit code: 1)

似乎没有正确记录如何处理这样的库名称。

2 个答案:

答案 0 :(得分:3)

简短回答:连字符(-)替换为下划线(_)。

据我所知,宏是在generatePackageVersionMacros function of the DriverPipeline.hs file

中生成的
generatePackageVersionMacros :: [PackageConfig] -> String
generatePackageVersionMacros pkgs = concat
  -- Do not add any C-style comments. See Trac #3389.
  [ generateMacros "" pkgname version
  | pkg <- pkgs
  , let version = packageVersion pkg
        pkgname = map fixchar (packageNameString pkg)
  ]

fixchar :: Char -> Char
fixchar '-' = '_'
fixchar c = c

generateMacros :: String -> String -> Version -> String
generateMacros prefix name version =
  concat
  ["#define ", prefix, "VERSION_",name," ",show (showVersion version),"\n"
  ,"#define MIN_", prefix, "VERSION_",name,"(major1,major2,minor) (\\\n"
  ,"  (major1) <  ",major1," || \\\n"
  ,"  (major1) == ",major1," && (major2) <  ",major2," || \\\n"
  ,"  (major1) == ",major1," && (major2) == ",major2," && (minor) <= ",minor,")"
  ,"\n\n"
  ]
  where
(major1:major2:minor:_) = map show (versionBranch version ++ repeat 0)

正如您所看到的,通过在其上执行packageNameString来修复程序包的map fixchar。连字符(-)替换为下划线(_)。因此宏可以写成:

#if !MIN_VERSION_quickcheck_instances(0,3,17)
instance Arbitrary SBS.ShortByteString where arbitrary = fmap SBS.pack arbitrary
#endif

答案 1 :(得分:2)

您可以在dist/build/autogen/cabal_macros.h

中查看生成的宏