diff --git a/app/Main.hs b/app/Main.hs
--- a/app/Main.hs
+++ b/app/Main.hs
@@ -4,19 +4,20 @@
             ) where
 
 import           Control.Composition
-import           Control.Lens               hiding (List, argument)
+import           Control.Concurrent.ParallelIO.Global
+import           Control.Lens                         hiding (List, argument)
 import           Control.Monad
-import           Data.Bool                  (bool)
-import           Data.Maybe                 (fromMaybe)
-import           Data.Semigroup             (Semigroup (..))
-import qualified Data.Text.Lazy             as TL
-import           Data.Version               hiding (Version (..))
+import           Data.Bool                            (bool)
+import           Data.Maybe                           (fromMaybe)
+import           Data.Semigroup                       (Semigroup (..))
+import qualified Data.Text.Lazy                       as TL
+import           Data.Version                         hiding (Version (..))
 import           Development.Shake.ATS
 import           Development.Shake.FilePath
 import           Language.ATS.Package
 import           Options.Applicative
 import           System.Directory
-import           System.IO.Temp             (withSystemTempDirectory)
+import           System.IO.Temp                       (withSystemTempDirectory)
 
 -- TODO command to list available packages.
 wrapper :: ParserInfo Command
@@ -187,19 +188,20 @@
 
 fetchPkg :: String -> IO ()
 fetchPkg pkg = withSystemTempDirectory "atspkg" $ \p -> do
