diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,11 @@
+Copyright Vanessa McHale (c) 2018
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,4 @@
+# shake-c
+
+Library for building C libraries and binaries using
+[shake](http://hackage.haskell.org/package/shake).
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/shake-c.cabal b/shake-c.cabal
new file mode 100644
--- /dev/null
+++ b/shake-c.cabal
@@ -0,0 +1,49 @@
+cabal-version: 1.18
+name: shake-c
+version: 0.1.0.0
+license: BSD3
+license-file: LICENSE
+copyright: Copyright: (c) 2018 Vanessa McHale
+maintainer: vanessa.mchale@iohk.io
+author: Vanessa McHale
+homepage: https://github.com/vmchale/shake-c#readme
+bug-reports: https://github.com/vmchale/atspkg/issues
+synopsis: Library for building C code with shake
+description:
+    Facilities for building C libraries and binaries, and depending on C source files. Extends [shake](http://hackage.haskell.org/package/shake).
+category: Development, C
+build-type: Simple
+extra-doc-files: README.md
+
+source-repository head
+    type: darcs
+    location: https://hub.darcs.net/vmchale/ats
+
+flag development
+    description:
+        Enable `-Werror`
+    default: False
+    manual: True
+
+library
+    exposed-modules:
+        Development.Shake.C
+    hs-source-dirs: src
+    default-language: Haskell2010
+    other-extensions: DeriveAnyClass DeriveGeneric DerivingStrategies
+                      GeneralizedNewtypeDeriving PatternSynonyms TypeFamilies
+    ghc-options: -Wall
+    build-depends:
+        base >=4.3 && <5,
+        shake >=0.14,
+        cdeps -any
+    
+    if flag(development)
+        ghc-options: -Werror
+    
+    if impl(ghc >=8.0)
+        ghc-options: -Wincomplete-uni-patterns -Wincomplete-record-updates
+                     -Wredundant-constraints -Wnoncanonical-monad-instances
+    
+    if impl(ghc >=8.4)
+        ghc-options: -Wmissing-export-lists
diff --git a/src/Development/Shake/C.hs b/src/Development/Shake/C.hs
new file mode 100644
--- /dev/null
+++ b/src/Development/Shake/C.hs
@@ -0,0 +1,269 @@
+{-# LANGUAGE DeriveAnyClass             #-}
+{-# LANGUAGE DeriveGeneric              #-}
+{-# LANGUAGE DerivingStrategies         #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE PatternSynonyms            #-}
+{-# LANGUAGE TypeFamilies               #-}
+
+-- | This module provides functions for easy C builds of binaries, static
+-- libraries, and dynamic libraries.
+module Development.Shake.C ( -- * Types
+                             CConfig (..)
+                           , CCompiler (ICC, GCC, Clang, GHC, Other, GCCStd, GHCStd, CompCert)
+                           -- * Rules
+                           , staticLibR
+                           , sharedLibR
+                           , objectFileR
+                           , dynLibR
+                           , cBin
+                           , cToLib
+                           -- * Actions
+                           , pkgConfig
+                           , binaryA
+                           , staticLibA
+                           , sharedLibA
+                           , stripA
+                           -- * Oracle helpers
+                           , queryCC
+                           , queryCfg
+                           , examineCC
+                           , examineCfg
+                           -- * Reëxports from "Language.C.Dependency"
+                           , getCDepends
+                           , getAll
+                           -- * Helper functions
+                           , cconfigToArgs
+                           , ccToString
+                           , ccFromString
+                           , host
+                           , isCross
+                           ) where
+
+import           Control.Monad
+import           Data.List                  (isPrefixOf, isSuffixOf)
+import           Development.Shake
+import           Development.Shake.Classes
+import           Development.Shake.FilePath
+import           GHC.Generics               (Generic)
+import           Language.C.Dependency
+import           System.Info
+
+-- | Given a package name or path to a @.pc@ file, output flags for C compiler.
+pkgConfig :: String -> Action [String]
+pkgConfig pkg = do
+    (Stdout o) <- command [] "pkg-config" ["--cflags", pkg]
+    (Stdout o') <- command [] "pkg-config" ["--libs", pkg]
+    pure (words o ++ words o')
+
+mkQualified :: Monoid a => Maybe a -> Maybe a -> a -> a
+mkQualified pre suff = h [f suff, g pre]
+    where g = maybe id mappend
+          f = maybe id (flip mappend)
+          h = foldr fmap id
+
+-- | The target triple of the host machine.
+host :: String
+host = arch ++ withManufacturer os
+    where withManufacturer "darwin" = "-apple-" ++ os
+          withManufacturer _        = "-unknown-" ++ os
+
+-- | Default @gcc@ available
+pattern GCCStd :: CCompiler
+pattern GCCStd = GCC Nothing
+
+-- | Default @ghc@ available
+pattern GHCStd :: CCompiler
+pattern GHCStd = GHC Nothing Nothing
+
+-- | Get the executable name for a 'CCompiler'
+ccToString :: CCompiler -> String
+ccToString ICC            = "icc"
+ccToString Clang          = "clang"
+ccToString (Other s)      = s
+ccToString (GCC pre)      = mkQualified pre Nothing "gcc"
+ccToString (GHC pre suff) = mkQualified pre suff "ghc"
+ccToString CompCert       = "ccomp"
+
+stripToString :: CCompiler -> String
+stripToString (GCC pre)   = mkQualified pre Nothing "strip"
+stripToString (GHC pre _) = mkQualified pre Nothing "strip"
+stripToString _           = "strip"
+
+arToString :: CCompiler -> String
+arToString (GCC pre)   = mkQualified pre Nothing "ar"
+arToString (GHC pre _) = mkQualified pre Nothing "ar"
+arToString _           = "ar"
+
+isCross :: CCompiler -> Bool
+isCross (GCC Just{})   = True
+isCross (GHC Just{} _) = True
+isCross _              = False
+
+-- | Attempt to parse a string as a 'CCompiler', defaulting to @cc@ if parsing
+-- fails.
+ccFromString :: String -> CCompiler
+ccFromString "icc" = ICC
+ccFromString "gcc" = GCC Nothing
+ccFromString "ccomp" = CompCert
+ccFromString "clang" = Clang
+ccFromString "ghc" = GHC Nothing Nothing
+ccFromString s
+    | "gcc" `isSuffixOf` s = GCC (Just (reverse . drop 3 . reverse $ s))
+    | "ghc" `isSuffixOf` s = GHC (Just (reverse . drop 3 . reverse $ s)) Nothing
+    | "ghc" `isPrefixOf` s = GHC Nothing (Just (drop 3 s))
+ccFromString _ = Other "cc"
+
+-- ALSO consider using Haskell -> C -> ICC ??
+-- TODO ICC??
+-- | A data type representing the C compiler to be used.
+data CCompiler = GCC { _prefix :: Maybe String -- ^ Usually the target triple
+                     }
+               | Clang
+               | GHC { _prefix  :: Maybe String -- ^ The target triple
+                     , _postfix :: Maybe String -- ^ The compiler version
+                     }
+               | CompCert
+               | ICC
+               | Other String
+               deriving (Show, Eq, Generic, Typeable, Hashable, Binary, NFData)
+
+mapFlags :: String -> ([String] -> [String])
+mapFlags s = fmap (s ++)
+
+data CConfig = CConfig { includes   :: [String] -- ^ Directories to be included.
+                       , libraries  :: [String] -- ^ Libraries against which to link.
+                       , libDirs    :: [String] -- ^ Directories to find libraries.
+                       , extras     :: [String] -- ^ Extra flags to be passed to the compiler
+                       , staticLink :: Bool -- ^ Whether to link against static versions of libraries
+                       }
+             deriving (Show, Eq, Generic, Typeable, Hashable, Binary, NFData)
+
+newtype CC = CC ()
+    deriving (Show, Eq)
+    deriving newtype (Typeable, Hashable, Binary, NFData)
+
+newtype Cfg = Cfg ()
+    deriving (Show, Eq)
+    deriving newtype (Typeable, Hashable, Binary, NFData)
+
+type instance RuleResult CC = CCompiler
+type instance RuleResult Cfg = CConfig
+
+-- | Set a 'CCompiler' that can be depended on later.
+examineCC :: CCompiler -> Rules ()
+examineCC cc = void $ addOracle $ \(CC _) -> pure cc
+
+examineCfg :: CConfig -> Rules ()
+examineCfg cfg = void $ addOracle $ \(Cfg _) -> pure cfg
+
+-- | Depend on the C compiler being used.
+queryCC :: Action ()
+queryCC = void $ askOracle (CC ())
+
+queryCfg :: Action ()
+queryCfg =void $ askOracle (Cfg ())
+
+-- | Rules for making a static library from C source files. Unlike 'staticLibR',
+-- this also creates rules for creating object files.
+cToLib :: CCompiler
+       -> [FilePath] -- ^ C source files
+       -> FilePattern -- ^ Static libary output
+       -> CConfig
+       -> Rules ()
+cToLib cc sources lib cfg =
+    mconcat [ mconcat objRules
+            , staticLibR cc (g sources) lib cfg
+            ]
+    where objRules = objectFileR cc cfg <$> g sources <*> pure lib
+          g = fmap (-<.> "o")
+
+-- | Rules for generating a binary from C source files. Can have at most have
+-- one @main@ function.
+cBin :: CCompiler
+     -> [FilePath] -- ^ C source files
+     -> FilePattern -- ^ Binary file output
+     -> CConfig
+     -> Rules ()
+cBin cc sources bin cfg = bin %> \out -> binaryA cc sources out cfg
+
+stripA :: CmdResult r
+       => FilePath -- ^ Build product to be stripped
+       -> CCompiler -- ^ C compiler
+       -> Action r
+stripA out cc = command mempty (stripToString cc) [out]
+
+-- | This action builds an executable.
+binaryA :: CmdResult r
+        => CCompiler
+        -> [FilePath] -- ^ Source files
+        -> FilePath -- ^ Executable output
+        -> CConfig
+        -> Action r
+binaryA cc sources out cfg =
+    need sources >>
+    (command [EchoStderr False] (ccToString cc) . (("-o" : out : sources) ++) . cconfigToArgs) cfg
+
+-- | Generate compiler flags for a given configuration.
+cconfigToArgs :: CConfig -> [String]
+cconfigToArgs (CConfig is ls ds es sl) = join [ mapFlags "-I" is, mapFlags "-l" (g sl <$> ls), mapFlags "-L" ds, es ]
+    where g :: Bool -> (String -> String)
+          g False = id
+          g True  = (":lib" ++) . (++ ".a")
+
+-- | These rules build a dynamic library (@.so@ on Linux).
+dynLibR :: CCompiler
+        -> [FilePath] -- ^ C source files
+        -> FilePattern -- ^ Shared object file to be generated.
+        -> CConfig
+        -> Rules ()
+dynLibR cc objFiles shLib cfg =
+    shLib %> \out ->
+        need objFiles >>
+        command [EchoStderr False] (ccToString cc) ("-shared" : "-o" : out : objFiles ++ cconfigToArgs cfg)
+
+-- | These rules build an object file from a C source file.
+objectFileR :: CCompiler
+            -> CConfig
+            -> FilePath -- ^ C source file
+            -> FilePattern -- ^ Object file output
+            -> Rules ()
+objectFileR cc cfg srcFile objFile =
+    objFile %> \out ->
+        need [srcFile] >>
+        command [EchoStderr False] (ccToString cc) (srcFile : "-c" : "-fPIC" : "-o" : out : cconfigToArgs cfg)
+
+sharedLibA :: CmdResult r
+           => CCompiler
+           -> [FilePath] -- ^ Object files to be linked
+           -> FilePattern -- ^ File pattern for shared library outputs
+           -> CConfig
+           -> Action r
+sharedLibA cc objFiles shrLib _ =
+    need objFiles >>
+    command mempty (ccToString cc) ("-shared" : "-o" : shrLib : objFiles)
+
+staticLibA :: CmdResult r
+           => CCompiler
+           -> [FilePath] -- ^ Object files to be linked
+           -> FilePattern -- ^ File pattern for static library outputs
+           -> CConfig
+           -> Action r
+staticLibA ar objFiles stalib _ =
+    need objFiles >>
+    command mempty (arToString ar) ("rcs" : stalib : objFiles)
+
+sharedLibR :: CCompiler
+           -> [FilePath] -- ^ Object files to be linked
+           -> FilePattern -- ^ File pattern for shared library outputs
+           -> CConfig
+           -> Rules ()
+sharedLibR cc objFiles shrLib cfg =
+    shrLib %> \out -> sharedLibA cc objFiles out cfg
+
+staticLibR :: CCompiler
+           -> [FilePath] -- ^ Object files to be linked
+           -> FilePattern -- ^ File pattern for static library outputs
+           -> CConfig
+           -> Rules ()
+staticLibR ar objFiles stalib cfg =
+    stalib %> \out -> staticLibA ar objFiles out cfg
