module Language.C.Preprocessor.Remover
( getLibExposedModulesPath
, preprocessFile
) where
import Language.C.Preprocessor.Remover.Internal.AddPadding (addPadding)
import Language.C.Preprocessor.Remover.Internal.Preprocess (parseModuleWithCpp)
import Language.C.Preprocessor.Remover.Internal.Types (CabalFilePath,
CppOptions (..),
ProjectDir,
emptyCppOptions)
import Control.Monad (filterM, (>=>))
import Data.List (inits, isSuffixOf)
import Data.Maybe (catMaybes)
import Data.Monoid ((<>))
import Distribution.ModuleName (toFilePath)
import Distribution.PackageDescription (condLibrary, condTreeData,
exposedModules, hsSourceDirs,
libBuildInfo)
import Distribution.PackageDescription.Parse (readPackageDescription)
import Distribution.Verbosity (silent)
import System.Directory (findFile, makeAbsolute)
import System.Directory.Extra (listContents)
import System.FilePath.Find (always, extension, fileName, find,
(&&?), (/=?), (==?))
import System.FilePath.Posix (joinPath, splitPath,
takeDirectory, (</>))
import System.Process (readCreateProcess, shell)
getLibExposedModulesPath :: CabalFilePath -> IO [FilePath]
getLibExposedModulesPath cabalPath = do
packageDesc <- readPackageDescription silent cabalPath
let Just lib = condTreeData <$> condLibrary packageDesc
modules = map (++ ".hs") . map toFilePath . exposedModules $ lib
sourceDirs =
map (takeDirectory cabalPath </>) . ("" :) . hsSourceDirs $
libBuildInfo lib
mbModulesPath <- mapM (findFile sourceDirs) modules
return (catMaybes mbModulesPath)
preprocessFile :: FilePath -> IO String
preprocessFile fp = do
projectDir <- findProjectDirectory fp
macroFile <- fromGenericFileToCppMacroFile fp
includeDirs <-
allDotHFiles projectDir >>= mapM (\x -> takeDirectory <$> makeAbsolute x)
rawString <-
parseModuleWithCpp
(emptyCppOptions
{ cppFile = [macroFile]
, cppInclude = includeDirs
})
fp
return $ addPadding fp rawString
fromGenericFileToCppMacroFile :: FilePath -> IO FilePath
fromGenericFileToCppMacroFile fp = do
distDir <- (findProjectDirectory >=> findDistDir) fp
return $ distDir <> "/build/autogen/cabal_macros.h"
findProjectDirectory :: FilePath -> IO ProjectDir
findProjectDirectory fileInProject = do
let splittedPath = splitPath fileInProject
possiblePaths = map joinPath $ init $ tail $ inits splittedPath
head <$> filterM containsCabalFile possiblePaths
where
containsCabalFile :: FilePath -> IO Bool
containsCabalFile dir = any (".cabal" `isSuffixOf`) <$> listContents dir
findDistDir :: ProjectDir -> IO FilePath
findDistDir fp = init <$> readCreateProcess (shell cmd) ""
where
cmd = "cd " ++ fp ++ "; " ++ "cd $(stack path --dist-dir)" ++ "; pwd"
allDotHFiles :: ProjectDir -> IO [FilePath]
allDotHFiles root = find always isDotH root
where
isDotH = (extension ==? ".h" &&? fileName /=? "cabal_macros.h")