module Development.Shake.C (
CConfig (..)
, CCompiler (GCC, Clang, GHC, Other, GCCStd, GHCStd)
, staticLibR
, objectFileR
, dynLibR
, cBin
, cToLib
, ccAction
, staticLibA
, cconfigToArgs
, ccToString
, ccFromString
, host
) where
import Control.Monad
import Data.List (isSuffixOf)
import Data.Semigroup
import Development.Shake
import Development.Shake.FilePath
import System.Info
mkQualified :: Monoid a => Maybe a -> a -> a
mkQualified suff = h (g <$> [suff])
where g = maybe id mappend
h = foldr fmap id
host :: String
host = arch ++ withManufacturer os
where withManufacturer "darwin" = "-apple-" ++ os
withManufacturer _ = "-unknown-" ++ os
pattern GCCStd :: CCompiler
pattern GCCStd = GCC Nothing
pattern GHCStd :: CCompiler
pattern GHCStd = GHC Nothing
ccToString :: CCompiler -> String
ccToString Clang = "clang"
ccToString (Other s) = s
ccToString (GCC pre) = mkQualified pre "gcc"
ccToString (GHC pre) = mkQualified pre "ghc"
arToString :: CCompiler -> String
arToString (GCC pre) = mkQualified pre "ar"
arToString (GHC pre) = mkQualified pre "ar"
arToString _ = "ar"
ccFromString :: String -> CCompiler
ccFromString "gcc" = GCC Nothing
ccFromString "clang" = Clang
ccFromString "ghc" = GHC Nothing
ccFromString s
| "gcc" `isSuffixOf` s = GCC (Just (reverse . drop 3 . reverse $ s))
| "ghc" `isSuffixOf` s = GHC (Just (reverse . drop 3 . reverse $ s))
ccFromString _ = GCC Nothing
data CCompiler = GCC { _prefix :: Maybe String }
| Clang
| Other String
| GHC { _prefix :: Maybe String }
deriving (Eq)
mapFlags :: String -> ([String] -> [String])
mapFlags s = fmap (s <>)
data CConfig = CConfig { includes :: [String]
, libraries :: [String]
, libDirs :: [String]
, extras :: [String]
}
cToLib :: CCompiler
-> [FilePath]
-> FilePattern
-> CConfig
-> Rules ()
cToLib cc sources lib cfg =
mconcat [ foldr (>>) (pure ()) objRules
, staticLibR cc (g sources) lib cfg
]
where objRules = objectFileR cc <$> g sources <*> pure lib <*> pure cfg
g = fmap (-<.> "o")
cBin :: CCompiler
-> [FilePath]
-> FilePattern
-> CConfig
-> Rules ()
cBin cc sources bin cfg = bin %> \out -> ccAction cc sources out cfg
ccAction :: CmdResult r
=> CCompiler
-> [FilePath]
-> FilePath
-> CConfig
-> Action r
ccAction cc sources out cfg =
need sources >>
(command [EchoStderr False] (ccToString cc) . (("-o" : out : sources) <>) . cconfigToArgs) cfg
cconfigToArgs :: CConfig -> [String]
cconfigToArgs (CConfig is ls ds es) = join [ mapFlags "-I" is, mapFlags "-l" ls, mapFlags "-L" ds, es ]
dynLibR :: CCompiler
-> [FilePath]
-> FilePattern
-> CConfig
-> Rules ()
dynLibR cc objFiles shLib cfg =
shLib %> \out ->
need objFiles >>
command mempty (ccToString cc) ("-shared" : "-o" : out : objFiles <> cconfigToArgs cfg)
objectFileR :: CCompiler
-> FilePath
-> FilePattern
-> CConfig
-> Rules ()
objectFileR cc srcFile objFile cfg =
objFile %> \out ->
need [srcFile] >>
command mempty (ccToString cc) (srcFile : "-c" : "-fPIC" : "-o" : out : cconfigToArgs cfg)
staticLibA :: CmdResult r
=> CCompiler
-> [FilePath]
-> FilePattern
-> CConfig
-> Action r
staticLibA ar objFiles stalib _ =
need objFiles >>
command mempty (arToString ar) ("rcs" : stalib : objFiles)
staticLibR :: CCompiler
-> [FilePath]
-> FilePattern
-> CConfig
-> Rules ()
staticLibR ar objFiles stalib cfg =
stalib %> \out -> staticLibA ar objFiles out cfg