packages feed

hoppy-runtime 0.8.0 → 0.9.0

raw patch · 4 files changed

+316/−66 lines, 4 filesdep ~Cabaldep ~basedep ~hoppy-generatorsetup-changedPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: Cabal, base, hoppy-generator

API changes (from Hackage documentation)

- Foreign.Hoppy.Setup: [cppSourcesDir] :: ProjectConfig -> FilePath
- Foreign.Hoppy.Setup: [hsSourcesDir] :: ProjectConfig -> FilePath
+ Foreign.Hoppy.Runtime: fromContentsToGc :: (Deletable c, FromContents c e) => [e] -> IO c
+ Foreign.Hoppy.Setup: GenerateInAutogenDir :: FilePath -> GenerateLocation
+ Foreign.Hoppy.Setup: GenerateInSourcesDir :: FilePath -> GenerateLocation
+ Foreign.Hoppy.Setup: [cppGeneratedSourcesLocation] :: ProjectConfig -> GenerateLocation
+ Foreign.Hoppy.Setup: [cppPackagedSourcesLocation] :: ProjectConfig -> Maybe FilePath
+ Foreign.Hoppy.Setup: combinedMain :: ProjectConfig -> IO ()
+ Foreign.Hoppy.Setup: combinedUserHooks :: ProjectConfig -> UserHooks
+ Foreign.Hoppy.Setup: data GenerateLocation
- Foreign.Hoppy.Setup: ProjectConfig :: Either String Interface -> String -> FilePath -> FilePath -> ProjectConfig
+ Foreign.Hoppy.Setup: ProjectConfig :: Either String Interface -> String -> Maybe FilePath -> GenerateLocation -> ProjectConfig

Files

