module Package.C.Build ( buildCPkg
, getVars
, cPkgToDir
) where
import Control.Concurrent (getNumCapabilities)
import CPkgPrelude
import Data.Maybe (isJust)
import qualified Data.Text as T
import qualified Data.Text.IO as TIO
import Package.C.Build.OS
import Package.C.Db.Register
import Package.C.Fetch
import Package.C.Logging
import Package.C.Monad
import Package.C.Type
import System.Directory
import System.Directory.Executable (mkExecutable)
import System.FilePath (takeDirectory, takeFileName, (</>))
import System.FilePath.Glob
import System.IO.Temp (withSystemTempDirectory)
import System.Process
import System.Process.Ext
envVarSplit :: EnvVar -> (String, String)
envVarSplit (EnvVar ev x) = (ev, x)
stepToProc :: FilePath
-> FilePath
-> Command
-> PkgM ()
stepToProc fp _ (Call p as envs dir') = do
let dir'' = maybe fp (fp </>) dir'
envVars = fmap envVarSplit <$> envs
putDiagnostic ("Running " ++ p ++ " with arguments " ++ unwords as ++ " in directory " ++ dir'' ++ " with environment " ++ show envVars)
waitProcess $ (proc p as) { cwd = Just dir'', std_in = CreatePipe, env = envVars }
stepToProc dir' _ (MakeExecutable fp) = do
putDiagnostic ("Marking " ++ (dir' </> fp) ++ " as executable...")
liftIO $ mkExecutable (dir' </> fp)
stepToProc dir' _ (CreateDirectory d) = do
putDiagnostic ("Creating directory " ++ (dir' </> d) ++ "...")
liftIO $ createDirectoryIfMissing True (dir' </> d)
stepToProc _ p (SymlinkBinary file') = do
binDir <- (</> "bin") <$> globalPkgDir
let actualBin = p </> file'
liftIO $ createDirectoryIfMissing True binDir
liftIO $ createFileLink actualBin (binDir </> takeFileName file')
stepToProc _ p (Symlink tgt' lnk) = do
let linkAbs = p </> lnk
putDiagnostic ("Creating directory" ++ takeDirectory linkAbs ++ "...")
liftIO $ createDirectoryIfMissing True (takeDirectory linkAbs)
liftIO $ createFileLink (p </> tgt') linkAbs
stepToProc dir' _ (Write out fp) = do
let fpAbs = dir' </> fp
putDiagnostic ("Writing\n" ++ T.unpack out ++ "\n in file" ++ fpAbs)
liftIO (TIO.writeFile fpAbs out)
stepToProc dir' p (CopyFile src' dest') = do
let absSrc = dir' </> src'
absDest = p </> dest'
putDiagnostic ("Copying file " ++ absSrc ++ " to " ++ absDest ++ "...")
liftIO $ createDirectoryIfMissing True (takeDirectory absDest)
liftIO $ copyFileWithMetadata absSrc absDest
stepToProc dir' _ (Patch contents') = do
liftIO $ TIO.writeFile (dir' </> "step.patch") contents'
waitProcess $ (proc "patch" ["-i", "step.patch"]) { cwd = Just dir' }
processSteps :: (Traversable t)
=> FilePath
-> FilePath
-> t Command
-> PkgM ()
processSteps pkgDir instDir = traverse_ (stepToProc pkgDir instDir)
configureInDir :: CPkg
-> BuildVars
-> FilePath
-> PkgM ()
configureInDir cpkg cfg p =
let steps = configureCommand cpkg cfg
in
putNormal ("Configuring " ++ pkgName cpkg) *>
processSteps p (installDir cfg) steps
buildInDir :: CPkg
-> BuildVars
-> FilePath
-> FilePath
-> PkgM ()
buildInDir cpkg cfg p p' = do
putNormal ("Building " ++ pkgName cpkg)
processSteps p p' (buildCommand cpkg cfg)
installInDir :: CPkg
-> BuildVars
-> FilePath
-> FilePath
-> PkgM ()
installInDir cpkg cfg p p' =
putNormal ("Installing " ++ pkgName cpkg) *>
processSteps p p' (installCommand cpkg cfg)
fetchCPkg :: CPkg
-> FilePath
-> PkgM ()
fetchCPkg cpkg = fetchUrl (pkgUrl cpkg) (pkgName cpkg) (pkgStream cpkg)
buildCPkg :: CPkg
-> Maybe TargetTriple
-> Bool
-> Bool
-> [FilePath]
-> [FilePath]
-> [FilePath]
-> [FilePath]
-> PkgM ()
buildCPkg cpkg host sta glob shr libs incls bins = do
buildVars <- getVars host sta shr libs incls bins
installed <- packageInstalled cpkg host glob buildVars
when installed $
putDiagnostic ("Package " ++ pkgName cpkg ++ " already installed, skipping.")
unless installed $
forceBuildCPkg cpkg host glob buildVars
getPreloads :: [ FilePath ] -> IO [ FilePath ]
getPreloads =
fmap fold . traverse (\fp -> namesMatching (fp </> "*.so"))
getVars :: Maybe TargetTriple
-> Bool
-> [FilePath]
-> [FilePath]
-> [FilePath]
-> [FilePath]
-> PkgM BuildVars
getVars host sta shr links incls bins = do
nproc <- liftIO getNumCapabilities
pure (BuildVars "" "" host (isJust host) incls [] shr links bins dhallOS dhallArch sta nproc)
forceBuildCPkg :: CPkg
-> Maybe TargetTriple
-> Bool
-> BuildVars
-> PkgM ()
forceBuildCPkg cpkg host glob buildVars = do
pkgDir <- cPkgToDir cpkg host glob buildVars
liftIO $ createDirectoryIfMissing True pkgDir
withSystemTempDirectory "cpkg" $ \p -> do
putDiagnostic ("Setting up temporary directory in " ++ p)
fetchCPkg cpkg p
let p' = p </> pkgSubdir cpkg
lds <- liftIO $ getPreloads $ linkDirs buildVars
let buildConfigured = buildVars { installDir = pkgDir, currentDir = p, preloadLibs = lds }
configureInDir cpkg buildConfigured p'
buildInDir cpkg buildConfigured p' pkgDir
installInDir cpkg buildConfigured p' pkgDir
registerPkg cpkg host glob buildVars