diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,36 @@
+# Changelog for shake-language-c
+
+## [v0.6.2][]
+
+Bug fix release.
+
+## [v0.6.1][]
+
+Bug fix release.
+
+## [v0.6.0][]
+
+### Added
+
+* Add `Data.Default.Class.Default` instances for some data types; add dependency on package `data-default-class`.
+
+### Changed
+
+* Don't export the entire module `Development.Shake.Language.C.ToolChain` from `Development.Shake.Language.C`; expose `Development.Shake.Language.C.ToolChain` for toolchain writers.
+* Export `Development.Shake.Language.C.Language.Language` from `Development.Shake.Language.C.BuildFlags` instead of `Development.Shake.Language.C`.
+* Export `Development.Shake.Language.C.Rules` from `Development.Shake.Language.C`; hide `Development.Shake.Language.C.Rules` in Cabal file.
+* **Android**: Add `libcxxabi` include directory instead of `gabi++` to include path when compiling with `libcxx`. Fixes `error: no member named '__cxa_demangle' in namespace '__cxxabiv1'`.
+
+### Removed
+
+* Remove `libppapi`, `libppapi_cpp`, `libnacl_io`, `libppapi_simple` from `Development.Shake.Language.C.Target.NaCl`.
+* Remove `Development.Shake.Language.C.Target.archString`.
+
+## [0.5.0][]
+
+First released version.
+
+[v0.6.2]: https://github.com/samplecount/shake-language-c/tree/v0.6.2
+[v0.6.1]: https://github.com/samplecount/shake-language-c/tree/v0.6.1
+[v0.6.0]: https://github.com/samplecount/shake-language-c/tree/v0.6.0
+[v0.5.0]: https://github.com/samplecount/shake-language-c/tree/v0.5.0
diff --git a/Changelog.md b/Changelog.md
deleted file mode 100644
--- a/Changelog.md
+++ /dev/null
diff --git a/Development/Shake/Language/C.hs b/Development/Shake/Language/C.hs
deleted file mode 100644
--- a/Development/Shake/Language/C.hs
+++ /dev/null
@@ -1,70 +0,0 @@
--- 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"
--}
diff --git a/Development/Shake/Language/C/BuildFlags.hs b/Development/Shake/Language/C/BuildFlags.hs
deleted file mode 100644
--- a/Development/Shake/Language/C/BuildFlags.hs
+++ /dev/null
@@ -1,195 +0,0 @@
--- 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 (>>>)
diff --git a/Development/Shake/Language/C/Config.hs b/Development/Shake/Language/C/Config.hs
deleted file mode 100644
--- a/Development/Shake/Language/C/Config.hs
+++ /dev/null
@@ -1,64 +0,0 @@
-{-# 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
diff --git a/Development/Shake/Language/C/Host.hs b/Development/Shake/Language/C/Host.hs
deleted file mode 100644
--- a/Development/Shake/Language/C/Host.hs
+++ /dev/null
@@ -1,86 +0,0 @@
--- 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 ++ ")"
diff --git a/Development/Shake/Language/C/Label.hs b/Development/Shake/Language/C/Label.hs
deleted file mode 100644
--- a/Development/Shake/Language/C/Label.hs
+++ /dev/null
@@ -1,46 +0,0 @@
--- 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`)
diff --git a/Development/Shake/Language/C/Language.hs b/Development/Shake/Language/C/Language.hs
deleted file mode 100644
--- a/Development/Shake/Language/C/Language.hs
+++ /dev/null
@@ -1,47 +0,0 @@
--- 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
diff --git a/Development/Shake/Language/C/PkgConfig.hs b/Development/Shake/Language/C/PkgConfig.hs
deleted file mode 100644
--- a/Development/Shake/Language/C/PkgConfig.hs
+++ /dev/null
@@ -1,132 +0,0 @@
--- 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
diff --git a/Development/Shake/Language/C/Rules.hs b/Development/Shake/Language/C/Rules.hs
deleted file mode 100644
--- a/Development/Shake/Language/C/Rules.hs
+++ /dev/null
@@ -1,154 +0,0 @@
--- 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
diff --git a/Development/Shake/Language/C/Target.hs b/Development/Shake/Language/C/Target.hs
deleted file mode 100644
--- a/Development/Shake/Language/C/Target.hs
+++ /dev/null
@@ -1,104 +0,0 @@
--- 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)
diff --git a/Development/Shake/Language/C/Target/Android.hs b/Development/Shake/Language/C/Target/Android.hs
deleted file mode 100644
--- a/Development/Shake/Language/C/Target/Android.hs
+++ /dev/null
@@ -1,202 +0,0 @@
--- 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"
diff --git a/Development/Shake/Language/C/Target/Linux.hs b/Development/Shake/Language/C/Target/Linux.hs
deleted file mode 100644
--- a/Development/Shake/Language/C/Target/Linux.hs
+++ /dev/null
@@ -1,80 +0,0 @@
--- 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)
diff --git a/Development/Shake/Language/C/Target/NaCl.hs b/Development/Shake/Language/C/Target/NaCl.hs
deleted file mode 100644
--- a/Development/Shake/Language/C/Target/NaCl.hs
+++ /dev/null
@@ -1,193 +0,0 @@
--- 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 ++ "\""
-         , "    }"
-         ]
diff --git a/Development/Shake/Language/C/Target/OSX.hs b/Development/Shake/Language/C/Target/OSX.hs
deleted file mode 100644
--- a/Development/Shake/Language/C/Target/OSX.hs
+++ /dev/null
@@ -1,190 +0,0 @@
--- 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
diff --git a/Development/Shake/Language/C/Target/Windows.hs b/Development/Shake/Language/C/Target/Windows.hs
deleted file mode 100644
--- a/Development/Shake/Language/C/Target/Windows.hs
+++ /dev/null
@@ -1,82 +0,0 @@
--- 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)
diff --git a/Development/Shake/Language/C/ToolChain.hs b/Development/Shake/Language/C/ToolChain.hs
deleted file mode 100644
--- a/Development/Shake/Language/C/ToolChain.hs
+++ /dev/null
@@ -1,271 +0,0 @@
--- 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)
-    ]
diff --git a/Development/Shake/Language/C/Util.hs b/Development/Shake/Language/C/Util.hs
deleted file mode 100644
--- a/Development/Shake/Language/C/Util.hs
+++ /dev/null
@@ -1,51 +0,0 @@
--- 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)
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,10 +1,12 @@
 # shake-language-c
 
+[![Build Status](https://travis-ci.org/samplecount/shake-language-c.svg?branch=develop)](https://travis-ci.org/samplecount/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.
+Please see the [package documentation](http://hackage.haskell.org/package/shake-language-c). Feel free to open an [issue](https://github.com/samplecount/shake-language-c/issues) or send a pull request if there's anything missing that you want to see covered.
 
 ## Examples
 
diff --git a/shake-language-c.cabal b/shake-language-c.cabal
--- a/shake-language-c.cabal
+++ b/shake-language-c.cabal
@@ -13,7 +13,7 @@
 -- limitations under the License.
 
 Name:         shake-language-c
-Version:      0.5.0
+Version:      0.6.2
 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
@@ -25,15 +25,15 @@
 Bug-Reports:  https://github.com/samplecount/shake-language-c/issues
 Maintainer:   stefan@samplecount.com
 
-Cabal-Version: >= 1.6
+Cabal-Version: >= 1.8
 Build-Type: Simple
 
 Extra-Source-Files:
-  Changelog.md
+  CHANGELOG.md
   README.md
 
 Library
-  Hs-Source-Dirs: .
+  Hs-Source-Dirs: src
   Exposed-Modules:
     Development.Shake.Language.C
     Development.Shake.Language.C.BuildFlags
@@ -41,25 +41,43 @@
     Development.Shake.Language.C.Host
     Development.Shake.Language.C.Label
     Development.Shake.Language.C.PkgConfig
-    Development.Shake.Language.C.Rules
+    Development.Shake.Language.C.ToolChain
     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.Host.Linux
+    Development.Shake.Language.C.Host.OSX
+    Development.Shake.Language.C.Host.Windows
     Development.Shake.Language.C.Language
+    Development.Shake.Language.C.Rules
     Development.Shake.Language.C.Target
-    Development.Shake.Language.C.ToolChain
     Development.Shake.Language.C.Util
   Ghc-Options: -Wall
   Build-Depends:
       base >= 4 && < 5
+    , data-default-class
     , fclabels >= 2
     , process
     , shake >= 0.10
     , split
     , unordered-containers
+
+test-suite doctests
+  type:           exitcode-stdio-1.0
+  hs-source-dirs: tests
+  main-is:        doctests.hs
+  ghc-options:    -threaded
+  build-depends:  base, doctest >= 0.8, shake >= 0.10, shake-language-c
+
+test-suite spectests
+  type:           exitcode-stdio-1.0
+  hs-source-dirs: tests
+  main-is:        spectests.hs
+  ghc-options:    -threaded
+  build-depends:  base, directory, hspec, shake >= 0.10, shake-language-c
 
 Source-Repository head
   Type:     git
diff --git a/src/Development/Shake/Language/C.hs b/src/Development/Shake/Language/C.hs
new file mode 100644
--- /dev/null
+++ b/src/Development/Shake/Language/C.hs
@@ -0,0 +1,49 @@
+-- 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 (
+  -- * Build targets
+  -- $targets
+    module Development.Shake.Language.C.Target
+  -- * High-level build rules
+  , Linkage(..)
+  , module Development.Shake.Language.C.BuildFlags
+  , module Development.Shake.Language.C.Rules
+  -- * Toolchain types and utilities
+  , ToolChain
+  , ToolChainVariant(..)
+  , applyEnv
+  , toEnv
+) where
+
+import Development.Shake.Language.C.BuildFlags
+import Development.Shake.Language.C.Rules
+import Development.Shake.Language.C.Target
+import Development.Shake.Language.C.ToolChain
+
+{- $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"
+-}
diff --git a/src/Development/Shake/Language/C/BuildFlags.hs b/src/Development/Shake/Language/C/BuildFlags.hs
new file mode 100644
--- /dev/null
+++ b/src/Development/Shake/Language/C/BuildFlags.hs
@@ -0,0 +1,218 @@
+-- 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 a
+bias towards binutils\/gcc/clang toolchains.
+-}
+
+module Development.Shake.Language.C.BuildFlags (
+  -- * Source Language
+    Language(..)
+  -- * Build flags
+  , 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.
+  -- ** Utilities for toolchain writers
+  , defineFlags
+  , compilerFlagsFor
+  -- ** Working with config files
+  , fromConfig
+  -- * Utilities
+  , (>>>=)
+  , append
+  , prepend
+) where
+
+import           Control.Category ((>>>))
+import           Control.Monad
+import           Data.Char (isSpace)
+import           Data.Default.Class (Default(..))
+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 of `Default`, you can create a default record with
+`def`. `BuildFlags` is also an instance `Monoid`, you can create an empty record with
+`mempty` and append flags with `mappend`. `def` and `mempty` are synonyms:
+
+>>> (def :: BuildFlags) == (mempty :: BuildFlags)
+True
+
+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
+    $ append systemIncludes ["path1"] . append systemIncludes ["path2"]
+    $ mempty
+:}
+["path2","path1"]
+
+>>> :{
+  get systemIncludes
+    $ 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 Default BuildFlags where
+  def = defaultBuildFlags
+
+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 (>>>)
diff --git a/src/Development/Shake/Language/C/Config.hs b/src/Development/Shake/Language/C/Config.hs
new file mode 100644
--- /dev/null
+++ b/src/Development/Shake/Language/C/Config.hs
@@ -0,0 +1,65 @@
+{-# 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.
+--
+-- >>> parsePaths "/a /a/b /a/b/c\\ d"
+-- ["/a","/a/b","/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
diff --git a/src/Development/Shake/Language/C/Host.hs b/src/Development/Shake/Language/C/Host.hs
new file mode 100644
--- /dev/null
+++ b/src/Development/Shake/Language/C/Host.hs
@@ -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.Host.Linux as Linux
+import qualified Development.Shake.Language.C.Host.OSX as OSX
+import qualified Development.Shake.Language.C.Host.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.getHostToolChain
+    OSX     -> OSX.getHostToolChain
+    Windows -> Windows.getHostToolChain
+    -- _ -> error $ "No default toolchain for this operating system (" ++ show os ++ ")"
diff --git a/src/Development/Shake/Language/C/Host/Linux.hs b/src/Development/Shake/Language/C/Host/Linux.hs
new file mode 100644
--- /dev/null
+++ b/src/Development/Shake/Language/C/Host/Linux.hs
@@ -0,0 +1,39 @@
+-- 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.Host.Linux (
+  getHostToolChain
+) where
+
+import Development.Shake
+import Development.Shake.Language.C.Target
+import Development.Shake.Language.C.Target.Linux
+import Development.Shake.Language.C.ToolChain
+import System.Process (readProcess)
+
+-- | Get host architecture.
+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
+
+-- | Get host toolchain.
+getHostToolChain :: IO (Target, Action ToolChain)
+getHostToolChain = do
+    t <- fmap target getHostArch
+    return (t, return $ toolChain GCC)
diff --git a/src/Development/Shake/Language/C/Host/OSX.hs b/src/Development/Shake/Language/C/Host/OSX.hs
new file mode 100644
--- /dev/null
+++ b/src/Development/Shake/Language/C/Host/OSX.hs
@@ -0,0 +1,33 @@
+-- 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.Host.OSX (
+  getHostToolChain
+) where
+
+import Control.Applicative hiding ((*>))
+import Development.Shake
+import Development.Shake.Language.C.Target
+import Development.Shake.Language.C.Target.OSX
+import Development.Shake.Language.C.ToolChain
+
+-- | Get host toolchain.
+getHostToolChain :: IO (Target, Action ToolChain)
+getHostToolChain = do
+    let defaultTarget = target macOSX (X86 X86_64)
+    return ( defaultTarget
+           , toolChain
+               <$> getSDKRoot
+               <*> (maximum <$> getPlatformVersions (targetPlatform defaultTarget))
+               <*> pure defaultTarget )
diff --git a/src/Development/Shake/Language/C/Host/Windows.hs b/src/Development/Shake/Language/C/Host/Windows.hs
new file mode 100644
--- /dev/null
+++ b/src/Development/Shake/Language/C/Host/Windows.hs
@@ -0,0 +1,38 @@
+-- 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.Host.Windows (
+  getHostToolChain
+) where
+
+import           Development.Shake
+import           Development.Shake.Language.C.Target
+import           Development.Shake.Language.C.Target.Linux
+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
+
+getHostToolChain :: IO (Target, Action ToolChain)
+getHostToolChain = do
+    t <- fmap target getHostArch
+    return (t, return $ toolChain Generic)
diff --git a/src/Development/Shake/Language/C/Label.hs b/src/Development/Shake/Language/C/Label.hs
new file mode 100644
--- /dev/null
+++ b/src/Development/Shake/Language/C/Label.hs
@@ -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`)
diff --git a/src/Development/Shake/Language/C/Language.hs b/src/Development/Shake/Language/C/Language.hs
new file mode 100644
--- /dev/null
+++ b/src/Development/Shake/Language/C/Language.hs
@@ -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
diff --git a/src/Development/Shake/Language/C/PkgConfig.hs b/src/Development/Shake/Language/C/PkgConfig.hs
new file mode 100644
--- /dev/null
+++ b/src/Development/Shake/Language/C/PkgConfig.hs
@@ -0,0 +1,125 @@
+-- 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
+  , pkgConfig
+  , fromConfig
+) where
+
+import Control.Applicative
+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')
+
+-- ====================================================================
+-- 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 @pkg-config@ options.
+--
+-- This function is an alias for `def`.
+defaultOptions :: Options
+defaultOptions = Options{
+    searchPath = Nothing
+  , static = False
+  }
+
+instance Default Options where
+  def = defaultOptions
+
+-- | 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.
+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) )
+
+-- | 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
+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
diff --git a/src/Development/Shake/Language/C/Rules.hs b/src/Development/Shake/Language/C/Rules.hs
new file mode 100644
--- /dev/null
+++ b/src/Development/Shake/Language/C/Rules.hs
@@ -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
diff --git a/src/Development/Shake/Language/C/Target.hs b/src/Development/Shake/Language/C/Target.hs
new file mode 100644
--- /dev/null
+++ b/src/Development/Shake/Language/C/Target.hs
@@ -0,0 +1,114 @@
+-- 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(..)
+  , Target(..)
+  , ToBuildPrefix(..)
+) where
+
+import           Data.Char (toLower)
+import           Development.Shake.FilePath
+
+-- $setup
+-- >>> :load Development.Shake.Language.C.Target.OSX
+-- >>> :module -Development.Shake.Language.C.Target.OSX
+-- >>> import Development.Shake.Language.C.Target
+
+-- | 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. Use `toBuildPrefix` to convert a platform to a file path prefix that can be used in Shake rules.
+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.
+--
+-- Use `toBuildPrefix` to convert an architecture to a short, more or less canonical file path prefix that can be used in Shake rules.
+data Arch =
+    X86 X86Version  -- ^ Intel @x86@ architecture
+  | Arm ArmVersion  -- ^ Arm architecture
+  | LLVM_IR         -- ^ LLVM intermediate representation, used by `Pepper` (PNaCl)
+  deriving (Eq, Show)
+
+-- | Compilation target triple consisting of operating system, platform and architecture.
+--
+-- Use `toBuildPrefix` to convert a target to a file path prefix that can be used in Shake rules. The prefix is of the form
+--
+-- > <platform>/<architecture>
+--
+-- For example:
+--
+-- >>> import qualified Development.Shake.Language.C.Target.OSX as OSX
+-- >>> toBuildPrefix $ OSX.target OSX.iPhoneOS (Arm Armv7)
+-- "iphoneos/armv7"
+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 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"
+
+instance ToBuildPrefix Target where
+   toBuildPrefix target =
+          toBuildPrefix (targetPlatform target)
+      </> toBuildPrefix (targetArch target)
diff --git a/src/Development/Shake/Language/C/Target/Android.hs b/src/Development/Shake/Language/C/Target/Android.hs
new file mode 100644
--- /dev/null
+++ b/src/Development/Shake/Language/C/Target/Android.hs
@@ -0,0 +1,203 @@
+-- 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.Category ((>>>))
+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.ToolChain
+import qualified System.Info as System
+
+unsupportedArch :: Arch -> a
+unsupportedArch arch = error $ "Unsupported Android target architecture " ++ show 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
+                          X86 I386   -> "i386"
+                          X86 I686   -> "i686"
+                          X86 X86_64 -> "x86_64"
+                          Arm Armv5  -> "armv5te"
+                          Arm Armv6  -> "armv5te"
+                          Arm Armv7  -> "armv7-a"
+                          _ -> unsupportedArch 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 [ stl </> "llvm-libc++" </> "libcxx" </> "include"
+                          -- NOTE: libcxx needs to be first in include path!
+                          , stl </> "llvm-libc++abi" </> "libcxxabi" </> "include"
+                          , ndk </> "sources" </> "android" </> "support" </> "include" ]
+  . append compilerFlags [(Just Cpp, ["-stdlib=libc++"])]
+  . append libraryPath [stl </> "llvm-libc++" </> "libs" </> abi]
+  . prepend libraries [lib]
+    where stl = ndk </> "sources" </> "cxx-stl"
+          abi = abiString (targetArch t)
+          lib = case linkage of
+                  Static -> "c++_static"
+                  Shared -> "c++_shared"
diff --git a/src/Development/Shake/Language/C/Target/Linux.hs b/src/Development/Shake/Language/C/Target/Linux.hs
new file mode 100644
--- /dev/null
+++ b/src/Development/Shake/Language/C/Target/Linux.hs
@@ -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.
+
+{-|
+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 (
+    target
+  , toolChain
+) 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
+
+-- | Build target given an architecture.
+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
diff --git a/src/Development/Shake/Language/C/Target/NaCl.hs b/src/Development/Shake/Language/C/Target/NaCl.hs
new file mode 100644
--- /dev/null
+++ b/src/Development/Shake/Language/C/Target/NaCl.hs
@@ -0,0 +1,173 @@
+-- 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
+  , 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]
+
+-- | 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 ++ "\""
+         , "    }"
+         ]
diff --git a/src/Development/Shake/Language/C/Target/OSX.hs b/src/Development/Shake/Language/C/Target/OSX.hs
new file mode 100644
--- /dev/null
+++ b/src/Development/Shake/Language/C/Target/OSX.hs
@@ -0,0 +1,185 @@
+-- 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: 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
+  , 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)
+
+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"
+    _          -> error $ "Unsupported OSX target architecture " ++ show arch
+
+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
+
+-- | 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
diff --git a/src/Development/Shake/Language/C/Target/Windows.hs b/src/Development/Shake/Language/C/Target/Windows.hs
new file mode 100644
--- /dev/null
+++ b/src/Development/Shake/Language/C/Target/Windows.hs
@@ -0,0 +1,67 @@
+-- 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 (
+    target
+  , toolChain
+) 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
+
+-- | Build target given an architecture.
+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
diff --git a/src/Development/Shake/Language/C/ToolChain.hs b/src/Development/Shake/Language/C/ToolChain.hs
new file mode 100644
--- /dev/null
+++ b/src/Development/Shake/Language/C/ToolChain.hs
@@ -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 (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)
+    ]
diff --git a/src/Development/Shake/Language/C/Util.hs b/src/Development/Shake/Language/C/Util.hs
new file mode 100644
--- /dev/null
+++ b/src/Development/Shake/Language/C/Util.hs
@@ -0,0 +1,65 @@
+-- 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 contains spaces"
+-- "string\\ contains\\ spaces"
+--
+-- >>> escapeSpaces " leading and trailing spaces "
+-- "\\ leading\\ and\\ trailing\\ spaces\\ "
+--
+-- >>> escapeSpaces "noSpaces"
+-- "noSpaces"
+--
+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' "word and word\\ with\\ spaces"
+-- ["word","and","word with spaces"]
+--
+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)
diff --git a/tests/doctests.hs b/tests/doctests.hs
new file mode 100644
--- /dev/null
+++ b/tests/doctests.hs
@@ -0,0 +1,23 @@
+-- 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.
+
+import Test.DocTest
+
+main = doctest [
+    "-isrc"
+  , "src/Development/Shake/Language/C/BuildFlags.hs"
+  , "src/Development/Shake/Language/C/Config.hs"
+  , "src/Development/Shake/Language/C/Target.hs"
+  , "src/Development/Shake/Language/C/Util.hs"
+  ]
diff --git a/tests/spectests.hs b/tests/spectests.hs
new file mode 100644
--- /dev/null
+++ b/tests/spectests.hs
@@ -0,0 +1,90 @@
+module Main where
+
+import Control.Applicative hiding ((*>))
+import Control.Monad
+import Data.IORef
+import Development.Shake
+import Development.Shake.FilePath
+import Development.Shake.Language.C
+import qualified Development.Shake.Language.C.Host as Host
+import qualified System.Directory as Dir
+import Test.Hspec
+
+buildDir :: FilePath
+buildDir = "tests/build"
+
+withShake :: String
+          -> (FilePath
+              -> (FilePath -> FilePath)
+              -> (FilePath -> FilePath)
+              -> Rules FilePath)
+          -> IO String
+withShake name mkRules = do
+  ref <- newIORef undefined
+  shake shakeOptions { shakeFiles = addTrailingPathSeparator buildDir } $ do
+    output <- mkRules name
+                      (\x -> buildDir </> name </> "input" </> x)
+                      (\x -> buildDir </> name </> "output" </> x)
+    action $ do
+      need [output]
+      liftIO $ writeIORef ref output
+  readFile =<< readIORef ref
+
+shouldBeBuiltBy :: String
+               -> (FilePath
+               -> (FilePath -> FilePath)
+               -> (FilePath -> FilePath)
+               -> Rules FilePath)
+               -> Expectation
+shouldBeBuiltBy name mkRules =
+  withShake name mkRules `shouldReturn` unlines [name]
+
+cstring :: String -> String
+cstring = show
+
+main :: IO ()
+main = hspec $ do
+  runIO $ do
+    b <- Dir.doesDirectoryExist buildDir
+    when b $ Dir.removeDirectoryRecursive buildDir
+  describe "Host toolchain" $ do
+    it "compiles a C file to an executable" $ do
+      "host_toolchain_compile_c" `shouldBeBuiltBy` \name mkInput mkOutput -> do
+        let (_, toolChain) = Host.defaultToolChain
+            input = mkInput "source.c"
+            outputGen = mkOutput $ "result" <.> exe
+            output = mkOutput "result.txt"
+        input *> \path -> do
+          writeFileLines path [
+              "#include <stdio.h>"
+            , "int main(int argc, char** argv)"
+            , "{"
+            , "    printf(\"%s\\n\", " ++ cstring name ++ ");"
+            , "    return 0;"
+            , "}"
+            ]
+        _ <- executable toolChain outputGen (pure id) (pure [input])
+        output *> \path -> do
+          need [outputGen]
+          cmd Shell (outputGen ++ " > " ++ path)
+        return output
+    it "compiles a C++ file to an executable" $ do
+      "host_toolchain_compile_cpp" `shouldBeBuiltBy` \name mkInput mkOutput -> do
+        let (_, toolChain) = Host.defaultToolChain
+            input = mkInput "source.cpp"
+            outputGen = mkOutput $ "result" <.> exe
+            output = mkOutput "result.txt"
+        input *> \path -> do
+          writeFileLines path [
+              "#include <iostream>"
+            , "int main(int argc, char** argv)"
+            , "{"
+            , "    std::cout << " ++ cstring name ++ " << std::endl;"
+            , "    return 0;"
+            , "}"
+            ]
+        _ <- executable toolChain outputGen (pure id) (pure [input])
+        output *> \path -> do
+          need [outputGen]
+          cmd Shell (outputGen ++ " > " ++ path)
+        return output