Setup.hs view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2024 Bryan Gardiner <bog@khumba.net> -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License.
hoppy-runtime.cabal view
@@ -1,12 +1,12 @@ name: hoppy-runtime-version: 0.8.0+version: 0.9.0 synopsis: C++ FFI generator - Runtime support-homepage: http://khumba.net/projects/hoppy+homepage: https://khumba.net/projects/hoppy license: Apache-2.0 license-file: LICENSE author: Bryan Gardiner <bog@khumba.net> maintainer: Bryan Gardiner <bog@khumba.net>-copyright: Copyright 2015-2021 Bryan Gardiner+copyright: Copyright 2015-2024 Bryan Gardiner category: Foreign build-type: Simple cabal-version: 1.24@@ -30,12 +30,12 @@     , MultiParamTypeClasses     , ScopedTypeVariables   build-depends:-      base >=4.7 && <5-    , Cabal >=1.24 && <3.3+      base >=4.10 && <5+    , Cabal >=1.24 && <3.11     , containers >=0.5 && <0.7     , directory >=1.2 && <1.4     , filepath >=1.3 && <1.5-    , hoppy-generator >=0.8 && <0.9+    , hoppy-generator >=0.9 && <0.10   hs-source-dirs: src   ghc-options: -W -fwarn-incomplete-patterns -fwarn-unused-do-bind   default-language: Haskell2010
src/Foreign/Hoppy/Runtime.hs view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2024 Bryan Gardiner <bog@khumba.net> -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License.@@ -41,6 +41,7 @@   -- * Containers   HasContents (..),   FromContents (..),+  fromContentsToGc,   -- * Internal   CCallback (..),   freeHaskellFunPtrFunPtr,@@ -53,6 +54,7 @@   ) where  import Control.Exception (Exception, bracket, catch, throwIO)+import Control.Monad ((<=<)) import Data.Int (Int8, Int16, Int32, Int64) import qualified Data.Map as M import Data.Map (Map)@@ -496,13 +498,13 @@ -- | Containers whose contents can be convered to a list. -- -- For a container @Cont@ holding values with C-side type @Foo@ and Haskell-side--- type @Bar@, if the container uses 'Foreign.Hoppy.Generator.Std.ConvertPtr'+-- type @Bar@, if the container uses @Foreign.Hoppy.Generator.Std.ConvertPtr@ -- then the following instances are recommended: -- -- > instance HasContents ContConst FooConst -- > instance HasContents Cont Foo ----- If the container uses 'Foreign.Hoppy.Generator.Std.ConvertValue' then the+-- If the container uses @Foreign.Hoppy.Generator.Std.ConvertValue@ then the -- following instances are recommended: -- -- > instance HasContents ContConst Bar@@ -528,7 +530,32 @@ -- resulting collection to a const pointer. class FromContents c e | c -> e where   -- | Creates and returns a new container holding the given elements.+  --+  -- The new container is not managed by the garbage collector.  If this is+  -- desired, use 'fromContentsToGc'.   fromContents :: [e] -> IO c++-- | Creates and returns a new container holding the given elements, like+-- 'fromContents', and additionally assigns ownership to the garbage collector.+--+-- This function is useful if the object being created is only needed as a+-- temporary for passing into another function, for example:+--+-- > processBlobs $ fromContentsToGc [Blob 1, Blob 2] :: IO BlobContainer+--+-- In this example, @processBlobs@ inspects all of the blobs but does not take+-- ownership of the container, so the Haskell code has to release the container+-- itself.  This is done via the garbage collector.+--+-- In a simple case like this, we can also write it a bit more efficiently like+-- below, since we don't truly need the garbage collector:+--+-- > withScopedPtr (fromContents [Blob 1, Blob 2] :: IO BlobContainer) processBlobs+--+-- In this second example, the container is freed immediately when+-- @processBlobs@ returns.+fromContentsToGc :: (Deletable c, FromContents c e) => [e] -> IO c+fromContentsToGc = toGc <=< fromContents  -- | Internal type that represents a pointer to a C++ callback object (callback -- impl object, specifically).
src/Foreign/Hoppy/Setup.hs view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2024 Bryan Gardiner <bog@khumba.net> -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License.@@ -37,23 +37,28 @@ -- -- main = --   cppMain $---   ProjectConfig+--   'ProjectConfig' --   { generatorExecutableName = \"foobar-generator\" --   , cppPackageName = \"foobar-cpp\"---   , cppSourcesDir = \"cpp\"---   , hsSourcesDir = \"src\"+--   , cppPackagedSourcesLocation = Nothing+--   , cppSourcesDir = 'GenerateInAutogenDir' \"\"+--   , hsSourcesDir = 'GenerateInAutogenDir' \"\" --   } -- @ -- -- The Haskell gateway uses the same code, except calling 'hsMain' instead of--- 'cppMain'.  This causes C++ sources to be generated in @foobar-cpp\/cpp@ and--- (assuming the Haskell gateway is at @foobar\/@) the Haskell sources to be--- generated in @foobar\/src@.+-- 'cppMain'.  This causes all (C++, Haskell) generated sources to be placed in+-- the \"autogen\" directories provided by Cabal, which keeps the source+-- directory clean.  See the documentation of the fields of 'ProjectConfig' for+-- more information on how to set up your project's build process. -- -- The gateway packages need to set @build-type: Custom@ in their @.cabal@ files -- to use these setup files. module Foreign.Hoppy.Setup (   ProjectConfig (..),+  GenerateLocation (..),+  combinedMain,+  combinedUserHooks,   cppMain,   cppUserHooks,   hsMain,@@ -62,7 +67,9 @@  import Control.Monad (unless, when) import Data.List (isInfixOf)+import qualified Data.Map as M import Distribution.InstalledPackageInfo (libraryDirs)+import qualified Distribution.ModuleName as ModuleName #if MIN_VERSION_Cabal(2,0,0) import Distribution.Package (mkPackageName) #else@@ -71,10 +78,12 @@ import Distribution.PackageDescription (   HookedBuildInfo,   PackageDescription,+  autogenModules,   emptyBuildInfo,   extraLibDirs,   ) import Distribution.Simple (defaultMainWithHooks, simpleUserHooks)+import Distribution.Simple.BuildPaths (autogenComponentModulesDir) import Distribution.Simple.LocalBuildInfo (   LocalBuildInfo,   absoluteInstallDirs,@@ -87,6 +96,7 @@ import Distribution.Simple.Program (   runDbProgram,   runProgram,+  simpleProgram,   ) import Distribution.Simple.Program.Find (   ProgramSearchPathEntry (ProgramSearchPathDefault),@@ -97,7 +107,6 @@   Program,   ProgramLocation (FoundOnSystem),   simpleConfiguredProgram,-  simpleProgram,   ) import Distribution.Simple.Setup (   CopyDest (CopyTo, NoCopyDest),@@ -113,6 +122,8 @@   installVerbosity,   regInPlace,   regVerbosity,+  replVerbosity,+  testVerbosity,   ) import Distribution.Simple.UserHooks (   UserHooks (@@ -137,10 +148,16 @@ import Distribution.Simple.Utils (die) #endif import Distribution.Simple.Utils (installOrdinaryFile)+import Distribution.Types.ComponentName (ComponentName (CLibName))+#if MIN_VERSION_Cabal(3,0,0)+import Distribution.Types.LibraryName (LibraryName (LMainLibName))+#endif+import Distribution.Types.LocalBuildInfo (componentNameCLBIs) import Distribution.Verbosity (Verbosity, normal)+import Foreign.Hoppy.Generator.Language.Haskell (getModuleName) import Foreign.Hoppy.Generator.Main (run)-import Foreign.Hoppy.Generator.Spec (Interface)-import System.Directory (createDirectoryIfMissing, doesFileExist)+import Foreign.Hoppy.Generator.Spec (Interface, interfaceModules)+import System.Directory (createDirectoryIfMissing, doesFileExist, getCurrentDirectory) import System.FilePath ((</>), takeDirectory)  -- | Configuration parameters for a project using Hoppy.@@ -149,16 +166,51 @@     -- ^ The interface to run the generator with.  This result is returned from     -- @Foreign.Hoppy.Generator.Spec.interface@ and some may have failed; the     -- string is a message indicating the problem.+   , cppPackageName :: String     -- ^ The name of the C++ gateway package.-  , cppSourcesDir :: FilePath-    -- ^ The directory into which to generate C++ sources, under the C++ gateway-    -- package root.-  , hsSourcesDir :: FilePath-    -- ^ The directory into which to generate Haskell sources, under the Haskell-    -- gateway package root.+    --+    -- When using separate Cabal packages for the C++ and Haskell gateway+    -- packages, this must be nonempty.  When using a single combined gateway+    -- package with 'combinedMain', this must be empty.++  , cppPackagedSourcesLocation :: Maybe FilePath+    -- ^ If the C++ gateway package includes C++ files needed for compliation+    -- (either sources or headers), then this should point to the base directory+    -- holding these files, relative to the root of the project.  The project+    -- root itself may be specified with @Just \"\"@.+    --+    -- When present, this is passed to the C++ package's makefile in the+    -- environment variable @HOPPY_CPP_PKG_DIR@.  A value of @Just \"\"@ is+    -- passed with @HOPPY_CPP_PKG_DIR@ set to the base directory of the Cabal+    -- package (equivalent to @Just \".\"@).+    --+    -- This is also added automatically as a system include path (i.e. @gcc -I@)+    -- for the C++ compiler when compiling the test program for enum+    -- autodetection.++  , cppGeneratedSourcesLocation :: GenerateLocation+    -- ^ Specifies the directory where C++ sources will be generated.+    --+    -- This is passed to the C++ package's makefile in the environment variable+    -- @HOPPY_CPP_GEN_DIR@.   } +-- | Where to generate sources for binding packages.+data GenerateLocation =+  GenerateInAutogenDir FilePath+  -- ^ Generate sources in the package's autogen directory provided by Cabal.+  -- This is preferrable as it keeps the source directory clean.+  --+  -- Sources are generated below the given @FilePath@ if nonempty, otherwise+  -- sources are generated directly in the autogen directory.+  | GenerateInSourcesDir FilePath+  -- ^ Generate sources in the package's root source directory, i.e. the+  -- directory with the @.cabal@ file.+  --+  -- Sources are generated below the given @FilePath@ if nonempty, otherwise+  -- sources are generated directly in the root directory.+ -- | The name of the file we'll use to hold the enum evaluation cache. enumEvalCacheFileName :: FilePath enumEvalCacheFileName = "hoppy-enum-eval-cache"@@ -176,6 +228,89 @@     "Error initializing interface: " ++ errorMsg   Right iface -> return iface +-- | A @main@ implementation to be used in the @Setup.hs@ of a single Hoppy+-- binding package that combined both the C++ and Haskell gateway code in one+-- package.+--+-- @combinedMain project = 'defaultMainWithHooks' $ 'combinedUserHooks' project@+combinedMain :: ProjectConfig -> IO ()+combinedMain project = defaultMainWithHooks $ combinedUserHooks project++-- | Cabal user hooks for a combined gateway package.  When overriding+-- overriding fields in the result, be sure to call the previous hook.+--+-- The following hooks are defined:+--+-- - 'postConf': Runs the generator to generate C++ and Haskell sources.+combinedUserHooks :: ProjectConfig -> UserHooks+combinedUserHooks project =+  simpleUserHooks+  { postConf = \args flags pkgDesc localBuildInfo -> do+      let verbosity = fromFlagOrDefault normal $ configVerbosity flags++      when (not $ null $ cppPackageName project) $+        die' verbosity $+        "combinedMain expects an empty cppPackageName, found \"" +++        cppPackageName project ++ "\"."++      iface <- case interfaceResult project of+        Left errorMsg ->+          die' verbosity $+          "Error initializing interface: " ++ errorMsg+        Right iface -> return iface++      genCpp project verbosity localBuildInfo iface+      genHs verbosity localBuildInfo iface+      postConf simpleUserHooks args flags pkgDesc localBuildInfo++  , preBuild = \_ flags -> myHsPreHook project (fromFlagOrDefault normal $ buildVerbosity flags)+  , preTest = \_ flags -> myHsPreHook project (fromFlagOrDefault normal $ testVerbosity flags)+  , preCopy = \_ flags -> myHsPreHook project (fromFlagOrDefault normal $ copyVerbosity flags)+  , preInst = \_ flags -> myHsPreHook project (fromFlagOrDefault normal $ installVerbosity flags)+  , preReg = \_ flags -> myHsPreHook project (fromFlagOrDefault normal $ regVerbosity flags)+  , preRepl = \_ flags -> myHsPreHook project (fromFlagOrDefault normal $ replVerbosity flags)+  }++  where genCpp :: ProjectConfig -> Verbosity -> LocalBuildInfo -> Interface -> IO ()+        genCpp project verbosity localBuildInfo iface = do+          (_, cppGenDir) <-+            getAutogenAndCppGenDir project verbosity localBuildInfo+          cppPackagedSourcesDir <- case cppPackagedSourcesLocation project of+            Nothing -> return ""+            Just subpath -> fmap (</> subpath) getCurrentDirectory+          createDirectoryIfMissing True cppGenDir+          createDirectoryIfMissing True $ buildDir localBuildInfo+          _ <- run [iface]+                   [ "--enum-eval-cache-mode", "refresh"+                   , "--enum-eval-cache-path", buildDir localBuildInfo </> enumEvalCacheFileName+                   , "--gen-cpp", cppGenDir, cppPackagedSourcesDir+                   ]+          return ()++        genHs :: Verbosity -> LocalBuildInfo -> Interface -> IO ()+        genHs verbosity localBuildInfo iface = do+          (_, hsGenDir) <- getAutogenAndHsGenDir verbosity localBuildInfo+          createDirectoryIfMissing True hsGenDir+          _ <- run [iface]+                   [ "--enum-eval-cache-mode", "must-exist"+                   , "--enum-eval-cache-path", buildDir localBuildInfo </> enumEvalCacheFileName+                   , "--gen-hs", hsGenDir+                   ]+          return ()++        -- See also hsPreHook.+        myHsPreHook :: ProjectConfig -> Verbosity -> IO HookedBuildInfo+        myHsPreHook project verbosity = do+          iface <- getInterface project verbosity+          let moduleNames =+                map (ModuleName.fromString . getModuleName iface) $+                M.elems (interfaceModules iface)++          -- Injected autogenerated modules here works for most commands, however sdist+          -- is not hookable, so autogen-modules should still be written out manually in+          -- your Cabal file!  (See Cabal issue #6180.)+          return (Just emptyBuildInfo { autogenModules = moduleNames }, [])+ -- | A @main@ implementation to be used in the @Setup.hs@ of a C++ gateway -- package. --@@ -212,25 +347,25 @@   , buildHook = \pkgDesc localBuildInfo hooks flags -> do       buildHook simpleUserHooks pkgDesc localBuildInfo hooks flags       let verbosity = fromFlagOrDefault normal $ buildVerbosity flags-      cppBuild verbosity localBuildInfo+      cppBuild project verbosity localBuildInfo    , copyHook = \pkgDesc localBuildInfo hooks flags -> do       copyHook simpleUserHooks pkgDesc localBuildInfo hooks flags       let verbosity = fromFlagOrDefault normal $ copyVerbosity flags           dest = fromFlagOrDefault NoCopyDest $ copyDest flags-      cppInstall verbosity pkgDesc localBuildInfo dest+      cppInstall project verbosity pkgDesc localBuildInfo dest    , instHook = \pkgDesc localBuildInfo hooks flags -> do       instHook simpleUserHooks pkgDesc localBuildInfo hooks flags       let verbosity = fromFlagOrDefault normal $ installVerbosity flags           dest = maybe NoCopyDest CopyTo $                  flagToMaybe $ installDistPref flags-      cppInstall verbosity pkgDesc localBuildInfo dest+      cppInstall project verbosity pkgDesc localBuildInfo dest    , regHook = \pkgDesc localBuildInfo hooks flags -> do       regHook simpleUserHooks pkgDesc localBuildInfo hooks flags       let verbosity = fromFlagOrDefault normal $ regVerbosity flags-      cppRegister verbosity localBuildInfo flags+      cppRegister project verbosity localBuildInfo flags    , cleanHook = \pkgDesc z hooks flags -> do       cleanHook simpleUserHooks pkgDesc z hooks flags@@ -241,17 +376,79 @@ makeProgram :: Program makeProgram = simpleProgram "make" +defaultLibComponentName :: ComponentName+defaultLibComponentName =+#if MIN_VERSION_Cabal(3,0,0)+  CLibName LMainLibName+#else+  CLibName+#endif++-- | Locates the autogen directory for the library component.+getAutogenDir :: Verbosity -> LocalBuildInfo -> IO FilePath+getAutogenDir verbosity localBuildInfo = do+  let libCLBIs = componentNameCLBIs localBuildInfo defaultLibComponentName+#if MIN_VERSION_Cabal(2,0,0)+      dieFn = die' verbosity+#else+      dieFn = die+#endif++  case libCLBIs of+    [libCLBI] -> return $ autogenComponentModulesDir localBuildInfo libCLBI+    _ ->+      -- TODO Show interface name, and "C++" or "Haskell"?+      dieFn $ concat+      ["Expected one library ComponentLocalBuildInfo, found ",+       show $ length libCLBIs, "."]++getAutogenAndGenDir :: GenerateLocation+                    -> Verbosity+                    -> LocalBuildInfo+                    -> IO (FilePath, FilePath)+getAutogenAndGenDir genLoc verbosity localBuildInfo = do+  autogenDir <- getAutogenDir verbosity localBuildInfo+  case genLoc of+    GenerateInAutogenDir subpath ->+      return (autogenDir, autogenDir </> subpath)+    GenerateInSourcesDir subpath -> do+      curDir <- getCurrentDirectory+      return (autogenDir, curDir </> subpath)++getAutogenAndCppGenDir :: ProjectConfig -> Verbosity -> LocalBuildInfo -> IO (FilePath, FilePath)+getAutogenAndCppGenDir project verbosity localBuildInfo =+  getAutogenAndGenDir (cppGeneratedSourcesLocation project) verbosity localBuildInfo++getAutogenAndHsGenDir :: Verbosity -> LocalBuildInfo -> IO (FilePath, FilePath)+getAutogenAndHsGenDir verbosity localBuildInfo =+  getAutogenAndGenDir (GenerateInAutogenDir "") verbosity localBuildInfo++getCppDirEnvVars :: ProjectConfig -> Verbosity -> LocalBuildInfo -> IO [String]+getCppDirEnvVars project verbosity localBuildInfo = do+  (autogenDir, cppGenDir) <- getAutogenAndCppGenDir project verbosity localBuildInfo+  return $+    [ "HOPPY_AUTOGEN_DIR=" ++ autogenDir+    , "HOPPY_CPP_GEN_DIR=" ++ cppGenDir+    ] +++    (case cppPackagedSourcesLocation project of+      Just "" -> ["HOPPY_CPP_PKG_DIR=."]+      Just subpath -> ["HOPPY_CPP_PKG_DIR=" ++ subpath]+      Nothing -> [])+ cppConfigure :: ProjectConfig -> Verbosity -> LocalBuildInfo -> IO () cppConfigure project verbosity localBuildInfo = do   -- Invoke the generator to create C++ code.-  let sourcesDir = cppSourcesDir project+  (_, cppGenDir) <- getAutogenAndCppGenDir project verbosity localBuildInfo+  cppPackagedSourcesDir <- case cppPackagedSourcesLocation project of+    Nothing -> return ""+    Just subpath -> fmap (</> subpath) getCurrentDirectory   iface <- getInterface project verbosity-  createDirectoryIfMissing True sourcesDir+  createDirectoryIfMissing True cppGenDir   createDirectoryIfMissing True $ buildDir localBuildInfo   _ <- run [iface]            [ "--enum-eval-cache-mode", "refresh"            , "--enum-eval-cache-path", buildDir localBuildInfo </> enumEvalCacheFileName-           , "--gen-cpp", sourcesDir+           , "--gen-cpp", cppGenDir, cppPackagedSourcesDir            ]    -- When there is a configure script, then run it.@@ -267,8 +464,8 @@                    then Just $ simpleConfiguredProgram "configure" $ FoundOnSystem "./configure"                    else Nothing -cppBuild :: Verbosity -> LocalBuildInfo -> IO ()-cppBuild verbosity localBuildInfo = do+cppBuild :: ProjectConfig -> Verbosity -> LocalBuildInfo -> IO ()+cppBuild project verbosity localBuildInfo = do   hasMakefile <- doesFileExist "Makefile"   unless hasMakefile $ #if MIN_VERSION_Cabal(2,0,0)@@ -277,11 +474,19 @@     die #endif     "No Makefile found."++  cppDirEnvVars <- getCppDirEnvVars project verbosity localBuildInfo+   let programDb = withPrograms localBuildInfo-  runDbProgram verbosity makeProgram programDb []+  runDbProgram verbosity makeProgram programDb cppDirEnvVars -cppInstall :: Verbosity -> PackageDescription -> LocalBuildInfo -> CopyDest -> IO ()-cppInstall verbosity pkgDesc localBuildInfo dest = do+cppInstall :: ProjectConfig+           -> Verbosity+           -> PackageDescription+           -> LocalBuildInfo+           -> CopyDest+           -> IO ()+cppInstall project verbosity pkgDesc localBuildInfo dest = do   hasMakefile <- doesFileExist "Makefile"   unless hasMakefile $ #if MIN_VERSION_Cabal(2,0,0)@@ -293,7 +498,9 @@   let programDb = withPrograms localBuildInfo       libDir = libdir $ absoluteInstallDirs pkgDesc localBuildInfo dest   createDirectoryIfMissing True libDir-  runDbProgram verbosity makeProgram programDb ["install", "libdir=" ++ libDir]+  cppDirEnvVars <- getCppDirEnvVars project verbosity localBuildInfo+  runDbProgram verbosity makeProgram programDb $+    ["install", "libdir=" ++ libDir] ++ cppDirEnvVars    -- We're doing an old-style install, so copy the enum eval cache file from the   -- build directory to the library directory where the Haskell side of the@@ -305,8 +512,8 @@                         enumEvalCacheFilePath                         (libDir </> enumEvalCacheFileName) -cppRegister :: Verbosity -> LocalBuildInfo -> RegisterFlags -> IO ()-cppRegister verbosity localBuildInfo flags = do+cppRegister :: ProjectConfig -> Verbosity -> LocalBuildInfo -> RegisterFlags -> IO ()+cppRegister project verbosity localBuildInfo flags = do   hasMakefile <- doesFileExist "Makefile"   unless hasMakefile $ #if MIN_VERSION_Cabal(2,0,0)@@ -319,12 +526,25 @@     let programDb = withPrograms localBuildInfo         libDir = buildDir localBuildInfo     createDirectoryIfMissing True libDir-    runDbProgram verbosity makeProgram programDb ["install", "libdir=" ++ libDir]+    cppDirEnvVars <- getCppDirEnvVars project verbosity localBuildInfo+    runDbProgram verbosity makeProgram programDb $+      ["install", "libdir=" ++ libDir] ++ cppDirEnvVars  cppClean :: ProjectConfig -> Verbosity -> IO () cppClean project verbosity = do   iface <- getInterface project verbosity-  _ <- run [iface] ["--clean-cpp", cppSourcesDir project]+  -- We can remove generated sources if we wrote them to the source directory.+  -- We don't have access to the autogen directory from this hook though.+  -- Although, Cabal ought to remove the autogen directory already when+  -- cleaning...+  case cppGeneratedSourcesLocation project of+    GenerateInAutogenDir _ -> return ()+    GenerateInSourcesDir subpath -> do+      cppPackagedSourcesDir <- case cppPackagedSourcesLocation project of+        Nothing -> return ""+        Just subpath -> fmap (</> subpath) getCurrentDirectory+      _ <- run [iface] ["--clean-cpp", subpath, cppPackagedSourcesDir]+      return ()    hasMakefile <- doesFileExist "Makefile"   unless hasMakefile $@@ -335,7 +555,7 @@ #endif     "No Makefile found."   make <- findSystemProgram verbosity "make"-  runProgram verbosity make ["clean"]+  runProgram verbosity make ["clean"]  -- No Hoppy directories passed in here!  findSystemProgram :: Verbosity -> FilePath -> IO ConfiguredProgram findSystemProgram verbosity basename = do@@ -383,17 +603,12 @@       let verbosity = fromFlagOrDefault normal $ configVerbosity flags       hsConfigure project verbosity localBuildInfo -  , preBuild = \_ _ -> addLibDir-  , preTest = \_ _ -> addLibDir-  , preCopy = \_ _ -> addLibDir  -- Not sure if necessary, but doesn't hurt.-  , preInst = \_ _ -> addLibDir  -- Not sure if necessary, but doesn't hurt.-  , preReg = \_ _ -> addLibDir  -- Necessary.-  , preRepl = \_ _ -> addLibDir -- Necessary.--  , cleanHook = \pkgDesc z hooks flags -> do-      cleanHook simpleUserHooks pkgDesc z hooks flags-      let verbosity = fromFlagOrDefault normal $ cleanVerbosity flags-      hsClean project verbosity+  , preBuild = \_ flags -> hsPreHook project (fromFlagOrDefault normal $ buildVerbosity flags)+  , preTest = \_ flags -> hsPreHook project (fromFlagOrDefault normal $ testVerbosity flags)+  , preCopy = \_ flags -> hsPreHook project (fromFlagOrDefault normal $ copyVerbosity flags)+  , preInst = \_ flags -> hsPreHook project (fromFlagOrDefault normal $ installVerbosity flags)+  , preReg = \_ flags -> hsPreHook project (fromFlagOrDefault normal $ regVerbosity flags)+  , preRepl = \_ flags -> hsPreHook project (fromFlagOrDefault normal $ replVerbosity flags)   }  hsCppLibDirFile :: FilePath@@ -444,22 +659,30 @@           writeFile hsCppLibDirFile libDir          generateSources iface libDir = do-          let sourcesDir = hsSourcesDir project-          createDirectoryIfMissing True sourcesDir+          (_, hsGenDir) <- getAutogenAndHsGenDir verbosity localBuildInfo+          createDirectoryIfMissing True hsGenDir           _ <- run [iface]                    [ "--enum-eval-cache-mode", "must-exist"                    , "--enum-eval-cache-path", libDir </> enumEvalCacheFileName-                   , "--gen-hs", sourcesDir+                   , "--gen-hs", hsGenDir                    ]           return () -addLibDir :: IO HookedBuildInfo-addLibDir = do+-- See also myHsPreHook.+hsPreHook :: ProjectConfig -> Verbosity -> IO HookedBuildInfo+hsPreHook project verbosity = do+  iface <- getInterface project verbosity+  let moduleNames =+        map (ModuleName.fromString . getModuleName iface) $+        M.elems (interfaceModules iface)+   libDir <- readFile hsCppLibDirFile-  return (Just emptyBuildInfo {extraLibDirs = [libDir]}, []) -hsClean :: ProjectConfig -> Verbosity -> IO ()-hsClean project verbosity = do-  iface <- getInterface project verbosity-  _ <- run [iface] ["--clean-hs", hsSourcesDir project]-  return ()+  -- Injected autogenerated modules here works for most commands, however sdist+  -- is not hookable, so autogen-modules should still be written out manually in+  -- your Cabal file!  (See Cabal issue #6180.)+  return (Just emptyBuildInfo+          { autogenModules = moduleNames+          , extraLibDirs = [libDir]+          }+         , [])