module DDC.Driver.Command.BaseBuild
        (cmdBaseBuild)
where
import DDC.Driver.Stage
import DDC.Build.Platform
import DDC.Build.Builder
import DDC.Driver.Command.Compile
import System.FilePath
import System.Directory
import Control.Monad.Trans.Except
import Control.Monad.IO.Class
import Control.Monad
import DDC.Build.Interface.Store        (Store)


baseSaltFiles :: Builder -> [FilePath]
baseSaltFiles builder
 = let  bits    = show $ archPointerWidth $ platformArch $ buildTarget builder
        runtime = "salt" </> "runtime" ++ bits
   in   [ runtime </> "debug"           </> "Trace.dcs"
        , runtime </> "primitive"       </> "Array.dcs"
        , runtime </> "primitive"       </> "Ref.dcs"
        , runtime </> "primitive"       </> "Text.dcs"
        , runtime </> "Apply.dcs"
        , runtime </> "Object.dcs" ]


baseSeaFiles  :: Builder -> [FilePath]
baseSeaFiles _builder
 =      ["sea"  </> "primitive" </> "Primitive.c"]


-- Buid the base libraries and runtime system.
cmdBaseBuild :: Config  -> Store -> ExceptT String IO ()
cmdBaseBuild config store
 = do   let builder     = configBuilder config
        let target      = buildTarget builder
        
        -- Ensure the lib dir exists.
        exists   <- liftIO $ doesDirectoryExist $ buildBaseLibDir builder
        when (not exists)
         $ liftIO $ createDirectory $ buildBaseLibDir builder

        -- Build all the .dcs files.
        let config'      = config { configInferTypes = True }
        let srcSaltFiles = map (buildBaseSrcDir builder </>) (baseSaltFiles builder)
        let objSaltFiles = map (flip replaceExtension "o")   srcSaltFiles
        mapM_ (cmdCompile config' False store) srcSaltFiles

        -- Build all the .c files.
        let srcSeaFiles  = map (buildBaseSrcDir builder </>) (baseSeaFiles builder)
        let objSeaFiles  = map (flip replaceExtension "o")   srcSeaFiles
        liftIO $ zipWithM_ (buildCC builder) srcSeaFiles objSeaFiles

        -- All the .o files
        let objFiles     = objSaltFiles ++ objSeaFiles

        -- Link the .o files into a static library.
        let staticRuntime 
                = buildBaseLibDir builder
                </> "libddc-runtime." ++ staticFileExtensionOfPlatform target

        liftIO $ buildLdLibStatic builder objFiles staticRuntime


        -- Link the .o files into a shared library.
        let sharedRuntime 
                = buildBaseLibDir builder
                </> "libddc-runtime." ++ sharedFileExtensionOfPlatform target

        liftIO $ buildLdLibShared builder objFiles sharedRuntime

        return ()