Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How are the MIN_VERSION_𝑙𝑖𝑏 macros defined for libraries with non-letter characters in their name?

Cabal, or more recently GHC itself, pre-defines CPP macros that allow checking what version of which library is used. It works easily in simple examples like

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

However, CPP macro names are more restricted than Cabal package names, so the following does not work:

#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)

It doesn't seem to be properly documented how library names like this are handled.

like image 464
leftaroundabout Avatar asked Apr 26 '18 09:04

leftaroundabout


2 Answers

Short answer: the hyphen (-) is replaced with an underscore (_).

The macros are - as far as I know - generated in the 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)

As you can see the packageNameString of the package is fixed by performing a map fixchar on it. The hyphen (-) is replaced with an underscore (_). The macro can thus be written like:

#if !MIN_VERSION_quickcheck_instances(0,3,17)
instance Arbitrary SBS.ShortByteString where arbitrary = fmap SBS.pack arbitrary
#endif
like image 88
Willem Van Onsem Avatar answered Oct 06 '22 18:10

Willem Van Onsem


You can check the generated macros in dist/build/autogen/cabal_macros.h.

The macro for quickcheck-instances would be named MIN_VERSION_quickcheck_instances.

like image 45
Jens Petersen Avatar answered Oct 06 '22 19:10

Jens Petersen