module Development.Shake.Language.C.PkgConfig (
Options(..)
, defaultOptions
, pkgConfig
, fromConfig
) where
import Data.Char (toLower)
import Data.Default.Class (Default(..))
import Data.List (intercalate, isPrefixOf)
import Development.Shake
import Development.Shake.FilePath
import Development.Shake.Language.C ( BuildFlags
, compilerFlags
, libraries
, libraryPath
, linkerFlags
, systemIncludes
, userIncludes )
import Development.Shake.Language.C.Label (append)
import Development.Shake.Language.C.Util (words')
parseCflags :: [String] -> (BuildFlags -> BuildFlags)
parseCflags [] = id
parseCflags (x:xs)
| isPrefixOf "-I" x = parseCflags xs . append systemIncludes [drop 2 x]
| isPrefixOf "-i" x = parseCflags xs . append userIncludes [drop 2 x]
| otherwise = append compilerFlags [(Nothing, [x])]
parseLibs :: [String] -> (BuildFlags -> BuildFlags)
parseLibs [] = id
parseLibs (x:xs)
| isPrefixOf "-l" x = parseLibs xs . append libraries [drop 2 x]
| isPrefixOf "-L" x = parseLibs xs . append libraryPath [drop 2 x]
| otherwise = parseLibs xs . append linkerFlags [x]
parseFlags :: String -> [String]
parseFlags = words' . head . lines
data Options = Options {
searchPath :: Maybe [FilePath]
, static :: Bool
} deriving (Eq, Show)
defaultOptions :: Options
defaultOptions = Options{
searchPath = Nothing
, static = False
}
instance Default Options where
def = defaultOptions
pkgConfig :: Options -> String -> Action (BuildFlags -> BuildFlags)
pkgConfig options pkg = do
env <- case searchPath options of
Nothing -> return []
Just path -> do
env <- addEnv [("PKG_CONFIG_PATH", intercalate [searchPathSeparator] path)]
return [env]
let flags = if static options then ["--static"] else []
pkgconfig which = command ([Traced ""] ++ env) "pkg-config" (flags ++ ["--" ++ which, pkg])
Stdout cflags <- pkgconfig "cflags"
Stdout libs <- pkgconfig "libs"
return ( parseCflags (parseFlags cflags)
. parseLibs (parseFlags libs) )
fromConfig :: Options -> (String -> Action (Maybe String)) -> Action (BuildFlags -> BuildFlags)
fromConfig initialOptions cfg = do
config_searchPath <- fmap words' <$> cfg "PkgConfig.options.searchPath"
config_static <- fmap (bool . words) <$> cfg "PkgConfig.options.static"
config_packages <- fmap words <$> cfg "PkgConfig.packages"
let options = initialOptions {
searchPath = maybe (searchPath initialOptions) Just config_searchPath,
static = maybe (static initialOptions) id config_static
}
flags <- mapM (pkgConfig options) (maybe [] id config_packages)
return $ foldl (.) id $ flags
where
bool (x:_) = map toLower x == "true"
bool _ = False