[Add auto-generated CPP macros for package version testing Simon Marlow **20080811173016 Now when using CPP you get MIN_VERSION_(A,B,C) for each in build-depends, which is true if the version of in use is >= A.B.C, using the normal ordering on version numbers. This is done by auto-generating a header file dist/build/autogen/cabal_macros.h, and passing a -include flag when running CPP. ] { hunk ./Distribution/Simple/Build.hs 65 - ( Package(..), packageName, packageVersion ) + ( PackageIdentifier, Package(..), packageName, packageVersion ) hunk ./Distribution/Simple/Build.hs 74 -import Distribution.Simple.BuildPaths ( autogenModuleName, autogenModulesDir ) +import Distribution.Simple.BuildPaths + ( autogenModulesDir, autogenModuleName, + cppHeaderName ) hunk ./Distribution/Simple/Build.hs 82 +import Distribution.Version ( versionBranch ) hunk ./Distribution/Simple/Build.hs 89 +import Text.Printf ( printf ) hunk ./Distribution/Simple/Build.hs 160 + buildCPPHeader distPref pkg_descr lbi hunk ./Distribution/Simple/Build.hs 164 +-- ------------------------------------------------------------ +-- * Building cabal_macros.h +-- ------------------------------------------------------------ + +buildCPPHeader :: FilePath -> PackageDescription -> LocalBuildInfo -> IO () +buildCPPHeader distPref _pkg_descr lbi = + let + cpp_header_filepath = autogenModulesDir lbi cppHeaderName + + preface = "/* DO NOT EDIT: This file is automatically generated by Cabal */" + + version_macro :: PackageIdentifier -> String + version_macro pkgid = + printf ("#define MIN_VERSION_%s(major1,major2,minor) \\\n" ++ + " (major1) < %d || \\\n" ++ + " (major1) == %d && (major2) < %d || \\\n" ++ + " (major1) == %d && (major2) == %d && (minor) <= %d") + (display (packageName pkgid)) major1 + major1 major2 + major1 major2 minor + where + vs = versionBranch (packageVersion pkgid) + (major1:major2:minor:_) = vs ++ repeat 0 + + contents = unlines (preface : map version_macro (packageDeps lbi)) + + in do + btime <- getModificationTime (localBuildInfoFile distPref) + exists <- doesFileExist cpp_header_filepath + ptime <- if exists + then getModificationTime cpp_header_filepath + else return btime + if btime >= ptime + then writeFile cpp_header_filepath contents + else return () + hunk ./Distribution/Simple/BuildPaths.hs 49 + cppHeaderName, hunk ./Distribution/Simple/BuildPaths.hs 95 +cppHeaderName :: String +cppHeaderName = "cabal_macros.h" hunk ./Distribution/Simple/GHC.hs 676 + ++ ["-I" ++ autogenModulesDir lbi] hunk ./Distribution/Simple/GHC.hs 681 + ++ [ "-optP-include", "-optP"++ (autogenModulesDir lbi cppHeaderName) ] hunk ./Distribution/Simple/PreProcess.hs 74 -import Distribution.Simple.BuildPaths (autogenModulesDir) +import Distribution.Simple.BuildPaths (autogenModulesDir,cppHeaderName) hunk ./Distribution/Simple/PreProcess.hs 322 + ++ [ "-optP-include", "-optP"++ (autogenModulesDir lbi cppHeaderName) ] hunk ./Distribution/Simple/PreProcess.hs 334 - rawSystemProgramConf verbosity cpphsProgram (withPrograms lbi) $ + rawSystemProgram verbosity cpphsProg $ hunk ./Distribution/Simple/PreProcess.hs 337 - : extraArgs + : (if cpphsVersion >= Version [1,6] [] + then ["--include="++ (autogenModulesDir lbi cppHeaderName)] + else []) + ++ extraArgs hunk ./Distribution/Simple/PreProcess.hs 342 + where Just cpphsProg = lookupProgram cpphsProgram (withPrograms lbi) + Just cpphsVersion = programVersion cpphsProg hunk ./doc/Cabal.xml 1684 + + Conditional compilation + + Sometimes you want to write code that works with more than + one version of a dependency. You can specify a range of + versions for the depenency in + the build-depends, but how do you then write + the code that can use different versions of the API? + + Haskell lets you preprocess your code using the C + preprocessor (either the real C preprocessor, or + cpphs). To enable this, + add extensions: CPP to your package + description. When using CPP, Cabal provides some pre-defined + macros to let you test the version of dependent packages; for + example, suppose your package works with either version 3 or + version 4 of the base package, you could + select the available version in your Haskell modules like + this: + +#if MIN_VERSION_base(4,0,0) +... code that works with base-4 ... +#else +... code that works with base-3 ... +#endif + +In general, Cabal supplies a + macro MIN_VERSION_package(A,B,C) + for each package depended on via build-depends. + This macro is true if the actual version of the package in use is + greater than or equal to A.B.C (using the + conventional ordering on version numbers, which is lexicographic on + the sequence, but numeric on each component, so for example 1.2.0 is + greater than 1.0.3). + + Cabal places the definitions of these macros into an + automatically-generated header file, which is included when + preprocessing Haskell source code by passing options to the C + preprocessor. + + }