packages feed

Blueprint-0.1: Blueprint/Tools/GCC.hs

-- @+leo-ver=4-thin
-- @+node:gcross.20091123114318.1335:@thin GCC.hs
-- @@language Haskell

-- @<< Language extensions >>
-- @+node:gcross.20091123114318.1337:<< Language extensions >>
-- @-node:gcross.20091123114318.1337:<< Language extensions >>
-- @nl

module Blueprint.Tools.GCC where

-- @<< Import needed modules >>
-- @+node:gcross.20091123114318.1339:<< Import needed modules >>
import Control.Applicative.Infix
import Control.Monad

import Data.Map (Map)
import qualified Data.Map as Map

import System.Directory
import System.Exit
import System.FilePath
import System.IO.Unsafe
import System.Process

import Text.PrettyPrint.ANSI.Leijen hiding ((</>))

import Blueprint.Cache.ExplicitDependencies
import Blueprint.Configuration
import Blueprint.Error
import Blueprint.Options
import Blueprint.Resources
-- @-node:gcross.20091123114318.1339:<< Import needed modules >>
-- @nl

-- @+others
-- @+node:gcross.20091129000542.1577:Keys
gccOptionSectionKey = makeOptionSectionKey "GCC"
gccConfigurationKey = makeConfigurationKey "path to gcc"
-- @-node:gcross.20091129000542.1577:Keys
-- @+node:gcross.20091123114318.1342:Types
-- @+node:gcross.20091123114318.1343:GCCConfiguration
data GCCConfiguration = GCCConfiguration { gccCompilerPath :: FilePath } deriving (Show)
-- @-node:gcross.20091123114318.1343:GCCConfiguration
-- @-node:gcross.20091123114318.1342:Types
-- @+node:gcross.20091128000856.1436:Instances
-- @+node:gcross.20091128000856.1437:ConfigurationData GCCConfiguration
instance ConfigurationData GCCConfiguration where
    readConfig  = simpleReadConfig  gccConfigurationKey GCCConfiguration 
    writeConfig = simpleWriteConfig gccConfigurationKey gccCompilerPath
-- @-node:gcross.20091128000856.1437:ConfigurationData GCCConfiguration
-- @+node:gcross.20091128000856.1438:AutomaticallyConfigurable GCCConfiguration
instance AutomaticallyConfigurable GCCConfiguration where
    automaticallyConfigure = simpleSearchForProgram gccOptionSectionKey GCCConfiguration "gcc"
-- @-node:gcross.20091128000856.1438:AutomaticallyConfigurable GCCConfiguration
-- @-node:gcross.20091128000856.1436:Instances
-- @+node:gcross.20091129000542.1585:Options processing
gccOptions = makeSimpleOptionSectionForProgram "gcc" gccOptionSectionKey
-- @-node:gcross.20091129000542.1585:Options processing
-- @+node:gcross.20091123114318.1372:Tools
-- @+node:gcross.20091123114318.1368:gccCompile
gccCompile ::
    GCCConfiguration ->
    [String] ->
    FilePath ->
    FilePath ->
    Resource ->
    Resource
gccCompile
    tools
    options
    object_destination_directory
    cache_directory
    source_resource
    =
    Resource
        {   resourceName = source_name
        ,   resourceType = "o"
        ,   resourceFilePath = object_filepath
        ,   resourceDigest = object_digest
        ,   resourceDependencies = [resourceId source_resource]
        }
  where
    source_filepath = resourceFilePath source_resource
    source_name = resourceName source_resource
    object_filepath = getFilePathForNameAndType object_destination_directory source_name "o"

    builder =
        let arguments = 
                options ++
                ["-c",source_filepath
                ,"-o",object_filepath
                ]
            path_to_gcc = gccCompilerPath tools
        in do
            createDirectoryIfMissing True . takeDirectory $ object_filepath
            putStrLn . unwords $ (path_to_gcc:arguments)
            compilation_result <- readProcessWithExitCode path_to_gcc arguments ""
            case compilation_result of
                (ExitFailure _,_,error_message) ->
                    return
                    .
                    Just
                    .
                    errorMessageTextWithLines ("compiling " ++ source_name)
                    $
                    error_message
                (ExitSuccess,_,_) -> return Nothing

    object_digest =
        case analyzeDependencyAndRebuildIfNecessary
                builder
                (cache_directory </> source_name <.> "o")
                [object_filepath]
                (unwords options)
                source_resource
        of Left error_message -> Left error_message
           Right [object_digest] -> Right object_digest
           x -> error $ "Programmer error:  Builder returned the wrong number of digests! (" ++ show x ++ ")"
-- @-node:gcross.20091123114318.1368:gccCompile
-- @+node:gcross.20091123114318.1371:gccCompileAll
gccCompileAll ::
    GCCConfiguration ->
    [String] ->
    FilePath ->
    FilePath ->
    Resources ->
    Resources
gccCompileAll
    tools
    options
    object_destination_directory
    cache_directory
    old_resources
    =
    new_resources
  where
    new_resources = go old_resources (Map.elems old_resources)
    go accum_resources [] = accum_resources
    go accum_resources (resource:rest_resources) =
        if resourceType (resource) == "c"
            then let object_resource =
                        gccCompile
                            tools
                            options
                            object_destination_directory
                            cache_directory
                            resource
                 in go (addResource object_resource accum_resources) rest_resources
            else go accum_resources rest_resources
-- @-node:gcross.20091123114318.1371:gccCompileAll
-- @-node:gcross.20091123114318.1372:Tools
-- @-others
-- @-node:gcross.20091123114318.1335:@thin GCC.hs
-- @-leo