-    let (lib, dirName, url') = (mempty, p, pkg) & each %~ TL.pack
-    buildHelper True (ATSDependency lib dirName url' undefined undefined mempty mempty mempty mempty)
+    let (dirName, url') = (p, pkg) & each %~ TL.pack
+    buildHelper True (ATSDependency mempty dirName url' undefined undefined mempty mempty mempty mempty)
     ps <- getSubdirs p
     pkgDir <- fromMaybe p <$> findFile (p:ps) "atspkg.dhall"
-    let a = withCurrentDirectory (takeDirectory pkgDir) (mkPkg False False False mempty ["install"] Nothing 0)
-    bool (buildAll Nothing (Just pkgDir) >> a) a =<< check (Just pkgDir)
+    let setup = [buildAll Nothing (Just pkgDir)]
+    withCurrentDirectory (takeDirectory pkgDir) (mkPkg False False False setup ["install"] Nothing 0)
+    stopGlobalPool
 
 main :: IO ()
 main = execParser wrapper >>= run
 
 runHelper :: Bool -> Bool -> Bool -> [String] -> Maybe String -> Int -> IO ()
 runHelper rba lint tim rs tgt v = g . bool x y =<< check Nothing
-    where g xs = mkPkg rba lint tim xs rs tgt v
+    where g xs = mkPkg rba lint tim xs rs tgt v >> stopGlobalPool
           y = mempty
           x = [buildAll tgt Nothing]
 
diff --git a/ats-pkg.cabal b/ats-pkg.cabal
--- a/ats-pkg.cabal
+++ b/ats-pkg.cabal
@@ -1,6 +1,6 @@
 cabal-version: 1.18
 name: ats-pkg
-version: 2.10.0.11
+version: 2.10.0.17
 license: BSD3
 license-file: LICENSE
 copyright: Copyright: (c) 2018 Vanessa McHale
@@ -78,7 +78,7 @@
     ghc-options: -Wall -Wincomplete-uni-patterns
                  -Wincomplete-record-updates
     build-depends:
-        base >=4.11 && <5,
+        base >=4.9 && <5,
         http-client -any,
         bytestring -any,
         file-embed -any,
@@ -97,7 +97,7 @@
         parallel-io -any,
         unix -any,
         mtl -any,
-        dhall >=1.11.0 && <=1.12.0,
+        dhall >=1.11.0 && <=1.13.0,
         ansi-wl-pprint -any,
         shake-ats >=1.8.0.0,
         shake-ext >=2.6.0.0,
@@ -109,7 +109,7 @@
         dependency -any,
         filemanip -any
     
-    if flag(development)
+    if flag(development) && impl(ghc <8.4)
         ghc-options: -Werror
 
 executable atspkg
@@ -118,7 +118,7 @@
     other-modules:
         Paths_ats_pkg
     default-language: Haskell2010
-    ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall
+    ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall -with-rtsopts=-I0
                  -Wincomplete-uni-patterns -Wincomplete-record-updates
     
     if flag(eventlog)
@@ -138,6 +138,7 @@
             directory -any,
             composition-prelude -any,
             text -any,
+            parallel-io -any,
             shake -any
     
     if flag(no-executable)
diff --git a/man/atspkg.1 b/man/atspkg.1
--- a/man/atspkg.1
+++ b/man/atspkg.1
@@ -1,4 +1,4 @@
-.\" Automatically generated by Pandoc 2.1.3
+.\" Automatically generated by Pandoc 2.2
 .\"
 .TH "atspkg (1)" "" "" "" ""
 .hy
diff --git a/src/Distribution/ATS/Build.hs b/src/Distribution/ATS/Build.hs
--- a/src/Distribution/ATS/Build.hs
+++ b/src/Distribution/ATS/Build.hs
@@ -4,6 +4,7 @@
                               ) where
 
 -- TODO use confHook to set extra-libraries and extra-lib-dirs ourselves?
+import           Control.Concurrent.ParallelIO.Global
 import           Distribution.PackageDescription
 import           Distribution.Simple
 import           Distribution.Simple.LocalBuildInfo
@@ -12,7 +13,9 @@
 
 -- | Use this in place of 'defaultMain' for a simple build.
 atsPolyglotBuild :: IO ()
-atsPolyglotBuild = defaultMainWithHooks cabalHooks
+atsPolyglotBuild =
+    defaultMainWithHooks cabalHooks >>
+    stopGlobalPool
 
 configureCabal :: IO LocalBuildInfo -> IO LocalBuildInfo
 configureCabal = (<*>) $ do
diff --git a/src/Language/ATS/Package.hs b/src/Language/ATS/Package.hs
--- a/src/Language/ATS/Package.hs
+++ b/src/Language/ATS/Package.hs
@@ -31,6 +31,7 @@
                             -- * Generic Packaging
                             , Package (..)
                             , InstallDirs (..)
+                            , CacheValid
                             -- * Typeclasses
                             , GenericPackage (..)
                             -- * Lenses
diff --git a/src/Language/ATS/Package/Build.hs b/src/Language/ATS/Package/Build.hs
--- a/src/Language/ATS/Package/Build.hs
+++ b/src/Language/ATS/Package/Build.hs
@@ -10,12 +10,11 @@
                                   , check
                                   ) where
 
-import           Control.Concurrent.ParallelIO.Global
-import qualified Data.ByteString                      as BS
-import qualified Data.ByteString.Lazy                 as BSL
-import           Data.List                            (intercalate)
+import qualified Data.ByteString                 as BS
+import qualified Data.ByteString.Lazy            as BSL
+import           Data.List                       (intercalate)
 import           Development.Shake.ATS
-import           Development.Shake.C                  (ccFromString)
+import           Development.Shake.C             (ccFromString)
 import           Development.Shake.Check
 import           Development.Shake.Clean
 import           Development.Shake.Man
@@ -23,7 +22,7 @@
 import           Language.ATS.Package.Build.C
 import           Language.ATS.Package.Compiler
 import           Language.ATS.Package.Config
-import           Language.ATS.Package.Debian          hiding (libraries, target)
+import           Language.ATS.Package.Debian     hiding (libraries, target)
 import           Language.ATS.Package.Dependency
 import           Language.ATS.Package.Type
 import           Quaalude
@@ -67,7 +66,9 @@
     removeFilesAfter ".atspkg" ["//*"]
     removeFilesAfter "ats-deps" ["//*"]
 
-mkInstall :: Maybe String -> Rules ()
+-- TODO take more arguments, in particular, include + library dirs
+mkInstall :: Maybe String -- ^ Optional target triple
+          -> Rules ()
 mkInstall tgt =
     "install" ~> do
         config <- getConfig Nothing
@@ -107,15 +108,14 @@
         Just _ -> bool (pure ()) manpages b
         _      -> pure ()
 
-cacheConfiguration :: Text -> IO Pkg
-cacheConfiguration = input auto
-
+-- FIXME this doesn't rebuild when it should; it should rebuild when
+-- @atspkg.dhall@ changes.
 getConfig :: MonadIO m => Maybe FilePath -> m Pkg
 getConfig dir' = liftIO $ do
     d <- fromMaybe <$> fmap (<> "/atspkg.dhall") getCurrentDirectory <*> pure dir'
     b <- not <$> doesFileExist ".atspkg/config"
     if b
-        then cacheConfiguration (pack d)
+        then input auto (pack d)
         else fmap (decode . BSL.fromStrict) . BS.readFile $ ".atspkg/config"
 
 manTarget :: Text -> FilePath
@@ -190,7 +190,6 @@
             , mkClean
             , pkgToAction setup rs tgt cfg
             ]
-    stopGlobalPool
 
 mkConfig :: Rules ()
 mkConfig =
@@ -243,8 +242,9 @@
     pure $ h ++ "lib/ats2-postiats-" ++ show libV
 
 -- | This is the @$PATSHOMELOCS@ variable to be passed to the shell.
-patsHomeLocsAtsPkg :: Int -> String
-patsHomeLocsAtsPkg n = intercalate ":" $ (<> ".atspkg/contrib") . ("./" <>) <$> g
+patsHomeLocsAtsPkg :: Int -- ^ Depth to recurse
+                   -> String
+patsHomeLocsAtsPkg n = intercalate ":" ((<> ".atspkg/contrib") . ("./" <>) <$> g)
     where g = [ join $ replicate i "../" | i <- [0..n] ]
 
 pkgToAction :: [IO ()] -- ^ Setup actions to be performed
@@ -265,7 +265,7 @@
         specialDeps %> \out -> do
             (_, cfgBin') <- cfgBin
             need [ cfgBin', ".atspkg/config" ]
-            -- TODO use an oracle here
+            -- TODO use an oracle for c compiler/flags
             liftIO $ fetchDeps (ccFromString cc') setup (unpack . fst <$> ds) (unpack . fst <$> cdps) (unpack . fst <$> bdeps) cfgBin' atslibSetup False >> writeFile out ""
 
         let bins = unpack . target <$> bs
diff --git a/src/Language/ATS/Package/Build/C.hs b/src/Language/ATS/Package/Build/C.hs
--- a/src/Language/ATS/Package/Build/C.hs
+++ b/src/Language/ATS/Package/Build/C.hs
@@ -19,6 +19,12 @@
     ds' <- mapM allSubdirs ds
     pure $ join (ds : ds')
 
+
+ccForConfig :: CCompiler -> String
+ccForConfig = g . ccToString
+    where g "icc" = "cc"
+          g x     = x
+
 clibSetup :: CCompiler -- ^ C compiler
           -> String -- ^ Library name
           -> FilePath -- ^ Filepath to unpack to
@@ -33,11 +39,10 @@
 
     -- Set environment variables for configure script
     h <- cpkgHome cc'
-    let procEnv = Just [("CC", ccToString cc'), ("CFLAGS" :: String, "-I" <> h <> "include"), ("PATH", "/usr/bin:/bin")]
+    let procEnv = Just [("CC", ccForConfig cc'), ("CFLAGS" :: String, "-I" <> h <> "include"), ("PATH", "/usr/bin:/bin")]
 
     biaxe [fold (configure h <$> configurePath <*> pure procEnv), cmake h cmakeLists, make, install] lib' p
 
--- TODO only do this if @./configure@ is missing
 cmake :: FilePath -> Maybe FilePath -> String -> FilePath -> IO ()
 cmake _ Nothing _ _ = mempty
 cmake prefixPath (Just cfgLists) _ _ = do
diff --git a/src/Language/ATS/Package/Dhall.hs b/src/Language/ATS/Package/Dhall.hs
--- a/src/Language/ATS/Package/Dhall.hs
+++ b/src/Language/ATS/Package/Dhall.hs
@@ -16,10 +16,8 @@
       => FilePath
       -> Bool
       -> IO a
-checkDhall path d = do
-    x <- input auto (pack ('.' : '/' : path))
-    let f = bool id detailed d
-    f (pure x)
+checkDhall path d =
+    bool id detailed d $ input auto (pack ('.' : '/' : path))
 
 checkPkgSet :: FilePath -- ^ Path to @.dhall@ file defining a package set.
             -> Bool -- ^ Whether to print detailed error messages.
diff --git a/src/Language/ATS/Package/Generic.hs b/src/Language/ATS/Package/Generic.hs
--- a/src/Language/ATS/Package/Generic.hs
+++ b/src/Language/ATS/Package/Generic.hs
@@ -6,6 +6,7 @@
 module Language.ATS.Package.Generic ( GenericPackage (..)
                                     , InstallDirs (..)
                                     , Package (..)
+                                    , CacheValid
                                     -- * Functions
                                     , atsInstallDirs
                                     ) where
@@ -14,10 +15,13 @@
 import           Data.Hashable        (Hashable (..))
 import           Quaalude
 
+-- | Compares cached value to new value, returning 'True' if valid.
+type CacheValid a = a -> a -> Bool
+
 -- | Functions containing installation information about a particular type.
 data InstallDirs a = InstallDirs { binDir      :: a -> FilePath
                                  , libDir      :: a -> String -> FilePath
-                                 , includeDir  :: a -> FilePath
+                                 , includeDir  :: a -> String -> FilePath
                                  , includeDeps :: a -> [FilePath]
                                  , libDeps     :: a -> [FilePath]
                                  }
@@ -30,7 +34,7 @@
         includeDir' = h ++ "/.atspkg/include"
         libDeps' = ["/.atspkg/lib"]
         includeDeps' = ["/.atspkg/include"]
-    pure $ InstallDirs (pure binDir') (\pkg n -> "/.atspkg/lib/" ++ n ++ "/" ++ hex (hash pkg)) (pure includeDir') (pure includeDeps') (pure libDeps')
+    pure $ InstallDirs (pure binDir') (\pkg n -> "/.atspkg/lib/" ++ n ++ "/" ++ hex (hash pkg)) (\_ _ -> includeDir') (pure includeDeps') (pure libDeps')
 
 -- | The package monad provides information about the package to be installed,
 -- in particular, the directory for installation and the directories for
@@ -38,8 +42,6 @@
 newtype Package a b = Package { unPack :: ReaderT (InstallDirs a) IO b }
     deriving (Functor)
     deriving newtype (Applicative, Monad)
-
--- TODO statically require various things about a build.
 
 -- | Any type implementing 'GenericPackage' can be depended on by other
 -- packages.
diff --git a/src/Quaalude.hs b/src/Quaalude.hs
--- a/src/Quaalude.hs
+++ b/src/Quaalude.hs
@@ -23,6 +23,7 @@
                 , (***)
                 , (&&&)
                 , (<=<)
+                , (<>)
                 , first
                 , second
                 , getEnv
@@ -126,6 +127,7 @@
 import           Data.Foldable
 import           Data.List
 import           Data.Maybe                   (fromMaybe)
+import           Data.Semigroup
 import           Data.Text.Lazy               (pack, unpack)
 import           Data.Version                 (showVersion)
 import           Development.Shake            hiding (getEnv)
@@ -150,8 +152,9 @@
 instance Semigroup a => Semigroup (Action a) where
     (<>) a b = (<>) <$> a <*> b
 
-instance Monoid a => Monoid (Action a) where
+instance (Semigroup a, Monoid a) => Monoid (Action a) where
     mempty = pure mempty
+    mappend = (<>)
 
 -- | Same as "Text.PrettyPrint.ANSI.Leijen"'s @<$>@, but doesn't clash with the
 -- prelude.
