shake-language-c (empty) → 0.5.0
raw patch · 21 files changed
+2291/−0 lines, 21 filesdep +basedep +fclabelsdep +processsetup-changed
Dependencies added: base, fclabels, process, shake, split, unordered-containers
Files
- Changelog.md +0/−0
- Development/Shake/Language/C.hs +70/−0
- Development/Shake/Language/C/BuildFlags.hs +195/−0
- Development/Shake/Language/C/Config.hs +64/−0
- Development/Shake/Language/C/Host.hs +86/−0
- Development/Shake/Language/C/Label.hs +46/−0
- Development/Shake/Language/C/Language.hs +47/−0
- Development/Shake/Language/C/PkgConfig.hs +132/−0
- Development/Shake/Language/C/Rules.hs +154/−0
- Development/Shake/Language/C/Target.hs +104/−0
- Development/Shake/Language/C/Target/Android.hs +202/−0
- Development/Shake/Language/C/Target/Linux.hs +80/−0
- Development/Shake/Language/C/Target/NaCl.hs +193/−0
- Development/Shake/Language/C/Target/OSX.hs +190/−0
- Development/Shake/Language/C/Target/Windows.hs +82/−0
- Development/Shake/Language/C/ToolChain.hs +271/−0
- Development/Shake/Language/C/Util.hs +51/−0
- LICENSE +202/−0
- README.md +38/−0
- Setup.hs +18/−0
- shake-language-c.cabal +66/−0
+ Changelog.md view
+ Development/Shake/Language/C.hs view
@@ -0,0 +1,70 @@+-- Copyright 2012-2014 Samplecount S.L.+--+-- Licensed under the Apache License, Version 2.0 (the "License");+-- you may not use this file except in compliance with the License.+-- You may obtain a copy of the License at+--+-- http://www.apache.org/licenses/LICENSE-2.0+--+-- Unless required by applicable law or agreed to in writing, software+-- distributed under the License is distributed on an "AS IS" BASIS,+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+-- See the License for the specific language governing permissions and+-- limitations under the License.++{-|+Description: Build @C@ language projects for various target platforms+-}++module Development.Shake.Language.C (+ -- * High-level build rules+ module Development.Shake.Language.C.Rules+ , module Development.Shake.Language.C.BuildFlags+ -- * Build targets+ -- $targets+ , module Development.Shake.Language.C.Target+ -- * Toolchains+ , module Development.Shake.Language.C.ToolChain+ -- * Source Languages+ , module Development.Shake.Language.C.Language+) where++import Development.Shake.Language.C.BuildFlags+import Development.Shake.Language.C.Language+import Development.Shake.Language.C.Rules+import Development.Shake.Language.C.Target+import Development.Shake.Language.C.ToolChain (+ Linkage(..)+ , LinkResult(..)+ , ToolChain+ , ToolChainVariant(..)+ , toolDirectory+ , toolPrefix+ , variant+ , compilerCommand+ , compiler+ , archiverCommand+ , archiver+ , linkerCommand+ , linker+ , defaultBuildFlags+ , defaultCompiler+ , Archiver+ , defaultArchiver+ , Linker+ , defaultLinker+ , applyEnv+ , toEnv+ )++{- $targets++This library's focus is on cross compilation. Here's a list of modules that+provide support for targeting specific platforms:++ * "Development.Shake.Language.C.Target.Android"+ * "Development.Shake.Language.C.Target.Linux"+ * "Development.Shake.Language.C.Target.NaCl"+ * "Development.Shake.Language.C.Target.OSX"+ * "Development.Shake.Language.C.Target.Windows"+-}
+ Development/Shake/Language/C/BuildFlags.hs view
@@ -0,0 +1,195 @@+-- Copyright 2012-2014 Samplecount S.L.+--+-- Licensed under the Apache License, Version 2.0 (the "License");+-- you may not use this file except in compliance with the License.+-- You may obtain a copy of the License at+--+-- http://www.apache.org/licenses/LICENSE-2.0+--+-- Unless required by applicable law or agreed to in writing, software+-- distributed under the License is distributed on an "AS IS" BASIS,+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+-- See the License for the specific language governing permissions and+-- limitations under the License.++{-# LANGUAGE TemplateHaskell #-}++{-|+Description: Build flags record for building @C@ language projects++The `BuildFlags` record is an abstraction for various toolchain flags for+building executables and libraries from source files in a @C@-based language.+It's intended to be toolchain-independent, but currently there's certainly a+bias towards binutils\/gcc/clang toolchains.+-}++module Development.Shake.Language.C.BuildFlags (+ BuildFlags+ -- Poor man's documentation for TH generated functions.+ , systemIncludes -- | System include directories, referenced by @#include \<...\>@ in code and usually passed to the compiler with the @-I@ flag.+ , userIncludes -- | User include directories, referenced by @#include "..."@ in code and usually passed to the compiler with the @-iquote@ flag.+ , defines -- | Preprocessor defines, a list of pairs of names with or without a value.+ , preprocessorFlags -- | Other preprocessor flags.+ , compilerFlags -- | Compiler flags, either generic ones or for a specific source 'Language'.+ , libraryPath -- | Linker search path for libraries.+ , libraries -- | List of libraries to link against. Note that you should use the library name without the @lib@ prefix and without extension.+ , linkerFlags -- | Flags passed to the linker.+ , localLibraries -- | Locally built static libraries to be linked against. See also the corresponding section in the <https://github.com/samplecount/shake-language-c/blob/master/docs/Manual.md#locally-built-libraries manual>.+ , archiverFlags -- | Flags passed to the object archiver.+ , defineFlags+ , compilerFlagsFor+ , fromConfig+ , (>>>=)+ , append+ , prepend+) where++import Control.Arrow+import Control.Monad+import Data.Char (isSpace)+import Data.Monoid+import Data.List+import Data.List.Split+import Data.Maybe+import Development.Shake.Language.C.Language (Language(..))+import Development.Shake.Language.C.Label+import Development.Shake.Language.C.Util++{-| Record type for abstracting various toolchain command line flags.++`BuildFlags` is an instance `Monoid`, you can create a default record with+`mempty` and append flags with `mappend`.++Record accessors are 'Data.Label.Mono.Lens' es from the+<https://hackage.haskell.org/package/fclabels fclabels> package, which+makes accessing and modifying record fields a bit more convenient.+@fclabels@ was chosen over <https://hackage.haskell.org/package/lens lens>+because it has far fewer dependencies, which is convenient when installing+the Shake build system in a per-project cabal sandbox. We might switch to+@lens@ when it gets included in the Haskell platform.++There are two convenience functions for working with `BuildFlags` record fields+containing lists of flags, `append` and `prepend`. Since most combinators in+this library expect a function @BuildFlags -> BuildFlags@, the following is a+common idiom:++@+buildFlags . append `systemIncludes` ["path"]+@++Note that when modifying the same record field, order of function composition+matters and you might want to use the arrow combinator '>>>' for appending in+source statement order:++>>> get systemIncludes \+ $ buildFlags >>> append systemIncludes ["path1"] >>> append systemIncludes ["path2"] \+ $ mempty+["path1", "path2"]++See "Development.Shake.Language.C.Rules" for how to use 'BuildFlags' in build+product rules.+-}+data BuildFlags = BuildFlags {+ _systemIncludes :: [FilePath]+ , _userIncludes :: [FilePath]+ , _defines :: [(String, Maybe String)]+ , _preprocessorFlags :: [String]+ , _compilerFlags :: [(Maybe Language, [String])]+ , _libraryPath :: [FilePath]+ , _libraries :: [String]+ , _linkerFlags :: [String]+ -- This is needed for linking against local libraries built by shake (the linker `needs' its inputs).+ , _localLibraries :: [FilePath]+ , _archiverFlags :: [String]+ } deriving (Eq, Show)++mkLabel ''BuildFlags++defaultBuildFlags :: BuildFlags+defaultBuildFlags =+ BuildFlags {+ _systemIncludes = []+ , _userIncludes = []+ , _defines = []+ , _preprocessorFlags = []+ , _compilerFlags = []+ , _libraryPath = []+ , _libraries = []+ , _linkerFlags = []+ , _localLibraries = []+ , _archiverFlags = []+ }++instance Monoid BuildFlags where+ mempty = defaultBuildFlags+ a `mappend` b =+ append systemIncludes (get systemIncludes a)+ . append userIncludes (get userIncludes a)+ . append defines (get defines a)+ . append preprocessorFlags (get preprocessorFlags a)+ . append compilerFlags (get compilerFlags a)+ . append libraryPath (get libraryPath a)+ . append libraries (get libraries a)+ . append linkerFlags (get linkerFlags a)+ . append localLibraries (get localLibraries a)+ . append archiverFlags (get archiverFlags a)+ $ b++-- | Construct preprocessor flags from the 'defines' field of 'BuildFlags'.+defineFlags :: BuildFlags -> [String]+defineFlags = concatMapFlag "-D"+ . map (\(a, b) -> maybe a (\b' -> a++"="++b') b)+ . get defines++-- | Return a list of compiler flags for a specific source language.+compilerFlagsFor :: Maybe Language -> BuildFlags -> [String]+compilerFlagsFor lang = concat+ . maybe (map snd . filter (isNothing.fst))+ (mapMaybe . f) lang+ . get compilerFlags+ where f _ (Nothing, x) = Just x+ f l (Just l', x) | l == l' = Just x+ | otherwise = Nothing++-- | Construct a 'BuildFlags' modifier function from a config file.+--+-- See also "Development.Shake.Language.C.Config".+fromConfig :: (Functor m, Monad m) => (String -> m (Maybe String)) -> m (BuildFlags -> BuildFlags)+fromConfig getConfig = do+ let parseConfig parser = fmap (maybe [] parser) . getConfig . ("BuildFlags."++)++ config_systemIncludes <- parseConfig paths "systemIncludes"+ config_userIncludes <- parseConfig paths "userIncludes"+ config_defines <- parseConfig defines' "defines"+ config_preprocessorFlags <- parseConfig flags "preprocessorFlags"+ config_compilerFlags <- parseConfig ((:[]) . ((,)Nothing) . flags) "compilerFlags"+ config_compilerFlags_c <- parseConfig ((:[]) . ((,)(Just C)) . flags) "compilerFlags.c"+ config_compilerFlags_cxx <- parseConfig ((:[]) . ((,)(Just Cpp)) . flags) "compilerFlags.cxx"+ config_libraryPath <- parseConfig paths "libraryPath"+ config_libraries <- parseConfig flags "libraries"+ config_linkerFlags <- parseConfig flags "linkerFlags"+ config_localLibraries <- parseConfig paths "localLibraries"+ config_archiverFlags <- parseConfig flags "archiverFlags"++ return $ append systemIncludes config_systemIncludes+ . append userIncludes config_userIncludes+ . append defines config_defines+ . append preprocessorFlags config_preprocessorFlags+ . append compilerFlags (config_compilerFlags ++ config_compilerFlags_c ++ config_compilerFlags_cxx)+ . append libraryPath config_libraryPath+ . append libraries config_libraries+ . append linkerFlags config_linkerFlags+ . append localLibraries config_localLibraries+ . append archiverFlags config_archiverFlags+ where+ flags = words' . dropWhile isSpace+ paths = words' . dropWhile isSpace+ define [] = error "Empty preprocessor definition"+ define [k] = (k, Nothing)+ define [k,v] = (k, Just v)+ define (k:vs) = (k, Just (intercalate "=" vs))+ defines' = map (define . splitOn "=") . flags++-- | Utility function for composing functions in a monad.+(>>>=) :: Monad m => m (a -> b) -> m (b -> c) -> m (a -> c)+(>>>=) = liftM2 (>>>)
+ Development/Shake/Language/C/Config.hs view
@@ -0,0 +1,64 @@+{-# LANGUAGE DeriveDataTypeable, GeneralizedNewtypeDeriving #-}++{-|+Description: Read values from configuration files++This module provides utilities for reading values from configuration files,+similar to the functions provided by "Development.Shake.Config".+-}+module Development.Shake.Language.C.Config(+ withConfig+ , parsePaths+ , getPaths+) where++import Control.Applicative+import qualified Data.HashMap.Strict as Map+import Development.Shake+import Development.Shake.Classes+import Development.Shake.Config (readConfigFileWithEnv)+import Development.Shake.Language.C.Util (words')++newtype Config = Config ([(String, String)], FilePath, String) deriving (Show,Typeable,Eq,Hashable,Binary,NFData)++{- | Given a list of dependencies, return a function that takes an environment+of variable bindings, a configuration file path and a configuration variable+and returns the corresponding configuration value.++This function is more flexible than `Development.Shake.Config.usingConfigFile`.+It allows the use of multiple configuration files as well as specifying default+variable bindings.++Typical usage would be something like this:++> -- In the Rules monad+> getConfig <- withConfig []+> -- Then in an Action+> ... value <- getConfig [("variable", "default value")] "config.cfg" "variable"+-}+withConfig :: [FilePath]+ -> Rules ( [(String,String)]+ -> FilePath+ -> String+ -> Action (Maybe String))+withConfig deps = do+ fileCache <- newCache $ \(env, file) -> do+ need deps+ liftIO $ readConfigFileWithEnv env file+ query <- addOracle $ \(Config (env, file, key)) -> Map.lookup key <$> fileCache (env, file)+ return $ \env file key -> query (Config (env, file, key))++-- | Parse a list of space separated paths from an input string. Spaces can be escaped by @\\@ characters.+--+-- prop> parsePaths "a b c\\ d" == ["a", "b", "c d"]+parsePaths :: String -> [FilePath]+parsePaths = words'++-- | Given a function that maps a configuration variable to a value and a list of variable names, return a corresponding list of file paths. Missing variables are ignored.+getPaths ::+ (String -> Action (Maybe String)) -- ^ Configuration lookup function+ -> [String] -- ^ Configuration keys+ -> Action [FilePath] -- ^ File paths+getPaths getConfig keys = do+ sources <- mapM (fmap (fmap parsePaths) . getConfig) keys+ return $ concatMap (maybe [] id) sources
+ Development/Shake/Language/C/Host.hs view
@@ -0,0 +1,86 @@+-- Copyright 2012-2013 Samplecount S.L.+--+-- Licensed under the Apache License, Version 2.0 (the "License");+-- you may not use this file except in compliance with the License.+-- You may obtain a copy of the License at+--+-- http://www.apache.org/licenses/LICENSE-2.0+--+-- Unless required by applicable law or agreed to in writing, software+-- distributed under the License is distributed on an "AS IS" BASIS,+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+-- See the License for the specific language governing permissions and+-- limitations under the License.++{-|+Description: Toolchain definitions and utilities for host platform+-}+module Development.Shake.Language.C.Host (+ OS(..)+ , os+ , executableExtension+ , sharedLibraryExtension+ , loadableLibraryExtension+ , defaultToolChain+) where++import Development.Shake (Action)+import Development.Shake.Language.C.Target (Target)+import qualified Development.Shake.Language.C.Target.Linux as Linux+import qualified Development.Shake.Language.C.Target.OSX as OSX+import qualified Development.Shake.Language.C.Target.Windows as Windows+import Development.Shake.Language.C.ToolChain (ToolChain)+import qualified System.Info as System+import System.IO.Unsafe (unsafePerformIO)++-- | Host operating system.+data OS =+ Linux+ | OSX+ | Windows+ deriving (Eq, Ord, Show)++-- | This host's operating system.+os :: OS+os =+ case System.os of+ "darwin" -> OSX+ "mingw32" -> Windows+ "linux" -> Linux+ _ -> error $ "Unknown host operating system: " ++ System.os++-- | File extension for executables.+executableExtension :: String+executableExtension =+ case os of+ Windows -> "exe"+ _ -> ""++-- | File extension for dynamic shared libraries.+sharedLibraryExtension :: String+sharedLibraryExtension =+ case os of+ Linux -> "so"+ OSX -> "dylib"+ Windows -> "dll"++-- | File extension for dynamic loadable libraries.+loadableLibraryExtension :: String+loadableLibraryExtension =+ case os of+ Linux -> "so"+ OSX -> "bundle"+ Windows -> "dll"++-- | Get host's default toolchain.+--+-- This function can be used for targeting the host operating system, see also "Development.Shake.Language.C.Rules".+defaultToolChain :: (Target, Action ToolChain)+{-# NOINLINE defaultToolChain #-}+defaultToolChain = unsafePerformIO $ do+ -- The assumption here is that target and toolchain don't change while the program is running.+ case os of+ Linux -> Linux.getDefaultToolChain+ OSX -> OSX.getDefaultToolChain+ Windows -> Windows.getDefaultToolChain+ -- _ -> error $ "No default toolchain for this operating system (" ++ show os ++ ")"
+ Development/Shake/Language/C/Label.hs view
@@ -0,0 +1,46 @@+-- Copyright 2012-2013 Samplecount S.L.+--+-- Licensed under the Apache License, Version 2.0 (the "License");+-- you may not use this file except in compliance with the License.+-- You may obtain a copy of the License at+--+-- http://www.apache.org/licenses/LICENSE-2.0+--+-- Unless required by applicable law or agreed to in writing, software+-- distributed under the License is distributed on an "AS IS" BASIS,+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+-- See the License for the specific language governing permissions and+-- limitations under the License.++{-# LANGUAGE TypeOperators #-}++{-|+Description: Lens utilities++This module provides some lens utilities and also re-exports "Data.Label",+which can avoid a package dependency on @fclabels@ in some cases.+-}+module Development.Shake.Language.C.Label (+ module Data.Label+ , append+ , prepend+) where++import Data.Label+import Data.Monoid (Monoid, mappend)++-- | Append stuff to the 'Monoid' in record field specified by lens.+append :: Monoid a =>+ (f :-> a) -- ^ lens+ -> a -- ^ stuff to append+ -> f -- ^ original record+ -> f -- ^ modified record+append l n = modify l (`mappend` n)++-- | Prepend stuff to the 'Monoid' in record field specified by lens.+prepend :: Monoid a =>+ (f :-> a) -- ^ lens+ -> a -- ^ stuff to prepend+ -> f -- ^ original record+ -> f -- ^ modified record+prepend l n = modify l (n `mappend`)
+ Development/Shake/Language/C/Language.hs view
@@ -0,0 +1,47 @@+-- Copyright 2012-2014 Samplecount S.L.+--+-- Licensed under the Apache License, Version 2.0 (the "License");+-- you may not use this file except in compliance with the License.+-- You may obtain a copy of the License at+--+-- http://www.apache.org/licenses/LICENSE-2.0+--+-- Unless required by applicable law or agreed to in writing, software+-- distributed under the License is distributed on an "AS IS" BASIS,+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+-- See the License for the specific language governing permissions and+-- limitations under the License.++{-# LANGUAGE TemplateHaskell #-}++module Development.Shake.Language.C.Language (+ Language(..)+ , defaultLanguageMap+ , languageOf+) where++import Development.Shake.FilePath (takeExtension)++-- | Source language.+--+-- Currently something derived from @C@.+data Language =+ C -- ^ Plain old C+ | Cpp -- ^ C+++ | ObjC -- ^ Objective-C+ | ObjCpp -- ^ Objective-C with C++ (Apple extension)+ deriving (Enum, Eq, Show)++-- | Default mapping from file extension to source language.+defaultLanguageMap :: [(String, Language)]+defaultLanguageMap = concatMap f [+ (C, [".c"])+ , (Cpp, [".cc", ".CC", ".cpp", ".CPP", ".C", ".cxx", ".CXX"])+ , (ObjC, [".m"])+ , (ObjCpp, [".mm", ".M"])+ ]+ where f (lang, exts) = map (\ext -> (ext, lang)) exts++-- | Determine the source language of a file based on its extension.+languageOf :: FilePath -> Maybe Language+languageOf = flip lookup defaultLanguageMap . takeExtension
+ Development/Shake/Language/C/PkgConfig.hs view
@@ -0,0 +1,132 @@+-- Copyright 2012-2013 Samplecount S.L.+--+-- Licensed under the Apache License, Version 2.0 (the "License");+-- you may not use this file except in compliance with the License.+-- You may obtain a copy of the License at+--+-- http://www.apache.org/licenses/LICENSE-2.0+--+-- Unless required by applicable law or agreed to in writing, software+-- distributed under the License is distributed on an "AS IS" BASIS,+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+-- See the License for the specific language governing permissions and+-- limitations under the License.++{-|+Description: Query build flags with @pkg-config@++This module provides utilities for querying 'BuildFlags' from the+<http://www.freedesktop.org/wiki/Software/pkg-config/ pkg-config> database,+which is available on many Unix like operating systems.+-}+module Development.Shake.Language.C.PkgConfig (+ Options(..)+ , defaultOptions+ , pkgConfigWithOptions+ , pkgConfig+ , fromConfig+ , fromConfigWithOptions+) where++import Control.Applicative+import Data.Char (toLower)+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')++-- ====================================================================+-- PkgConfig++-- TODO:+-- * Use parsec or attoparsec for more robust parser+-- * Parse preprocessor defines+-- * Parse framework path (-F) and -framework flags++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++-- | PkgConfig options.+data Options = Options {+ searchPath :: Maybe [FilePath] -- ^ List of directories where @.pc@ files are searched, corresponding to the @PKG_CONFIG_PATH@ environment variable+ , static :: Bool -- ^ Return flags appropriate for static linking+ } deriving (Eq, Show)++-- | Default options.+defaultOptions :: Options+defaultOptions = Options {+ searchPath = Nothing+ , static = False+ }++-- | Call @pkg-config@ with options and a package name and return a 'BuildFlags' modification function.+--+-- The @pkg-config@ executable must be installed on the build host.+pkgConfigWithOptions :: Options -> String -> Action (BuildFlags -> BuildFlags)+pkgConfigWithOptions 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) )++-- | Call @pkg-config@ with default options and a package name and return a 'BuildFlags' modification function.+--+-- The @pkg-config@ executable must be installed on the build host.+pkgConfig :: String -> Action (BuildFlags -> BuildFlags)+pkgConfig = pkgConfigWithOptions defaultOptions++-- | Given an initial 'Options' record and a configuration variable lookup function, call @pkg-config@ based on configuration variable settings and return a 'BuildFlags' modification function.+--+-- The following configuration variables are recognised:+--+-- [@PkgConfig.packages@] List of package names for which build flags should be queried+-- [@PkgConfig.options.searchPath@] Space-separated list of file paths, corresponds to the `searchPath` option+-- [@PkgConfig.options.static@] @true@ or @false@, corresponds to the `static` option+fromConfigWithOptions :: Options -> (String -> Action (Maybe String)) -> Action (BuildFlags -> BuildFlags)+fromConfigWithOptions 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 (pkgConfigWithOptions options)+ (maybe [] id config_packages)+ return $ foldl (.) id $ flags+ where+ bool (x:_) = map toLower x == "true"+ bool _ = False++-- | Like `fromConfigWithOptions` but with default options.+fromConfig :: (String -> Action (Maybe String)) -> Action (BuildFlags -> BuildFlags)+fromConfig = fromConfigWithOptions defaultOptions
+ Development/Shake/Language/C/Rules.hs view
@@ -0,0 +1,154 @@+-- Copyright 2012-2014 Samplecount S.L.+--+-- Licensed under the Apache License, Version 2.0 (the "License");+-- you may not use this file except in compliance with the License.+-- You may obtain a copy of the License at+--+-- http://www.apache.org/licenses/LICENSE-2.0+--+-- Unless required by applicable law or agreed to in writing, software+-- distributed under the License is distributed on an "AS IS" BASIS,+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+-- See the License for the specific language governing permissions and+-- limitations under the License.++{-|+Description: High-level Shake rules++This module provides a few high-level rules for building executables and+libraries. Below is an example that builds both a static library and an executable. See+"Development.Shake.Language.C.ToolChain" for examples of toolchain definitions.++> let toolChain = ...+> lib <- staticLibrary toolChain "libexample.a" (pure mempty) (pure ["example_lib.c"])+> exe <- staticLibrary toolChain ("example" <.> exe) (pure mempty) (pure ["example_exe.c"])+> want [lib, exe]++Sometimes you want to structure your project in a set of static libraries that+are later linked into one or more executables. For Shake to recognise the+libraries as dependencies of the executable you need to add them to the+`localLibraries` field of the `BuildFlags` record:++> let toolChain = ...+> buildFlags = ...+> lib <- staticLibrary toolChain "libexample.a"+> (pure buildFlags)+> (pure ["example_lib.c"])+> exe <- executable toolChain ("example" <.> exe)+> (pure $ buildFlags . append localLibraries [lib])+> (pure ["example_exe.c"])+> want [exe]++The rule functions expect their arguments in the 'Action' monad in order to be+able to derive them from side-effecting configuration actions. For example it+can be useful to determine certain toolchain settings either from the+environment, or from configuration files. Using "Control.Applicative" we could+write:++> Android.toolChain+> <$> getEnvWithDefault+> (error "ANDROID_NDK is undefined")+> "ANDROID_NDK"+> <*> pure (Android.sdkVersion 9)+> <*> pure (LLVM, Version [3,4] [])+> <*> pure (Android.target (Arm Armv7))+-}++module Development.Shake.Language.C.Rules (+ executable+ , staticLibrary+ , sharedLibrary+ , loadableLibrary+) where++import Data.Monoid (mempty)+import Development.Shake+import Development.Shake.FilePath+import Development.Shake.Language.C.BuildFlags as BuildFlags+import Development.Shake.Language.C.ToolChain as ToolChain+import Development.Shake.Language.C.Label (get)++mkObjectsDir :: FilePath -> FilePath+mkObjectsDir path = takeDirectory path </> map tr (takeFileName path) ++ "_obj"+ where tr '.' = '_'+ tr x = x++buildProduct :: (ToolChain -> Linker)+ -> Action ToolChain+ -> FilePath+ -> Action (BuildFlags -> BuildFlags)+ -> Action [FilePath]+ -> Rules FilePath+buildProduct getLinker getToolChain result getBuildFlags getSources = do+ let objectsDir = mkObjectsDir result+ cachedObjects <- newCache $ \() -> do+ sources <- getSources+ return $ [ objectsDir </> makeRelative "/" (src <.> if isAbsolute src then "abs.o" else "rel.o")+ | src <- sources ]+ cachedToolChain <- newCache $ \() -> getToolChain+ cachedBuildFlags <- newCache $ \() -> do+ tc <- cachedToolChain ()+ f1 <- get ToolChain.defaultBuildFlags tc+ f2 <- getBuildFlags+ return $ f2 . f1 $ mempty+ result *> \_ -> do+ tc <- cachedToolChain ()+ flags <- cachedBuildFlags ()+ objs <- cachedObjects ()+ need objs+ (getLinker tc)+ tc+ flags+ objs+ result+ (dropTrailingPathSeparator objectsDir ++ "//*.o") *> \obj -> do+ tc <- cachedToolChain ()+ flags <- cachedBuildFlags ()+ -- Compute source file name from object file name+ -- Using getSources here would result in a dependency of every object file on the list of sources, leading to unnecessary rebuilds.+ let src = case splitExtension $ dropExtension $ makeRelative objectsDir obj of+ (x, ".abs") -> "/" </> x -- Source file had absolute path+ (x, ".rel") -> x+ (_, ext) -> error $ "BUG: Unexpected object file extension " ++ ext+ (get compiler tc)+ tc+ flags+ src+ obj+ return result++-- TODO: The following result type would be more composable, e.g. allowing for further build product processing:+-- Rules (FilePath -> Action ())+-- See https://github.com/samplecount/shake-language-c/issues/15++-- | Shake rule for building an executable.+executable :: Action ToolChain -- ^ Action returning a target 'ToolChain'+ -> FilePath -- ^ Output file+ -> Action (BuildFlags -> BuildFlags) -- ^ Action returning a 'BuildFlags' modifier+ -> Action [FilePath] -- ^ Action returning a list of input source files+ -> Rules FilePath -- ^ Rule returning the output file path+executable toolChain = buildProduct (flip (get linker) Executable) toolChain++-- | Shake rule for building a static library.+staticLibrary :: Action ToolChain -- ^ Action returning a target 'ToolChain'+ -> FilePath -- ^ Output file+ -> Action (BuildFlags -> BuildFlags) -- ^ Action returning a 'BuildFlags' modifier+ -> Action [FilePath] -- ^ Action returning a list of input source files+ -> Rules FilePath -- ^ Rule returning the output file path+staticLibrary toolChain = buildProduct (get archiver) toolChain++-- | Shake rule for building a shared (dynamically linked) library.+sharedLibrary :: Action ToolChain -- ^ Action returning a target 'ToolChain'+ -> FilePath -- ^ Output file+ -> Action (BuildFlags -> BuildFlags) -- ^ Action returning a 'BuildFlags' modifier+ -> Action [FilePath] -- ^ Action returning a list of input source files+ -> Rules FilePath -- ^ Rule returning the output file path+sharedLibrary toolChain = buildProduct (flip (get linker) SharedLibrary) toolChain++-- | Shake rule for building a dynamically loadable library.+loadableLibrary :: Action ToolChain -- ^ Action returning a target 'ToolChain'+ -> FilePath -- ^ Output file+ -> Action (BuildFlags -> BuildFlags) -- ^ Action returning a 'BuildFlags' modifier+ -> Action [FilePath] -- ^ Action returning a list of input source files+ -> Rules FilePath -- ^ Rule returning the output file path+loadableLibrary toolChain = buildProduct (flip (get linker) LoadableLibrary) toolChain
+ Development/Shake/Language/C/Target.hs view
@@ -0,0 +1,104 @@+-- Copyright 2012-2014 Samplecount S.L.+--+-- Licensed under the Apache License, Version 2.0 (the "License");+-- you may not use this file except in compliance with the License.+-- You may obtain a copy of the License at+--+-- http://www.apache.org/licenses/LICENSE-2.0+--+-- Unless required by applicable law or agreed to in writing, software+-- distributed under the License is distributed on an "AS IS" BASIS,+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+-- See the License for the specific language governing permissions and+-- limitations under the License.++module Development.Shake.Language.C.Target (+ OS(..)+ , Platform(..)+ , ArmVersion(..)+ , X86Version(..)+ , Arch(..)+ , archString+ , Target(..)+ , ToBuildPrefix(..)+) where++import Data.Char (toLower)+import Development.Shake.FilePath++-- | Target operating system.+data OS =+ Android -- ^ Google Android+ | Linux -- ^ GNU Linux+ | OSX -- ^ Apple Mac OSX and iOS+ | Pepper -- ^ Google Portable Native Client (PNaCl)+ | Windows -- ^ Microsoft Windows+ deriving (Eq, Ord, Show)++-- | Target platform.+--+-- Basically just a platform identifier string.+data Platform = Platform {+ platformName :: String+ } deriving (Eq, Show)++-- | `X86` architecture version.+data X86Version =+ I386 -- ^ @i386@, 32-bit architecture without @SSE@+ | I686 -- ^ @i686@, 32-bit architecture with @SSE@ (/Pentium-Pro/)+ | X86_64 -- ^ @x86_64@, 64-bit architecture+ deriving (Eq, Show)++-- | `Arm` architecture version.+data ArmVersion =+ Armv5+ | Armv6+ | Armv7+ | Armv7s+ deriving (Eq, Show)++-- | Target architecture.+data Arch =+ X86 X86Version -- ^ Intel @x86@ architecture+ | Arm ArmVersion -- ^ Arm architecture+ | LLVM_IR -- ^ LLVM intermediate representation, used by `Pepper` (PNaCl)+ deriving (Eq, Show)++-- | Architecture short string.+--+-- Mainly useful for constructing build output directories.+archString :: Arch -> String+archString arch =+ case arch of+ X86 I386 -> "i386"+ X86 I686 -> "i686"+ X86 X86_64 -> "x86_64"+ Arm Armv5 -> "armv5"+ Arm Armv6 -> "armv6"+ Arm Armv7 -> "armv7"+ Arm Armv7s -> "armv7s"+ LLVM_IR -> "llvm_ir"++-- | Compilation target triple consisting of operating system, platform and architecture.+data Target = Target {+ targetOS :: OS -- ^ Target operating system+ , targetPlatform :: Platform -- ^ Target platform+ , targetArch :: Arch -- ^ Target architecture+ } deriving (Show)++-- | Convert a value to a build directory prefix.+--+-- The idea is that several such values can be combined to form more complex build directory hierarchies. This can be important for disambiguating build product paths in Shake rules.+class ToBuildPrefix a where+ toBuildPrefix :: a -> FilePath++instance ToBuildPrefix Platform where+ toBuildPrefix = map toLower . platformName++instance ToBuildPrefix Arch where+ toBuildPrefix = archString++instance ToBuildPrefix Target where+ toBuildPrefix target =+ toBuildPrefix (targetPlatform target)+ </> toBuildPrefix (targetArch target)
+ Development/Shake/Language/C/Target/Android.hs view
@@ -0,0 +1,202 @@+-- Copyright 2012-2013 Samplecount S.L.+--+-- Licensed under the Apache License, Version 2.0 (the "License");+-- you may not use this file except in compliance with the License.+-- You may obtain a copy of the License at+--+-- http://www.apache.org/licenses/LICENSE-2.0+--+-- Unless required by applicable law or agreed to in writing, software+-- distributed under the License is distributed on an "AS IS" BASIS,+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+-- See the License for the specific language governing permissions and+-- limitations under the License.++{-|+Description: Toolchain definitions and utilities for Android++This module provides toolchain definitions and utilities for targeting Android.+See "Development.Shake.Language.C.Rules" for examples of how to use a target+toolchain.+-}+module Development.Shake.Language.C.Target.Android (+ target+ , sdkVersion+ , toolChain+ , abiString+ , gnustl+ , libcxx+ , native_app_glue+) where++import Control.Arrow+import Development.Shake.FilePath+import Data.Version (Version(..), showVersion)+import Development.Shake.Language.C.BuildFlags+import Development.Shake.Language.C.Target+import Development.Shake.Language.C.Label+import Development.Shake.Language.C.Language+import Development.Shake.Language.C.ToolChain+import qualified System.Info as System++unsupportedArch :: Arch -> a+unsupportedArch arch = error $ "Unsupported Android target architecture " ++ archString arch++toolChainPrefix :: Target -> String+toolChainPrefix x =+ case targetArch x of+ X86 _ -> "x86-"+ Arm _ -> "arm-linux-androideabi-"+ arch -> unsupportedArch arch++osPrefix :: String+osPrefix = System.os ++ "-" ++ cpu+ where cpu = case System.arch of+ "i386" -> "x86"+ arch -> arch++-- | Android target for architecture.+target :: Arch -> Target+target = Target Android (Platform "android")++mkDefaultBuildFlags :: FilePath -> Version -> Arch -> BuildFlags -> BuildFlags+mkDefaultBuildFlags ndk version arch =+ append compilerFlags [(Nothing, [sysroot, march])]+ >>> append compilerFlags (archCompilerFlags arch)+ >>> append compilerFlags [(Nothing, [+ "-fpic"+ , "-ffunction-sections"+ , "-funwind-tables"+ , "-fstack-protector"+ , "-no-canonical-prefixes"])]+ >>> append linkerFlags [sysroot, march]+ >>> append linkerFlags (archLinkerFlags arch)+ >>> append linkerFlags ["-Wl,--no-undefined", "-Wl,-z,relro", "-Wl,-z,now"]+ >>> append linkerFlags ["-no-canonical-prefixes"]+ >>> append archiverFlags ["crs"]+ where+ sysroot = "--sysroot="+ ++ ndk+ </> "platforms"+ </> "android-" ++ show (head (versionBranch version))+ </> "arch-" ++ case arch of+ (X86 _) -> "x86"+ (Arm _) -> "arm"+ _ -> unsupportedArch arch+ march = "-march=" ++ case arch of+ (Arm Armv5) -> "armv5te"+ (Arm Armv6) -> "armv5te"+ (Arm Armv7) -> "armv7-a"+ _ -> archString arch+ archCompilerFlags (Arm Armv7) = [(Nothing, ["-mfloat-abi=softfp", "-mfpu=neon" {- vfpv3-d16 -}])]+ archCompilerFlags (Arm _) = [(Nothing, ["-mtune=xscale", "-msoft-float"])]+ archCompilerFlags _ = []+ archLinkerFlags (Arm Armv7) = ["-Wl,--fix-cortex-a8"]+ archLinkerFlags _ = []++-- | Construct a version record from an integral Android SDK version.+--+-- prop> sdkVersion 19 == Version [19] []+sdkVersion :: Int -> Version+sdkVersion n = Version [n] []++-- | Construct an Android toolchain.+toolChain :: FilePath -- ^ NDK source directory+ -> Version -- ^ SDK version, see `sdkVersion`+ -> (ToolChainVariant, Version) -- ^ Toolchain variant and version+ -> Target -- ^ Build target, see `target`+ -> ToolChain -- ^ Resulting toolchain+toolChain "" _ (_, _) _ = error "Empty NDK directory"+toolChain ndk version (GCC, tcVersion) t =+ set variant GCC+ $ set toolDirectory (Just (ndk </> "toolchains"+ </> toolChainPrefix t ++ showVersion tcVersion+ </> "prebuilt"+ </> osPrefix+ </> "bin"))+ $ set toolPrefix (toolChainPrefix t)+ $ set compilerCommand "gcc"+ $ set archiverCommand "ar"+ $ set linkerCommand "g++"+ $ set defaultBuildFlags (return $ mkDefaultBuildFlags ndk version (targetArch t))+ $ defaultToolChain+toolChain ndk version (LLVM, tcVersion) t =+ set variant LLVM+ $ set toolDirectory (Just (ndk </> "toolchains"+ </> "llvm-" ++ showVersion tcVersion+ </> "prebuilt"+ </> osPrefix+ </> "bin"))+ $ set compilerCommand "clang"+ $ set archiverCommand "llvm-ar"+ $ set linkerCommand "clang++"+ $ set defaultBuildFlags (return $+ let gcc_toolchain = ndk </> "toolchains/arm-linux-androideabi-4.8/prebuilt" </> osPrefix+ flags = ["-target", llvmTarget t, "-gcc-toolchain", gcc_toolchain]+ in mkDefaultBuildFlags ndk version (targetArch t)+ . append compilerFlags [(Nothing, flags)]+ . append linkerFlags flags+ )+ $ defaultToolChain+ where+ llvmTarget x =+ case targetArch x of+ Arm Armv5 -> "armv5te-none-linux-androideabi"+ Arm Armv7 -> "armv7-none-linux-androideabi"+ X86 I386 -> "i686-none-linux-android"+ arch -> unsupportedArch arch+toolChain _ _ (tcVariant, tcVersion) _ =+ error $ "Unknown toolchain variant "+ ++ show tcVariant ++ " "+ ++ showVersion tcVersion++-- | Valid Android ABI identifier for the given architecture.+abiString :: Arch -> String+abiString (Arm Armv5) = "armeabi"+abiString (Arm Armv6) = "armeabi"+abiString (Arm Armv7) = "armeabi-v7a"+abiString (X86 _) = "x86"+abiString arch = unsupportedArch arch++-- | Source paths and build flags for the @native_app_glue@ module.+native_app_glue :: FilePath -- ^ NDK source directory+ -> ([FilePath], BuildFlags -> BuildFlags)+native_app_glue ndk =+ ( [ndk </> "sources/android/native_app_glue/android_native_app_glue.c"]+ , append systemIncludes [ndk </> "sources/android/native_app_glue"] )++-- | Build flags for building with and linking against the GNU @gnustl@ standard C++ library.+gnustl :: Version -- ^ GNU STL version+ -> Linkage -- ^ `Static` or `Shared`+ -> FilePath -- ^ NDK source directory+ -> Target -- ^ Build target, see `target`+ -> (BuildFlags -> BuildFlags) -- ^ 'BuildFlags' modification function+gnustl version linkage ndk t =+ append systemIncludes [stlPath </> "include", stlPath </> "libs" </> abi </> "include"]+ . append libraryPath [stlPath </> "libs" </> abi]+ . append libraries [lib]+ where stlPath = ndk </> "sources/cxx-stl/gnu-libstdc++" </> showVersion version+ abi = abiString (targetArch t)+ lib = case linkage of+ Static -> "gnustl_static"+ Shared -> "gnustl_shared"++-- | Build flags for building with and linking against the LLVM @libc++@ standard C++ library.+libcxx :: Linkage -- ^ `Static` or `Shared`+ -> FilePath -- ^ NDK source directory+ -> Target -- ^ Build target, see `target`+ -> (BuildFlags -> BuildFlags) -- ^ 'BuildFlags' modification function+libcxx linkage ndk t =+ append systemIncludes [ libcxxPath </> "libcxx" </> "include"+ -- NOTE: libcxx needs to be first in include path!+ , stlPath </> "gabi++" </> "include"+ , ndk </> "sources" </> "android" </> "support" </> "include" ]+ . append compilerFlags [(Just Cpp, ["-stdlib=libc++"])]+ . append libraryPath [libcxxPath </> "libs" </> abi]+ . prepend libraries [lib]+ where stlPath = ndk </> "sources" </> "cxx-stl"+ libcxxPath = stlPath </> "llvm-libc++"+ abi = abiString (targetArch t)+ lib = case linkage of+ Static -> "c++_static"+ Shared -> "c++_shared"
+ Development/Shake/Language/C/Target/Linux.hs view
@@ -0,0 +1,80 @@+-- Copyright 2012-2013 Samplecount S.L.+--+-- Licensed under the Apache License, Version 2.0 (the "License");+-- you may not use this file except in compliance with the License.+-- You may obtain a copy of the License at+--+-- http://www.apache.org/licenses/LICENSE-2.0+--+-- Unless required by applicable law or agreed to in writing, software+-- distributed under the License is distributed on an "AS IS" BASIS,+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+-- See the License for the specific language governing permissions and+-- limitations under the License.++{-|+Description: Toolchain definitions and utilities for Linux++This module provides toolchain definitions and utilities for targeting Linux.+See "Development.Shake.Language.C.Rules" for examples of how to use a target+toolchain.++Linux is also a supported host operating system, see+"Development.Shake.Language.C.Host" for examples of how to target the host.+-}++module Development.Shake.Language.C.Target.Linux (+ toolChain+ , getDefaultToolChain+) where++import Data.Label (get, set)+import Development.Shake+import Development.Shake.Language.C.BuildFlags+import Development.Shake.Language.C.Target+import Development.Shake.Language.C.ToolChain+import System.Process (readProcess)++getHostArch :: IO Arch+getHostArch = do+ arch <- fmap (head.lines) $ readProcess "arch" [] ""+ return $ case arch of+ "i386" -> X86 I386+ "i686" -> X86 I686+ "x86_64" -> X86 X86_64+ _ -> error $ "Unknown host architecture " ++ arch++target :: Arch -> Target+target = Target Linux (Platform "linux")++platformArchiver :: Archiver+platformArchiver tc buildFlags inputs output = do+ need inputs+ command_ [] (tool tc archiverCommand)+ $ ["cr"]+ ++ get archiverFlags buildFlags+ ++ [output]+ ++ inputs+ command_ [] (toolFromString tc "ranlib") [output]++-- | Linux toolchain.+toolChain :: ToolChainVariant -> ToolChain+toolChain GCC =+ set variant GCC+ $ set compilerCommand "gcc"+ $ set archiverCommand "ar"+ $ set archiver platformArchiver+ $ set linkerCommand "g++"+ $ defaultToolChain+toolChain LLVM =+ set variant LLVM+ $ set compilerCommand "gcc"+ $ set archiverCommand "ar"+ $ set linkerCommand "g++"+ $ defaultToolChain+toolChain Generic = toolChain GCC++getDefaultToolChain :: IO (Target, Action ToolChain)+getDefaultToolChain = do+ t <- fmap target getHostArch+ return (t, return $ toolChain GCC)
+ Development/Shake/Language/C/Target/NaCl.hs view
@@ -0,0 +1,193 @@+-- Copyright 2013 Samplecount S.L.+--+-- Licensed under the Apache License, Version 2.0 (the "License");+-- you may not use this file except in compliance with the License.+-- You may obtain a copy of the License at+--+-- http://www.apache.org/licenses/LICENSE-2.0+--+-- Unless required by applicable law or agreed to in writing, software+-- distributed under the License is distributed on an "AS IS" BASIS,+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+-- See the License for the specific language governing permissions and+-- limitations under the License.++{-|+Description: Toolchain definitions and utilities for Google Pepper and Portable Native Client++This module provides toolchain definitions and utilities for targeting Google+Pepper and Portable Native Client (PNaCl). Arguably it should be renamed+appropriately. See "Development.Shake.Language.C.Rules" for examples of how to+use a target toolchain.+-}+module Development.Shake.Language.C.Target.NaCl (+ pepper+ , canary+ , target+ , Config(..)+ , toolChain+ , finalize+ , translate+ , libppapi+ , libppapi_cpp+ , libnacl_io+ , libppapi_simple+ , Arch(..)+ , mk_nmf+) where++import Data.List (intercalate)+import Development.Shake+import Development.Shake.FilePath+import Data.Version (Version(..))+import Development.Shake.Language.C hiding (Arch)+import qualified Development.Shake.Language.C.Target as C+import Development.Shake.Language.C.ToolChain+import qualified Development.Shake.Language.C.Host as Host+import Development.Shake.Language.C.Label++-- | Stable /Pepper/ API version.+pepper :: Int -> Version+pepper apiVersion = Version [apiVersion] []++-- | Unstable /Pepper Canary/ API version.+canary :: Version+canary = Version [] ["canary"]++-- | Pepper target.+--+-- `LLVM_IR` (PNaCl) is the only supported target architecture at the moment.+target :: Target+target = Target Pepper (Platform "pepper") LLVM_IR++hostString :: String+hostString =+ case Host.os of+ Host.Linux -> "linux"+ Host.OSX -> "mac"+ Host.Windows -> "win"++-- | Pepper build configuration.+--+-- This is used to select the respective library versions when linking.+data Config = Debug | Release deriving (Eq, Show)++-- | Construct Pepper toolchain.+toolChain :: FilePath -- ^ Pepper SDK directory (@nacl_sdk@)+ -> Version -- ^ Pepper API version, see `pepper` and `canary`+ -> Config -- ^ Build configuration for linked libraries+ -> Target -- ^ Target, see `target`+ -> ToolChain -- ^ Resulting toolchain+toolChain sdk sdkVersion config t =+ set variant LLVM+ $ set toolDirectory (Just (platformDir </> "toolchain" </> hostString ++ "_" ++ "pnacl" </> "bin"))+ $ set toolPrefix "pnacl-"+ $ set compilerCommand "clang"+ $ set archiverCommand "ar"+ $ set archiver (\tc flags inputs output -> do+ need inputs+ command_ [] (tool tc archiverCommand)+ $ ["cr"]+ ++ get archiverFlags flags+ ++ [output]+ ++ inputs+ command_ [] (toolFromString tc "ranlib") [output]+ )+ $ set linkerCommand "clang++"+ $ set defaultBuildFlags+ ( return $+ append systemIncludes [includeDir]+ . append userIncludes [includeDir]+ . append systemIncludes [includeDir </> "pnacl"]+ . append libraryPath [platformDir </> "lib" </> "pnacl" </> show config] )+ $ defaultToolChain+ where+ platformDir =+ sdk+ </> platformName (targetPlatform t)+ ++ "_"+ ++ case versionTags sdkVersion of+ ["canary"] -> "canary"+ _ -> show $ head (versionBranch sdkVersion)+ includeDir = platformDir </> "include"++-- | Finalize a bit code executable.+finalize :: ToolChain -- ^ Toolchain, see `toolChain`+ -> FilePath -- ^ Bit code input executable+ -> FilePath -- ^ Finalised bit code output executable+ -> Action ()+finalize tc input output = do+ need [input]+ command_ [] (toolFromString tc "finalize")+ ["-o", output, input]++-- | Translate bit code to native code.+translate :: ToolChain -> C.Arch -> FilePath -> FilePath -> Action ()+translate tc arch input output = do+ let archName =+ case arch of+ X86 I686 -> "i686"+ X86 X86_64 -> "x86-64"+ Arm Armv7 -> "armv7"+ _ -> error $ "Unsupported architecture: " ++ show arch+ need [input]+ command_ [] (toolFromString tc "finalize")+ ["-arch", archName, "-o", output, input]++-- | Link against the Pepper C API library.+libppapi :: BuildFlags -> BuildFlags+libppapi = append libraries ["ppapi"]++-- | Link against the Pepper C++ API library.+libppapi_cpp :: BuildFlags -> BuildFlags+libppapi_cpp = append libraries ["ppapi_cpp"]++-- | Link against @libnacl_io@.+libnacl_io :: BuildFlags -> BuildFlags+libnacl_io = append libraries ["nacl_io"]++-- | Link against the Simple Pepper C API library.+libppapi_simple :: BuildFlags -> BuildFlags+libppapi_simple = append libraries ["ppapi_simple"]++-- | Pepper target architecture+data Arch =+ PNaCl -- ^ Portable Native Client architecture+ | NaCl C.Arch -- ^ Native Client architecture for specific CPU architecture+ deriving (Eq, Show)++-- | Create Native Client Manifest (nmf) file.+--+-- This file is needed for serving NaCl/PNaCl outside the Google Play store. See the native client <https://developer.chrome.com/native-client/reference/nacl-manifest-format documentation> for more information on the file format.+mk_nmf :: [(Arch, FilePath)] -- ^ List of executables with the corresponding architecture+ -> FilePath -- ^ Output file+ -> Action ()+mk_nmf inputs output = do+ need $ map snd inputs+ writeFileLines output $ [+ "{"+ , " \"program\": {"+ ]+ ++ intercalate [","] (map program inputs) +++ [ " }"+ , " }"+ , "}"+ ]+ where+ program (PNaCl, input) = [+ " \"portable\": {"+ , " \"pnacl-translate\": {"+ , " \"url\": \"" ++ makeRelative (takeDirectory output) input ++ "\""+ , " }"+ ]+ program (NaCl arch, input) =+ let archName = case arch of+ X86 X86_64 -> "x86_64"+ X86 _ -> "x86_32"+ Arm _ -> "arm"+ _ -> error $ "mk_nmf: Unsupported architecture " ++ show arch+ in [+ " \"" ++ archName ++ "\": {"+ , " \"url\": \"" ++ makeRelative (takeDirectory output) input ++ "\""+ , " }"+ ]
+ Development/Shake/Language/C/Target/OSX.hs view
@@ -0,0 +1,190 @@+-- Copyright 2012-2013 Samplecount S.L.+--+-- Licensed under the Apache License, Version 2.0 (the "License");+-- you may not use this file except in compliance with the License.+-- You may obtain a copy of the License at+--+-- http://www.apache.org/licenses/LICENSE-2.0+--+-- Unless required by applicable law or agreed to in writing, software+-- distributed under the License is distributed on an "AS IS" BASIS,+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+-- See the License for the specific language governing permissions and+-- limitations under the License.++{-|+Description: Toolchain definitions and utilities for OSX and iOS++This module provides toolchain definitions and utilities for targeting OSX+and iOS. See "Development.Shake.Language.C.Rules" for examples of how to use a+target toolchain.++OSX is also a supported host operating system, see+"Development.Shake.Language.C.Host" for examples of how to target the host.+-}++module Development.Shake.Language.C.Target.OSX (+ DeveloperPath+ , getSDKRoot+ , macOSX+ , iPhoneOS+ , iPhoneSimulator+ , target+ , sdkVersion+ , toolChain+ , getPlatformVersions+ , getDefaultToolChain+ , macosx_version_min+ , iphoneos_version_min+ , universalBinary+) where++import Control.Applicative hiding ((*>))+import Data.List (stripPrefix)+import Data.List.Split (splitOn)+import Data.Maybe+import Data.Version (Version(..), showVersion)+import Development.Shake as Shake+import Development.Shake.FilePath+import Development.Shake.Language.C.BuildFlags+import Development.Shake.Language.C.Target+import Development.Shake.Language.C.Label+import Development.Shake.Language.C.ToolChain+import System.Process (readProcess)+import Text.Read (readEither)++archFlags :: Target -> [String]+archFlags t = ["-arch", archString (targetArch t)]++-- | Base path of development tools on OSX.+newtype DeveloperPath = DeveloperPath FilePath+ deriving (Show)++-- | Get base path of development tools on OSX.+getSDKRoot :: Action DeveloperPath+getSDKRoot = liftIO $+ (DeveloperPath . head . splitOn "\n")+ <$> readProcess "xcode-select" ["--print-path"] ""++-- | Mac OSX platform.+macOSX :: Platform+macOSX = Platform "MacOSX"++-- | iOS platform.+iPhoneOS :: Platform+iPhoneOS = Platform "iPhoneOS"++-- | iOS simulator platform.+iPhoneSimulator :: Platform+iPhoneSimulator = Platform "iPhoneSimulator"++-- | Build target given a platform and an architecture.+target :: Platform -> Arch -> Target+target = Target OSX++sdkDirectory :: FilePath -> Platform -> FilePath+sdkDirectory sdkRoot platform =+ sdkRoot+ </> "Platforms"+ </> (platformName platform ++ ".platform")+ </> "Developer"+ </> "SDKs"++platformSDKPath :: FilePath -> Platform -> Version -> FilePath+platformSDKPath sdkRoot platform version =+ sdkDirectory sdkRoot platform+ </> platformName platform ++ showVersion version ++ ".sdk"++getPlatformVersionsWithRoot :: Platform -> DeveloperPath -> Action [Version]+getPlatformVersionsWithRoot platform (DeveloperPath sdkRoot) = do+ dirs <- getDirectoryDirs (sdkDirectory sdkRoot platform)+ case mapMaybe (stripPrefix name) dirs of+ [] -> error $ "OSX: No SDK found for " ++ name+ xs -> return [ flip Version []+ . map (either error id . readEither)+ . splitOn "."+ . dropExtension $ x+ | x <- xs ]+ where name = platformName platform++-- | Return a list of available platform SDK versions.+--+-- For example in order to get the latest iOS SDK version:+--+-- > maximum <$> getPlatformVersions iPhoneOS+getPlatformVersions :: Platform -> Action [Version]+getPlatformVersions platform =+ getPlatformVersionsWithRoot platform =<< getSDKRoot++-- | Get OSX system version (first two digits).+systemVersion :: Action Version+systemVersion = liftIO $+ flip Version []+ <$> (map read . take 2 . splitOn ".")+ <$> readProcess "sw_vers" ["-productVersion"] ""++getDefaultToolChain :: IO (Target, Action ToolChain)+getDefaultToolChain = do+ let defaultTarget = target macOSX (X86 X86_64)+ return ( defaultTarget+ , toolChain+ <$> getSDKRoot+ <*> systemVersion+ <*> pure defaultTarget )++-- | SDK version given major and minor version numbers.+sdkVersion :: Int -> Int -> Version+sdkVersion major minor = Version [major, minor] []++-- | Construct an OSX or iOS toolchain.+toolChain :: DeveloperPath -- ^ Developer tools base path, see `getSDKRoot`+ -> Version -- ^ Target SDK version+ -> Target -- ^ Build target, see `target`+ -> ToolChain -- ^ Resulting toolchain+toolChain (DeveloperPath sdkRoot) version t =+ set variant LLVM+ $ set toolDirectory (Just (sdkRoot </> "Toolchains/XcodeDefault.xctoolchain/usr/bin"))+ $ set compilerCommand "clang"+ $ set archiverCommand "libtool"+ $ set archiver (\tc flags inputs output -> do+ need inputs+ command_ [] (tool tc archiverCommand)+ $ get archiverFlags flags+ ++ ["-static"]+ ++ ["-o", output]+ ++ inputs+ )+ $ set linkerCommand "clang++"+ $ set linker (\lr tc ->+ case lr of+ Executable -> defaultLinker tc+ SharedLibrary -> defaultLinker tc . prepend linkerFlags ["-dynamiclib"]+ LoadableLibrary -> defaultLinker tc . prepend linkerFlags ["-bundle"]+ )+ $ set defaultBuildFlags+ ( return $+ append preprocessorFlags [ "-isysroot", sysRoot ]+ . append compilerFlags [(Nothing, archFlags t)]+ . append linkerFlags (archFlags t ++ [ "-isysroot", sysRoot ]) )+ $ defaultToolChain+ where sysRoot = platformSDKPath sdkRoot (targetPlatform t) version++-- | Specify the @-mmacosx-version-min@ compiler flag.+macosx_version_min :: Version -> BuildFlags -> BuildFlags+macosx_version_min version =+ append compilerFlags [(Nothing, ["-mmacosx-version-min=" ++ showVersion version])]++-- | Specify the @-miphoneos-version-min@ compiler flag.+iphoneos_version_min :: Version -> BuildFlags -> BuildFlags+iphoneos_version_min version =+ append compilerFlags [(Nothing, ["-miphoneos-version-min=" ++ showVersion version])]++-- | Create a universal binary a list of input files.+--+-- Calls <http://www.manpages.info/macosx/lipo.1.html lipo> with the @-create@ option.+universalBinary :: [FilePath] -- ^ Input files, can be executables, dynamic libraries or static archives but should be all of the same type+ -> FilePath -- ^ Output file path+ -> Action ()+universalBinary inputs output = do+ need inputs+ command_ [] "lipo" $ ["-create", "-output", output] ++ inputs
+ Development/Shake/Language/C/Target/Windows.hs view
@@ -0,0 +1,82 @@+-- Copyright 2014 Samplecount S.L.+--+-- Licensed under the Apache License, Version 2.0 (the "License");+-- you may not use this file except in compliance with the License.+-- You may obtain a copy of the License at+--+-- http://www.apache.org/licenses/LICENSE-2.0+--+-- Unless required by applicable law or agreed to in writing, software+-- distributed under the License is distributed on an "AS IS" BASIS,+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+-- See the License for the specific language governing permissions and+-- limitations under the License.++{-|+Description: Toolchain definitions and utilities for Windows++This module provides toolchain definitions and utilities for targeting Windows.+See "Development.Shake.Language.C.Rules" for examples of how to use a target+toolchain.++Windows is also a supported host operating system, see+"Development.Shake.Language.C.Host" for examples of how to target the host.++On Windows currently only the <http://www.mingw.org/ MinGW> toolchain is+supported.+-}++module Development.Shake.Language.C.Target.Windows (+ toolChain+ , getDefaultToolChain+) where++import Data.Label (get, set)+import Development.Shake+import Development.Shake.Language.C.BuildFlags+import Development.Shake.Language.C.Target+import Development.Shake.Language.C.ToolChain+import qualified System.Info as System++getHostArch :: IO Arch+getHostArch = do+ -- TODO: Get the info from the environment+ let arch = System.arch+ return $ case arch of+ "i386" -> X86 I386+ "i686" -> X86 I686+ "x86_64" -> X86 X86_64+ _ -> error $ "Unknown host architecture " ++ arch++target :: Arch -> Target+target = Target Windows (Platform "windows")++-- | Windows toolchain.+toolChain :: ToolChainVariant -> ToolChain+toolChain GCC =+ set variant GCC+ $ set compilerCommand "gcc"+ $ set archiverCommand "ar"+ $ set archiver (\tc flags inputs output -> do+ need inputs+ command_ [] (tool tc archiverCommand)+ $ ["cr"]+ ++ get archiverFlags flags+ ++ [output]+ ++ inputs+ command_ [] (toolFromString tc "ranlib") [output]+ )+ $ set linkerCommand "g++"+ $ defaultToolChain+toolChain LLVM =+ set variant LLVM+ $ set compilerCommand "gcc"+ $ set archiverCommand "ar"+ $ set linkerCommand "g++"+ $ defaultToolChain+toolChain Generic = toolChain GCC++getDefaultToolChain :: IO (Target, Action ToolChain)+getDefaultToolChain = do+ t <- fmap target getHostArch+ return (t, return $ toolChain Generic)
+ Development/Shake/Language/C/ToolChain.hs view
@@ -0,0 +1,271 @@+-- Copyright 2012-2014 Samplecount S.L.+--+-- Licensed under the Apache License, Version 2.0 (the "License");+-- you may not use this file except in compliance with the License.+-- You may obtain a copy of the License at+--+-- http://www.apache.org/licenses/LICENSE-2.0+--+-- Unless required by applicable law or agreed to in writing, software+-- distributed under the License is distributed on an "AS IS" BASIS,+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+-- See the License for the specific language governing permissions and+-- limitations under the License.++{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeOperators #-}++{-|+Description: Types and functions for working with target tool chains+-}++module Development.Shake.Language.C.ToolChain (+ Linkage(..)+ -- ** Working with toolchains+ , ToolChain+ , ToolChainVariant(..)+ , toolDirectory -- | Directory prefix for tools in a `ToolChain`, e.g. @\/usr\/local\/linux-armv5-eabi\/bin@.+ , toolPrefix -- | Prefix string for tools in a `ToolChain`, e.g. @"linux-armv5-eabi-"@.+ , variant -- | Toolchain variant.+ , compilerCommand -- | Compiler command, usually used in the `compiler` action.+ , Compiler+ , compiler -- | Compiler action for this `ToolChain`.+ , archiverCommand -- | Archiver command, usually used in the `archiver` action.+ , Archiver+ , archiver -- | Archiver action for this `ToolChain`.+ , linkerCommand -- | Linker command, usually used in the `linker` action.+ , Linker+ , LinkResult(..)+ , linker -- | Linker action for this `ToolChain`.+ , defaultBuildFlags -- | Action returning the default `BuildFlags` for this `ToolChain`.++ -- ** Interfacing with other build systems+ , applyEnv+ , toEnv+ -- ** Utilities for toolchain writers+ , defaultToolChain+ , defaultCompiler+ , defaultArchiver+ , defaultLinker+ , toolFromString+ , tool+) where++import Control.Applicative+import Data.Char (toLower)+import Data.List (isInfixOf, isSuffixOf)+import Data.Monoid (mempty)+import Development.Shake+import Development.Shake.FilePath+import Development.Shake.Util (needMakefileDependencies)+import Development.Shake.Language.C.Label+import Development.Shake.Language.C.BuildFlags+import Development.Shake.Language.C.Language (Language(..), languageOf)+import Development.Shake.Language.C.Util++-- | Linkage type, static or shared.+data Linkage = Static | Shared deriving (Enum, Eq, Show)++-- | Link result type+data LinkResult =+ Executable -- ^ Executable+ | SharedLibrary -- ^ Shared (dynamically linked) library+ | LoadableLibrary -- ^ Dynamically loadable library+ deriving (Enum, Eq, Show)++-- | Toolchain variant.+data ToolChainVariant =+ Generic -- ^ Unspecified toolchain+ | GCC -- ^ GNU Compiler Collection (gcc) toolchain+ | LLVM -- ^ Low-Level Virtual Machine (LLVM) toolchain+ deriving (Eq, Show)++-- | `Action` type for producing an object file from a source file.+type Compiler =+ ToolChain -- ^ Toolchain+ -> BuildFlags -- ^ Compiler flags+ -> FilePath -- ^ Input source file+ -> FilePath -- ^ Output object file+ -> Action ()++-- | `Action` type for linking object files into an executable or a library.+type Linker =+ ToolChain -- ^ Toolchain+ -> BuildFlags -- ^ Linker flags+ -> [FilePath] -- ^ Input object files+ -> FilePath -- ^ Output link product+ -> Action ()++-- | `Action` type for archiving object files into a static library.+type Archiver =+ ToolChain -- ^ Toolchain+ -> BuildFlags -- ^ Archiver flags+ -> [FilePath] -- ^ Input object files+ -> FilePath -- ^ Output object archive (static library)+ -> Action ()++data ToolChain = ToolChain {+ _variant :: ToolChainVariant+ , _toolDirectory :: Maybe FilePath+ , _toolPrefix :: String+ , _compilerCommand :: FilePath+ , _compiler :: Compiler+ , _archiverCommand :: FilePath+ , _archiver :: Archiver+ , _linkerCommand :: FilePath+ , _linker :: LinkResult -> Linker+ , _defaultBuildFlags :: Action (BuildFlags -> BuildFlags)+ }++mkLabel ''ToolChain++-- | Default compiler action.+defaultCompiler :: Compiler+defaultCompiler toolChain buildFlags input output = do+ need $ [input]+ let depFile = output <.> "d"+ command_ [] (tool toolChain compilerCommand)+ $ concatMapFlag "-I" (get systemIncludes buildFlags)+ ++ mapFlag "-iquote" (get userIncludes buildFlags)+ ++ defineFlags buildFlags+ ++ get preprocessorFlags buildFlags+ ++ compilerFlagsFor (languageOf input) buildFlags+ ++ ["-MD", "-MF", depFile]+ ++ ["-c", "-o", output, input]+ needMakefileDependencies depFile++-- | Default archiver action.+defaultArchiver :: Archiver+defaultArchiver toolChain buildFlags inputs output = do+ need inputs+ command_ [] (tool toolChain archiverCommand)+ $ get archiverFlags buildFlags+ ++ [output]+ ++ inputs++-- | Default linker action.+defaultLinker :: Linker+defaultLinker toolChain buildFlags inputs output = do+ let localLibs = get localLibraries buildFlags+ buildFlags' = append libraryPath (map takeDirectory localLibs)+ -- Local libraries must be passed to the linker before system libraries they depend on+ . prepend libraries (map (strip.dropExtension.takeFileName) localLibs)+ $ buildFlags+ need $ inputs ++ localLibs+ command_ [] (tool toolChain linkerCommand)+ $ inputs+ ++ get linkerFlags buildFlags'+ ++ concatMapFlag "-L" (get libraryPath buildFlags')+ ++ concatMapFlag "-l" (get libraries buildFlags')+ ++ ["-o", output]+ where+ strip ('l':'i':'b':rest) = rest+ strip x = x++-- | Default toolchain.+--+-- Probably not useful without modification.+defaultToolChain :: ToolChain+defaultToolChain =+ ToolChain {+ _variant = GCC+ , _toolDirectory = Nothing+ , _toolPrefix = ""+ , _compilerCommand = "gcc"+ , _compiler = defaultCompiler+ , _archiverCommand = "ar"+ , _archiver = defaultArchiver+ , _linkerCommand = "gcc"+ , _linker = \linkResult linkerCmd ->+ case linkResult of+ Executable -> defaultLinker linkerCmd+ _ -> defaultLinker linkerCmd . append linkerFlags ["-shared"]+ , _defaultBuildFlags = return id+ }++-- | Given a tool chain command name, construct the command's full path, taking into account the toolchain's `toolPrefix`.+toolFromString ::+ ToolChain -- ^ Toolchain+ -> String -- ^ Command name+ -> FilePath -- ^ Full command path+toolFromString toolChain name =+ let c = _toolPrefix toolChain ++ name+ in maybe c (</> c) (_toolDirectory toolChain)++-- | Construct the full path of a predefined tool given a `ToolChain` accessor.+tool ::+ ToolChain -- ^ Toolchain+ -> (ToolChain :-> String) -- ^ Toolchain accessor+ -> FilePath -- ^ Full command path+tool toolChain getter = toolFromString toolChain (get getter toolChain)++-- | Apply the current environment and return a modified toolchain.+--+-- This function is experimental and subject to change!+--+-- Currently recognised environment variables are+--+-- [@CC@] Path to @C@ compiler.+--+-- [@SHAKE_TOOLCHAIN_VARIANT@] One of the values of 'ToolChainVariant' (case insensitive). If this variable is not present, an attempt is made to determine the toolchain variant from the @C@ compiler command.+applyEnv :: ToolChain -> Action ToolChain+applyEnv toolChain = do+ cc <- getEnv "CC"+ vendor <- getEnv "SHAKE_TOOLCHAIN_VARIANT"+ return $ maybe id (set compilerCommand) cc+ . maybe id (set variant) ((vendor >>= parseVendor) <|> (cc >>= vendorFromCommand))+ $ toolChain+ where+ parseVendor s =+ case map toLower s of+ "gcc" -> Just GCC+ "llvm" -> Just LLVM+ "clang" -> Just LLVM+ _ -> Nothing+ vendorFromCommand path =+ let x = takeFileName path+ in if "gcc" `isInfixOf` x || "g++" `isInfixOf` x+ then Just GCC+ else if "clang" `isInfixOf` x+ then Just LLVM+ else Just Generic++-- | Export a 'ToolChain' definition to a list of environment variable mappings, suitable e.g. for calling third-party configure scripts in cross-compilation mode.+--+-- Needs some fleshing out; currently only works for "standard" binutil toolchains.+toEnv :: ToolChain -> Action [(String,String)]+toEnv tc = do+ flags <- (\f -> f mempty) <$> get defaultBuildFlags tc+ let cflags = concatMapFlag "-I" (map escapeSpaces (get systemIncludes flags))+ ++ concatMapFlag "-I" (map escapeSpaces (get userIncludes flags))+ ++ defineFlags flags+ ++ get preprocessorFlags flags+ ++ compilerFlagsFor (Just C) flags+ cxxflags = cflags ++ compilerFlagsFor (Just Cpp) flags+ ldflags = get linkerFlags flags+ ++ concatMapFlag "-L" (get libraryPath flags)+ ++ concatMapFlag "-l" (get libraries flags)+ c2cxx path = let x = takeFileName path+ in if "gcc" `isSuffixOf` x+ then (++"g++") . reverse . drop 3 . reverse $ path+ else if "clang" `isSuffixOf` x+ then path ++ "++"+ else path+ let cc = tool tc compilerCommand+ cpp = toolFromString tc "cpp"+ cppExists <- doesFileExist cpp+ let cpp' = if cppExists then cpp else cc ++ " -E"+ return $ [+ ("CPP", cpp')+ , ("AR", tool tc archiverCommand)+ , ("NM", toolFromString tc "nm")+ , ("CC", tool tc compilerCommand)+ -- FIXME: Configure toolchain with compiler command per language?+ , ("CXX", c2cxx $ tool tc compilerCommand)+ , ("LD", toolFromString tc "ld")+ , ("RANLIB", toolFromString tc "ranlib")+ , ("CFLAGS", unwords cflags)+ , ("CPPFLAGS", unwords cflags)+ , ("CXXFLAGS", unwords cxxflags)+ , ("LDFLAGS", unwords ldflags)+ ]
+ Development/Shake/Language/C/Util.hs view
@@ -0,0 +1,51 @@+-- Copyright 2012-2014 Samplecount S.L.+--+-- Licensed under the Apache License, Version 2.0 (the "License");+-- you may not use this file except in compliance with the License.+-- You may obtain a copy of the License at+--+-- http://www.apache.org/licenses/LICENSE-2.0+--+-- Unless required by applicable law or agreed to in writing, software+-- distributed under the License is distributed on an "AS IS" BASIS,+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+-- See the License for the specific language governing permissions and+-- limitations under the License.++module Development.Shake.Language.C.Util (+ mapFlag+ , concatMapFlag+ , escapeSpaces+ , words'+) where++import Data.List++mapFlag :: String -> [String] -> [String]+mapFlag f = concatMap (\x -> [f, x])++concatMapFlag :: String -> [String] -> [String]+concatMapFlag f = map (f++)++-- | Escape spaces with '\\' character.+escapeSpaces :: String -> String+escapeSpaces [] = []+escapeSpaces (' ':xs) = '\\' : ' ' : escapeSpaces xs+escapeSpaces ('\\':xs) = '\\' : '\\' : escapeSpaces xs+escapeSpaces (x:xs) = x : escapeSpaces xs++-- | Split a list of space separated strings.+--+-- Spaces can be escaped by '\\'.+words' :: String -> [String]+words' = unescape . words+ where+ escape = "\\"+ escapeLength = length escape+ isEscaped = isSuffixOf escape+ dropEscape = (++" ") . reverse . drop escapeLength . reverse+ unescape [] = []+ unescape [x] = [if isEscaped x then dropEscape x else x]+ unescape (x1:x2:xs)+ | isEscaped x1 = unescape ((dropEscape x1 ++ x2):xs)+ | otherwise = [x1] ++ unescape (x2:xs)
+ LICENSE view
@@ -0,0 +1,202 @@++ Apache License+ Version 2.0, January 2004+ http://www.apache.org/licenses/++ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION++ 1. Definitions.++ "License" shall mean the terms and conditions for use, reproduction,+ and distribution as defined by Sections 1 through 9 of this document.++ "Licensor" shall mean the copyright owner or entity authorized by+ the copyright owner that is granting the License.++ "Legal Entity" shall mean the union of the acting entity and all+ other entities that control, are controlled by, or are under common+ control with that entity. For the purposes of this definition,+ "control" means (i) the power, direct or indirect, to cause the+ direction or management of such entity, whether by contract or+ otherwise, or (ii) ownership of fifty percent (50%) or more of the+ outstanding shares, or (iii) beneficial ownership of such entity.++ "You" (or "Your") shall mean an individual or Legal Entity+ exercising permissions granted by this License.++ "Source" form shall mean the preferred form for making modifications,+ including but not limited to software source code, documentation+ source, and configuration files.++ "Object" form shall mean any form resulting from mechanical+ transformation or translation of a Source form, including but+ not limited to compiled object code, generated documentation,+ and conversions to other media types.++ "Work" shall mean the work of authorship, whether in Source or+ Object form, made available under the License, as indicated by a+ copyright notice that is included in or attached to the work+ (an example is provided in the Appendix below).++ "Derivative Works" shall mean any work, whether in Source or Object+ form, that is based on (or derived from) the Work and for which the+ editorial revisions, annotations, elaborations, or other modifications+ represent, as a whole, an original work of authorship. For the purposes+ of this License, Derivative Works shall not include works that remain+ separable from, or merely link (or bind by name) to the interfaces of,+ the Work and Derivative Works thereof.++ "Contribution" shall mean any work of authorship, including+ the original version of the Work and any modifications or additions+ to that Work or Derivative Works thereof, that is intentionally+ submitted to Licensor for inclusion in the Work by the copyright owner+ or by an individual or Legal Entity authorized to submit on behalf of+ the copyright owner. For the purposes of this definition, "submitted"+ means any form of electronic, verbal, or written communication sent+ to the Licensor or its representatives, including but not limited to+ communication on electronic mailing lists, source code control systems,+ and issue tracking systems that are managed by, or on behalf of, the+ Licensor for the purpose of discussing and improving the Work, but+ excluding communication that is conspicuously marked or otherwise+ designated in writing by the copyright owner as "Not a Contribution."++ "Contributor" shall mean Licensor and any individual or Legal Entity+ on behalf of whom a Contribution has been received by Licensor and+ subsequently incorporated within the Work.++ 2. Grant of Copyright License. Subject to the terms and conditions of+ this License, each Contributor hereby grants to You a perpetual,+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable+ copyright license to reproduce, prepare Derivative Works of,+ publicly display, publicly perform, sublicense, and distribute the+ Work and such Derivative Works in Source or Object form.++ 3. Grant of Patent License. Subject to the terms and conditions of+ this License, each Contributor hereby grants to You a perpetual,+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable+ (except as stated in this section) patent license to make, have made,+ use, offer to sell, sell, import, and otherwise transfer the Work,+ where such license applies only to those patent claims licensable+ by such Contributor that are necessarily infringed by their+ Contribution(s) alone or by combination of their Contribution(s)+ with the Work to which such Contribution(s) was submitted. If You+ institute patent litigation against any entity (including a+ cross-claim or counterclaim in a lawsuit) alleging that the Work+ or a Contribution incorporated within the Work constitutes direct+ or contributory patent infringement, then any patent licenses+ granted to You under this License for that Work shall terminate+ as of the date such litigation is filed.++ 4. Redistribution. You may reproduce and distribute copies of the+ Work or Derivative Works thereof in any medium, with or without+ modifications, and in Source or Object form, provided that You+ meet the following conditions:++ (a) You must give any other recipients of the Work or+ Derivative Works a copy of this License; and++ (b) You must cause any modified files to carry prominent notices+ stating that You changed the files; and++ (c) You must retain, in the Source form of any Derivative Works+ that You distribute, all copyright, patent, trademark, and+ attribution notices from the Source form of the Work,+ excluding those notices that do not pertain to any part of+ the Derivative Works; and++ (d) If the Work includes a "NOTICE" text file as part of its+ distribution, then any Derivative Works that You distribute must+ include a readable copy of the attribution notices contained+ within such NOTICE file, excluding those notices that do not+ pertain to any part of the Derivative Works, in at least one+ of the following places: within a NOTICE text file distributed+ as part of the Derivative Works; within the Source form or+ documentation, if provided along with the Derivative Works; or,+ within a display generated by the Derivative Works, if and+ wherever such third-party notices normally appear. The contents+ of the NOTICE file are for informational purposes only and+ do not modify the License. You may add Your own attribution+ notices within Derivative Works that You distribute, alongside+ or as an addendum to the NOTICE text from the Work, provided+ that such additional attribution notices cannot be construed+ as modifying the License.++ You may add Your own copyright statement to Your modifications and+ may provide additional or different license terms and conditions+ for use, reproduction, or distribution of Your modifications, or+ for any such Derivative Works as a whole, provided Your use,+ reproduction, and distribution of the Work otherwise complies with+ the conditions stated in this License.++ 5. Submission of Contributions. Unless You explicitly state otherwise,+ any Contribution intentionally submitted for inclusion in the Work+ by You to the Licensor shall be under the terms and conditions of+ this License, without any additional terms or conditions.+ Notwithstanding the above, nothing herein shall supersede or modify+ the terms of any separate license agreement you may have executed+ with Licensor regarding such Contributions.++ 6. Trademarks. This License does not grant permission to use the trade+ names, trademarks, service marks, or product names of the Licensor,+ except as required for reasonable and customary use in describing the+ origin of the Work and reproducing the content of the NOTICE file.++ 7. Disclaimer of Warranty. Unless required by applicable law or+ agreed to in writing, Licensor provides the Work (and each+ Contributor provides its Contributions) on an "AS IS" BASIS,+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or+ implied, including, without limitation, any warranties or conditions+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A+ PARTICULAR PURPOSE. You are solely responsible for determining the+ appropriateness of using or redistributing the Work and assume any+ risks associated with Your exercise of permissions under this License.++ 8. Limitation of Liability. In no event and under no legal theory,+ whether in tort (including negligence), contract, or otherwise,+ unless required by applicable law (such as deliberate and grossly+ negligent acts) or agreed to in writing, shall any Contributor be+ liable to You for damages, including any direct, indirect, special,+ incidental, or consequential damages of any character arising as a+ result of this License or out of the use or inability to use the+ Work (including but not limited to damages for loss of goodwill,+ work stoppage, computer failure or malfunction, or any and all+ other commercial damages or losses), even if such Contributor+ has been advised of the possibility of such damages.++ 9. Accepting Warranty or Additional Liability. While redistributing+ the Work or Derivative Works thereof, You may choose to offer,+ and charge a fee for, acceptance of support, warranty, indemnity,+ or other liability obligations and/or rights consistent with this+ License. However, in accepting such obligations, You may act only+ on Your own behalf and on Your sole responsibility, not on behalf+ of any other Contributor, and only if You agree to indemnify,+ defend, and hold each Contributor harmless for any liability+ incurred by, or claims asserted against, such Contributor by reason+ of your accepting any such warranty or additional liability.++ END OF TERMS AND CONDITIONS++ APPENDIX: How to apply the Apache License to your work.++ To apply the Apache License to your work, attach the following+ boilerplate notice, with the fields enclosed by brackets "[]"+ replaced with your own identifying information. (Don't include+ the brackets!) The text should be enclosed in the appropriate+ comment syntax for the file format. We also recommend that a+ file or class name and description of purpose be included on the+ same "printed page" as the copyright notice for easier+ identification within third-party archives.++ Copyright [yyyy] [name of copyright owner]++ Licensed under the Apache License, Version 2.0 (the "License");+ you may not use this file except in compliance with the License.+ You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++ Unless required by applicable law or agreed to in writing, software+ distributed under the License is distributed on an "AS IS" BASIS,+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ See the License for the specific language governing permissions and+ limitations under the License.
+ README.md view
@@ -0,0 +1,38 @@+# shake-language-c++**shake-language-c** is a cross-platform build system based on the [Shake](https://github.com/ndmitchell/shake) Haskell library. The focus is on cross-compilation of *C*, *C++* and *Objective C* source code to various target platforms. Currently supported target platforms are *iOS*, *Android NDK*, *Google Portable Native Client*, *MacOS X*, *Linux* and *Windows* (*MinGW*). Supported host platforms are *MacOS X*, *Linux* and *Windows*.++## Documentation++Please see the [manual](/docs/Manual.md) for beginnings of developer documentation.++## Examples++Here's an *iOS* example that compiles all `.cpp` files in the `src` directory. The resulting static library `libexample.a` can then be used e.g. from an `XCode` project.++ import Control.Applicative+ import Control.Arrow+ import Development.Shake+ import Development.Shake.FilePath+ import Development.Shake.Language.C+ import qualified Development.Shake.Language.C.Target.OSX as OSX++ main :: IO ()+ main = shakeArgs shakeOptions { shakeFiles = "build/" } $ do+ let target = OSX.target OSX.iPhoneOS (Arm Armv7s)+ toolChain = OSX.toolChain+ <$> OSX.getSDKRoot+ <*> (maximum <$> OSX.getPlatformVersions (targetPlatform target))+ <*> pure target++ lib <- staticLibrary toolChain+ ("build" </> toBuildPrefix target </> "libexample.a")+ (return $ + append compilerFlags [(Just Cpp, ["-std=c++11"])]+ >>> append compilerFlags [(Nothing, ["-O3"])]+ >>> append userIncludes ["include"] )+ (getDirectoryFiles "" ["src//*.cpp"])++ want [lib]++A more complex [build script](https://github.com/samplecount/methcla/tree/develop/Shake_Methcla.hs) is used by the [Methcla](http://methc.la) sound engine library. It defines Shake rules for building the library on various platforms and also exports functions for transparently including the library into other build systems. The build script makes extensive use of Shake [configuration files](https://github.com/samplecount/methcla/tree/develop/config).
+ Setup.hs view
@@ -0,0 +1,18 @@+-- Copyright 2012-2013 Samplecount S.L.+--+-- Licensed under the Apache License, Version 2.0 (the "License");+-- you may not use this file except in compliance with the License.+-- You may obtain a copy of the License at+--+-- http://www.apache.org/licenses/LICENSE-2.0+--+-- Unless required by applicable law or agreed to in writing, software+-- distributed under the License is distributed on an "AS IS" BASIS,+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+-- See the License for the specific language governing permissions and+-- limitations under the License.++import Distribution.Simple (defaultMain)++main :: IO ()+main = defaultMain
+ shake-language-c.cabal view
@@ -0,0 +1,66 @@+-- Copyright 2012-2014 Samplecount S.L.+-- +-- Licensed under the Apache License, Version 2.0 (the "License");+-- you may not use this file except in compliance with the License.+-- You may obtain a copy of the License at+-- +-- http://www.apache.org/licenses/LICENSE-2.0+-- +-- Unless required by applicable law or agreed to in writing, software+-- distributed under the License is distributed on an "AS IS" BASIS,+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+-- See the License for the specific language governing permissions and+-- limitations under the License.++Name: shake-language-c+Version: 0.5.0+Synopsis: Utilities for cross-compiling with Shake+Description: This library provides <http://hackage.haskell.org/package/shake Shake> utilities for cross-compiling @C@, @C++@ and @ObjC@ code for various target platforms. Currently supported target platforms are Android, iOS, Linux, MacOS X, Windows\/MinGW and Google Portable Native Client (PNaCl). Supported host platforms are MacOS X, Linux and Windows.+Category: Development+License: Apache-2.0+License-File: LICENSE++Copyright: Copyright (c) 2012-2014 Samplecount S.L.+Homepage: https://github.com/samplecount/shake-language-c+Bug-Reports: https://github.com/samplecount/shake-language-c/issues+Maintainer: stefan@samplecount.com++Cabal-Version: >= 1.6+Build-Type: Simple++Extra-Source-Files:+ Changelog.md+ README.md++Library+ Hs-Source-Dirs: .+ Exposed-Modules:+ Development.Shake.Language.C+ Development.Shake.Language.C.BuildFlags+ Development.Shake.Language.C.Config+ Development.Shake.Language.C.Host+ Development.Shake.Language.C.Label+ Development.Shake.Language.C.PkgConfig+ Development.Shake.Language.C.Rules+ Development.Shake.Language.C.Target.Android+ Development.Shake.Language.C.Target.Linux+ Development.Shake.Language.C.Target.NaCl+ Development.Shake.Language.C.Target.OSX+ Development.Shake.Language.C.Target.Windows+ Other-Modules:+ Development.Shake.Language.C.Language+ Development.Shake.Language.C.Target+ Development.Shake.Language.C.ToolChain+ Development.Shake.Language.C.Util+ Ghc-Options: -Wall+ Build-Depends:+ base >= 4 && < 5+ , fclabels >= 2+ , process+ , shake >= 0.10+ , split+ , unordered-containers++Source-Repository head+ Type: git+ Location: https://github.com/samplecount/shake-language-c.git