diff --git a/ats-pkg.cabal b/ats-pkg.cabal
--- a/ats-pkg.cabal
+++ b/ats-pkg.cabal
@@ -1,5 +1,5 @@
 name:                ats-pkg
-version:             2.4.0.6
+version:             2.4.1.0
 synopsis:            A build tool for ATS
 description:         A collection of scripts to simplify building ATS projects.
 homepage:            https://github.com/vmchale/atspkg#readme
@@ -72,8 +72,7 @@
                      , binary
                      , dependency
                      , ats-setup
-                     -- , lzma
-                     -- , bzlib
+  build-tools:         cpphs
   default-language:    Haskell2010
   if flag(development)
     ghc-options: -Werror
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
@@ -11,36 +11,24 @@
                                   , check
                                   ) where
 
-import           Control.Concurrent.ParallelIO.Global
-import           Control.Lens
-import           Control.Monad.IO.Class               (MonadIO)
-import           Data.Binary                          (decode, encode)
-import qualified Data.ByteString                      as BS
-import qualified Data.ByteString.Lazy                 as BSL
-import           Data.List                            (nub)
-import           Data.Maybe                           (fromMaybe)
-import           Data.Semigroup                       (Semigroup (..))
-import qualified Data.Text.Lazy                       as TL
-import           Data.Version                         hiding (Version (..))
-import           Development.Shake                    hiding (doesFileExist)
+import qualified Data.ByteString                 as BS
+import qualified Data.ByteString.Lazy            as BSL
+import           Data.List                       (nub)
+import           Data.Version                    (showVersion)
 import           Development.Shake.ATS
 import           Development.Shake.Check
 import           Development.Shake.Clean
-import           Development.Shake.FilePath
 import           Development.Shake.Man
-import           Dhall                                hiding (bool, maybe)
 import           Language.ATS.Package.Compiler
 import           Language.ATS.Package.Config
 import           Language.ATS.Package.Dependency
-import           Language.ATS.Package.Type            hiding (version)
-import           Paths_ats_pkg
+import           Language.ATS.Package.Type       hiding (Version)
+import qualified Paths_ats_pkg                   as P
 import           Quaalude
-import           System.Directory                     (doesFileExist, getCurrentDirectory)
-import qualified System.Environment                   as SE
 
 check :: Maybe FilePath -> IO Bool
 check p = do
-    home <- SE.getEnv "HOME"
+    home <- getEnv "HOME"
     v <- wants p
     doesFileExist (home ++ "/.atspkg/" ++ show v ++ "/bin/patscc")
 
@@ -61,7 +49,7 @@
 mkClean :: Rules ()
 mkClean = "clean" ~> do
     cleanHaskell
-    removeFilesAfter "." ["//*.1", "//*.c", "tags"]
+    removeFilesAfter "." ["//*.1", "//*.c", "tags", "//*.a"]
     removeFilesAfter "target" ["//*"]
     removeFilesAfter ".atspkg" ["//*"]
     removeFilesAfter "ats-deps" ["//*"]
@@ -70,9 +58,9 @@
 mkInstall =
     "install" ~> do
         config <- getConfig Nothing
-        bins <- fmap (TL.unpack . target) . bin <$> getConfig Nothing
+        bins <- fmap (unpack . target) . bin <$> getConfig Nothing
         need bins
-        home <- fromMaybe "" <$> getEnv "HOME"
+        home <- liftIO $ getEnv "HOME"
         let binDest = ((home <> "/.local/bin/") <>) . takeBaseName <$> bins
         void $ zipWithM copyFile' bins binDest
         pa <- pandoc
@@ -101,17 +89,17 @@
     d <- fromMaybe <$> fmap (<> "/atspkg.dhall") getCurrentDirectory <*> pure dir'
     b <- not <$> doesFileExist ".atspkg/config"
     if b
-        then input auto (TL.pack d)
+        then input auto (pack d)
         else fmap (decode . BSL.fromStrict) . BS.readFile $ ".atspkg/config"
 
 manTarget :: Text -> FilePath
-manTarget m = TL.unpack m -<.> "1"
+manTarget m = unpack m -<.> "1"
 
 mkPhony :: String -> (String -> String) -> (Pkg -> [Bin]) -> [String] -> Rules ()
 mkPhony cmdStr f select rs =
     cmdStr ~> do
         config <- getConfig Nothing
-        let runs = bool (filter (/= cmdStr) rs) (fmap (TL.unpack . target) . select $ config) (rs == [cmdStr])
+        let runs = bool (filter (/= cmdStr) rs) (fmap (unpack . target) . select $ config) (rs == [cmdStr])
         need runs
         mapM_ cmd_ (f <$> runs)
 
@@ -124,19 +112,28 @@
 mkRun :: [String] -> Rules ()
 mkRun = mkPhony "run" id bin
 
+toVerbosity :: Int -> Verbosity
+toVerbosity 0 = Normal
+toVerbosity 1 = Loud
+toVerbosity 2 = Chatty
+toVerbosity 3 = Diagnostic
+toVerbosity _ = undefined
+
 options :: Bool -- ^ Whether to rebuild config
         -> Bool -- ^ Whether to rebuild all targets
         -> Bool -- ^ Whether to run the linter
+        -> Int -- ^ Verbosity level
         -> [String] -- ^ A list of targets
         -> ShakeOptions
-options rb rba lint rs = shakeOptions { shakeFiles = ".atspkg"
+options rb rba lint v rs = shakeOptions { shakeFiles = ".atspkg"
                           , shakeThreads = 4
                           , shakeLint = bool Nothing (Just LintBasic) lint
-                          , shakeVersion = showVersion version
+                          , shakeVersion = showVersion P.version
                           , shakeRebuild = foldMap g [ (rb, [(RebuildNow, ".atspkg/config")])
                                                      , (rba, (RebuildNow ,) <$> rs)
                                                      ]
                           , shakeChange = ChangeModtimeAndDigestInput
+                          , shakeVerbosity = toVerbosity v
                           }
     where g (b, ts) = bool mempty ts b
 
@@ -152,12 +149,12 @@
       -> Maybe String -- ^ Target triple
       -> Int -- ^ Verbosity
       -> IO ()
-mkPkg rb rba lint setup rs tgt _ = do
+mkPkg rb rba lint setup rs tgt v = do
     cfg <- cleanConfig rs
-    let opt = options rb rba lint $ pkgToTargets cfg rs
+    let opt = options rb rba lint v $ pkgToTargets cfg rs
     shake opt $
         mconcat
-            [ want rs
+            [ want (pkgToTargets cfg rs)
             , mkClean
             , pkgToAction setup rs tgt =<< cleanConfig rs
             ]
@@ -184,7 +181,7 @@
     sequence [ mkRun, mkTest, mkValgrind ] rs
 
 pkgToTargets :: Pkg -> [FilePath] -> [FilePath]
-pkgToTargets ~Pkg{..} [] = TL.unpack . target <$> bin
+pkgToTargets ~Pkg{..} [] = (unpack . target <$> bin) <> (unpack . libTarget <$> libraries)
 pkgToTargets _ ts        = ts
 
 -- CROSS-COMPILING atslib:
@@ -198,7 +195,7 @@
             -> Maybe String -- ^ Optional compiler triple (overrides 'ccompiler')
             -> Pkg -- ^ Package data type
             -> Rules ()
-pkgToAction setup rs tgt ~(Pkg bs ts mt v v' ds cds ccLocal cf as cdir) =
+pkgToAction setup rs tgt ~(Pkg bs ts libs mt v v' ds cds ccLocal cf as cdir) =
 
     unless (rs == ["clean"]) $ do
 
@@ -209,30 +206,35 @@
         ".atspkg/deps" %> \out -> do
             (_, cfgBin') <- cfgBin
             need [ cfgBin' ]
-            liftIO $ fetchDeps (ccFromString cc') setup (TL.unpack <$> ds) (TL.unpack <$> cdps) cfgBin' False >> stopGlobalPool
-            liftIO $ writeFile out ""
+            liftIO $ fetchDeps (ccFromString cc') setup (unpack <$> ds) (unpack <$> cdps) cfgBin' False >> writeFile out ""
 
-        let bins = TL.unpack . target <$> bs
+        let bins = unpack . target <$> bs
         setTargets rs bins mt
 
         cDepsRules >> bits rs
 
+        mapM_ h libs
+
         mapM_ g (bs ++ ts)
 
     where g (Bin s t ls hs' atg gc' cSrc extra) =
             atsBin
-                (BinaryTarget (TL.unpack <$> cf) (ATSToolConfig v v' False (ccFromString cc')) gc' (TL.unpack <$> ls) [TL.unpack s] hs' (unpackBoth . asTuple <$> atg) (TL.unpack t) (TL.unpack <$> cSrc) (deps extra) Executable)
+                (BinaryTarget (unpack <$> cf) (ATSToolConfig v v' False (ccFromString cc')) gc' (unpack <$> ls) [unpack s] hs' (unpackBoth . asTuple <$> atg) (unpack t) (unpack <$> cSrc) (deps extra) Executable)
 
+          h (Lib sources t ls hs' atg cSrc extra) =
+            atsBin (BinaryTarget (unpack <$> cf) (ATSToolConfig v v' False (ccFromString cc')) False (unpack <$> ls) (unpack <$> sources) hs' (unpackBoth . asTuple <$> atg) (unpack t) (unpack <$> cSrc) (deps extra) StaticLibrary)
+
+
           cDepsRules = unless (null as) $ do
-            let cedar = TL.unpack cdir
-                atsSourceDirs = nub (takeDirectory . TL.unpack <$> as)
-                targets = fmap (((cedar <> "/") <>) . (-<.> "c") . takeBaseName . TL.unpack) as
+            let cedar = unpack cdir
+                atsSourceDirs = nub (takeDirectory . unpack <$> as)
+                targets = fmap (((cedar <> "/") <>) . (-<.> "c") . takeBaseName . unpack) as
             want targets
             hasPF <- patsFilter
             mapM_ (cgen (ATSToolConfig v v' hasPF (ccFromString cc')) [".atspkg/deps", ".atspkg/config"]) atsSourceDirs
 
-          cc' = maybe (TL.unpack ccLocal) (<> "-gcc") tgt
-          deps = (".atspkg/deps":) . (".atspkg/config":) . fmap TL.unpack
+          cc' = maybe (unpack ccLocal) (<> "-gcc") tgt
+          deps = (".atspkg/deps":) . (".atspkg/config":) . fmap unpack
 
           unpackBoth :: (Text, Text, Bool) -> (String, String, Bool)
-          unpackBoth = over _1 TL.unpack . over _2 TL.unpack
+          unpackBoth = over _1 unpack . over _2 unpack
diff --git a/src/Language/ATS/Package/Compiler.hs b/src/Language/ATS/Package/Compiler.hs
--- a/src/Language/ATS/Package/Compiler.hs
+++ b/src/Language/ATS/Package/Compiler.hs
@@ -7,11 +7,9 @@
     , setupCompiler
     ) where
 
-import           Control.Monad
 import           Data.Dependency
-import qualified Distribution.ATS   as X
-import           System.Directory
-import           System.Environment (getEnv)
+import qualified Distribution.ATS as X
+import           Quaalude
 
 cleanAll :: IO ()
 cleanAll = do
diff --git a/src/Language/ATS/Package/Config.hs b/src/Language/ATS/Package/Config.hs
--- a/src/Language/ATS/Package/Config.hs
+++ b/src/Language/ATS/Package/Config.hs
@@ -7,16 +7,10 @@
                                    , cfgBin
                                    ) where
 
-import           Control.Arrow
-import           Control.Monad.IO.Class
-import           Data.Binary
-import qualified Data.ByteString.Lazy   as BSL
+import qualified Data.ByteString.Lazy as BSL
 import           Data.FileEmbed
-import qualified Data.Text.Lazy         as TL
-import           Development.Shake      hiding (getEnv)
-import           Dhall
-import           System.Directory       (createDirectoryIfMissing)
-import           System.Environment     (getEnv)
+import qualified Data.Text.Lazy       as TL
+import           Quaalude
 
 data UserConfig = UserConfig { defaultPkgs    :: Text
                              , path           :: Maybe Text
diff --git a/src/Language/ATS/Package/Dependency.hs b/src/Language/ATS/Package/Dependency.hs
--- a/src/Language/ATS/Package/Dependency.hs
+++ b/src/Language/ATS/Package/Dependency.hs
@@ -11,25 +11,14 @@
 import qualified Codec.Compression.GZip               as Gzip
 import qualified Codec.Compression.Lzma               as Lzma
 import           Control.Concurrent.ParallelIO.Global
-import           Control.Lens
-import           Control.Monad
-import           Data.Binary                          (decode)
-import           Data.ByteString.Lazy                 (ByteString)
 import qualified Data.ByteString.Lazy                 as BSL
-import           Data.Maybe                           (fromMaybe)
-import           Data.Semigroup                       (Semigroup (..))
 import qualified Data.Text.Lazy                       as TL
 import           Development.Shake.ATS
-import           Dhall
 import           Language.ATS.Package.Config
 import           Language.ATS.Package.Error
 import           Language.ATS.Package.PackageSet
 import           Language.ATS.Package.Type
-import           Network.HTTP.Client                  hiding (host)
-import           Network.HTTP.Client.TLS              (tlsManagerSettings)
-import           System.Directory
-import           System.Environment                   (getEnv)
-import           System.Posix.Files
+import           Quaalude
 import           System.Process
 
 fetchDeps :: CCompiler -- ^ C compiler to use
@@ -41,16 +30,17 @@
           -> IO ()
 fetchDeps cc' setup' deps cdeps cfgPath b' =
     unless (null deps && null cdeps && b') $ do
-        pkgSet <- TL.unpack . defaultPkgs . decode <$> BSL.readFile cfgPath
+        putStrLn "Resolving dependencies..."
+        pkgSet <- unpack . defaultPkgs . decode <$> BSL.readFile cfgPath
         deps' <- join <$> setBuildPlan "ats" pkgSet deps
         putStrLn "Checking ATS dependencies..."
         d <- (<> "lib/") <$> pkgHome cc'
         let libs' = fmap (buildHelper False) deps'
         cdeps' <- join <$> setBuildPlan "c" pkgSet cdeps
-        let unpacked = fmap (over dirLens (TL.pack d <>)) cdeps'
+        let unpacked = fmap (over dirLens (pack d <>)) cdeps'
             clibs = fmap (buildHelper False) unpacked
-        parallel_ (setup' ++ libs' ++ clibs)
-        mapM_ (setup cc') unpacked
+        parallel_ (extraWorkerWhileBlocked <$> (setup' ++ libs' ++ clibs))
+        mapM_ (setup cc') unpacked >> stopGlobalPool
 
 pkgHome :: CCompiler -> IO FilePath
 pkgHome cc' = (++ ("/.atspkg/" ++ ccToDir cc')) <$> getEnv "HOME"
@@ -86,10 +76,10 @@
       -> ATSDependency -- ^ ATSDependency itself
       -> IO ()
 setup cc' (ATSDependency lib' dirName' _ _ _) = do
-    lib'' <- (<> TL.unpack lib') <$> pkgHome cc'
+    lib'' <- (<> unpack lib') <$> pkgHome cc'
     b <- doesFileExist lib''
     unless b $ do
-        clibSetup cc' (TL.unpack lib') (TL.unpack dirName')
+        clibSetup cc' (unpack lib') (unpack dirName')
         writeFile lib'' ""
 
 getCompressor :: Text -> IO (ByteString -> ByteString)
@@ -98,7 +88,7 @@
     | ".tar" `TL.isSuffixOf` s = pure id
     | ".tar.xz" `TL.isSuffixOf` s = pure Lzma.decompress
     | ".tar.bz2" `TL.isSuffixOf` s = pure Bzip.decompress
-    | otherwise = unrecognized (TL.unpack s)
+    | otherwise = unrecognized (unpack s)
 
 tarResponse :: Text -> FilePath -> ByteString -> IO ()
 tarResponse url' dirName response = do
@@ -114,7 +104,7 @@
 buildHelper :: Bool -> ATSDependency -> IO ()
 buildHelper b (ATSDependency lib' dirName' url'' _ _) = do
 
-    let (lib, dirName, url') = (lib', dirName', url'') & each %~ TL.unpack
+    let (lib, dirName, url') = (lib', dirName', url'') & each %~ unpack
 
     needsSetup <- not <$> doesDirectoryExist (dirName ++ if b then "/atspkg.dhall" else "")
 
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
@@ -1,13 +1,13 @@
 module Language.ATS.Package.Dhall ( checkPkg
                                   ) where
 
-import           Data.Bool                 (bool)
-import qualified Data.Text.Lazy            as TL
-import           Dhall                     hiding (bool)
 import           Language.ATS.Package.Type
+import           Quaalude
 
-checkPkg :: FilePath -> Bool -> IO ATSDependency
-checkPkg path details = do
-    x <- input auto (TL.pack ('.' : '/' : path))
-    let f = bool id detailed details
+checkPkg :: FilePath -- ^ Path to @pkg.dhall@ or similar.
+         -> Bool -- ^ Whether to print detailed error messages.
+         -> IO ATSDependency
+checkPkg path d = do
+    x <- input auto (pack ('.' : '/' : path))
+    let f = bool id detailed d
     f (pure (x :: ATSDependency))
diff --git a/src/Language/ATS/Package/Error.hs b/src/Language/ATS/Package/Error.hs
--- a/src/Language/ATS/Package/Error.hs
+++ b/src/Language/ATS/Package/Error.hs
@@ -6,11 +6,9 @@
                                   ) where
 
 import           Data.Dependency
+import           Quaalude
 import           System.Exit
-import           Text.PrettyPrint.ANSI.Leijen
 
-infixr 5 <#>
-
 unrecognized :: String -> IO a
 unrecognized = printErr . Unrecognized
 
@@ -19,9 +17,6 @@
 
 data PackageError = Unrecognized String
                   | DepErr ResolveError
-
-(<#>) :: Doc -> Doc -> Doc
-(<#>) a b = a <> line <> b
 
 instance Pretty PackageError where
     pretty (Unrecognized t) = red "Error:" <+> "Unrecognized archive format when unpacking" <#> hang 2 (text t)
diff --git a/src/Language/ATS/Package/Exec.hs b/src/Language/ATS/Package/Exec.hs
--- a/src/Language/ATS/Package/Exec.hs
+++ b/src/Language/ATS/Package/Exec.hs
@@ -2,7 +2,6 @@
 
 module Language.ATS.Package.Exec ( exec
                                  ) where
-
 import           Control.Composition
 import           Control.Lens               hiding (argument)
 import           Data.Bool                  (bool)
@@ -12,9 +11,9 @@
 import           Data.Version               hiding (Version (..))
 import           Development.Shake.ATS
 import           Development.Shake.FilePath
-import           Language.ATS.Package       hiding (version)
+import           Language.ATS.Package
 import           Options.Applicative        hiding (auto)
-import           Paths_ats_pkg
+import qualified Paths_ats_pkg              as P
 import           System.Directory
 import           System.IO.Temp             (withSystemTempDirectory)
 
@@ -26,7 +25,7 @@
     <> header "atspkg - a build tool for ATS\nsee 'man atspkg' for more detailed help")
 
 versionInfo :: Parser (a -> a)
-versionInfo = infoOption ("atspkg version: " ++ showVersion version) (short 'v' <> long "version" <> help "Show version")
+versionInfo = infoOption ("atspkg version: " ++ showVersion P.version) (short 'V' <> long "version" <> help "Show version")
 
 data Command = Install
              | Build { _targets    :: [String]
@@ -61,14 +60,18 @@
 
 check' :: Parser Command
 check' = Check
-    <$> targetP completions id "check"
+    <$> targetP dhallCompletions id "check"
     <*> switch
     (long "detailed"
     <> short 'd'
     <> help "Enable detailed error messages")
 
-    where completions = completer (bashCompleter "file -X '!*.dhall' -o plusdirs")
+ftypeCompletions :: String -> Mod ArgumentFields a
+ftypeCompletions ext = completer . bashCompleter $ "file -X '!*." ++ ext ++ "' -o plusdirs"
 
+dhallCompletions :: Mod ArgumentFields a
+dhallCompletions = ftypeCompletions "dhall"
+
 run' :: Parser Command
 run' = Run <$> targets "run"
 
@@ -105,7 +108,7 @@
         <> short 'r'
         <> help "Force rebuild of all targets")
     <*> (length <$>
-        many (flag' () (short 't' <> long "verbose" <> help "Turn up verbosity")))
+        many (flag' () (short 'v' <> long "verbose" <> help "Turn up verbosity")))
     <*> noLint
 
 noLint :: Parser Bool
diff --git a/src/Language/ATS/Package/PackageSet.hs b/src/Language/ATS/Package/PackageSet.hs
--- a/src/Language/ATS/Package/PackageSet.hs
+++ b/src/Language/ATS/Package/PackageSet.hs
@@ -7,19 +7,13 @@
                                        , mkBuildPlan
                                        ) where
 
-import           Control.Arrow
-import           Control.Monad
-import           Data.Binary                (decode, encode)
-import           Data.Bool                  (bool)
 import qualified Data.ByteString.Lazy       as BSL
 import           Data.Dependency
 import qualified Data.Map                   as M
 import qualified Data.Set                   as S
-import qualified Data.Text.Lazy             as TL
-import           Dhall                      hiding (bool)
 import           Language.ATS.Package.Error
 import           Language.ATS.Package.Type
-import           System.Directory           (createDirectoryIfMissing, doesFileExist)
+import           Quaalude
 
 -- TODO string instance? string :: Type String
 
@@ -36,8 +30,7 @@
 
     where depCache = ".atspkg/buildplan-" ++ p
           setBuildPlan' = do
-            putStrLn "Resolving dependencies..."
-            pkgSet <- input auto (TL.pack url)
+            pkgSet <- input auto (pack url)
             case mkBuildPlan pkgSet deps of
                 Right x -> createDirectoryIfMissing True ".atspkg" >> BSL.writeFile depCache (encode x) >> pure x
                 Left x  -> resolutionFailed x
@@ -47,25 +40,25 @@
     where finalize = fmap (fmap (fmap (lookupVersions aps)))
           resolve = resolveDependencies (atsPkgsToPkgs aps)
           stringBuildPlan names = sequence [ lookup' x libs | x <- names ]
-              where libs = (TL.unpack . libName &&& id) <$> ps
+              where libs = (unpack . libName &&& id) <$> ps
                     lookup' k vs = case lookup k vs of
                         Just x  -> Right x
                         Nothing -> Left (NotPresent k)
 
 asDep :: ATSDependency -> Dependency
-asDep ATSDependency{..} = Dependency (TL.unpack libName) mempty (TL.unpack <$> libDeps) libVersion
+asDep ATSDependency{..} = Dependency (unpack libName) mempty (unpack <$> libDeps) libVersion
 
 atsPkgsToPkgs :: ATSPackageSet -> PackageSet Dependency
 atsPkgsToPkgs (ATSPackageSet deps) = PackageSet $ foldr (.) id inserts mempty
     where inserts = insert <$> deps
           insert dep = M.insertWith
             (\_ -> S.insert (asDep dep))
-            (TL.unpack $ libName dep)
+            (unpack $ libName dep)
             (S.singleton (asDep dep))
 
 lookupVersions :: ATSPackageSet -> Dependency -> ATSDependency
 lookupVersions (ATSPackageSet deps) (Dependency name _ _ v) = head (filter f deps)
     where f = (&&) <$> matchName <*> matchVersion
-          libName' = TL.unpack . libName
+          libName' = unpack . libName
           matchName = (== name) . libName'
           matchVersion = (== v) . libVersion
diff --git a/src/Language/ATS/Package/Type.hs b/src/Language/ATS/Package/Type.hs
--- a/src/Language/ATS/Package/Type.hs
+++ b/src/Language/ATS/Package/Type.hs
@@ -3,6 +3,7 @@
 {-# LANGUAGE DeriveAnyClass             #-}
 {-# LANGUAGE DeriveGeneric              #-}
 {-# LANGUAGE DerivingStrategies         #-}
+{-# LANGUAGE DuplicateRecordFields      #-}
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
 {-# LANGUAGE OverloadedStrings          #-}
 {-# LANGUAGE ScopedTypeVariables        #-}
@@ -13,6 +14,7 @@
                                    Pkg (..)
                                  , ATSDependency (..)
                                  , Bin (..)
+                                 , Lib (..)
                                  , Version (..)
                                  , ATSConstraint (..)
                                  , TargetPair (..)
@@ -21,11 +23,9 @@
                                  , dirLens
                                  ) where
 
-import           Control.Lens
-import           Data.Binary           (Binary (..))
 import           Data.Dependency
 import           Development.Shake.ATS
-import           Dhall
+import           Quaalude
 
 data ATSConstraint = ATSConstraint { pkgName :: Text
                                    , lower   :: Maybe Version
@@ -67,19 +67,21 @@
                }
          deriving (Show, Eq, Generic, Interpret, Binary)
 
--- data Lib = Lib { src      :: [Text] -- ^ Source files (should end with @.dats@) to be compiled to object files
---                , target   :: Text
---                , hsDeps   :: [ForeignCabal] -- ^ Haskell @.cabal@ files associated with object files
---                , hs2ats   :: [TargetPair] -- ^ Sources and targets for @hs2ats@
---                , cSources :: [Text] -- ^ C source files the build depends on
---                , extras   :: [Text] -- ^ Other source files the build depends on
---                }
---          deriving (Show, Eq, Generic, Interpret, Binary)
+data Lib = Lib { src       :: [Text] -- ^ Source files (should end with @.dats@) to be compiled to object files
+               , libTarget :: Text
+               , libs      :: [Text] -- ^ Libraries to link against (e.g. @[ "pthread" ]@)
+               , hsDeps    :: [ForeignCabal] -- ^ Haskell @.cabal@ files associated with object files
+               , hs2ats    :: [TargetPair] -- ^ Sources and targets for @hs2ats@
+               , cSources  :: [Text] -- ^ C source files the build depends on
+               , extras    :: [Text] -- ^ Other source files the build depends on
+               }
+         deriving (Show, Eq, Generic, Interpret, Binary)
 
 -- TODO make binaries optional
 -- | Data type associated with @atspkg.dhall@ file.
 data Pkg = Pkg { bin          :: [Bin] -- ^ List of binaries to be built
                , test         :: [Bin] -- ^ List of test suites
+               , libraries    :: [Lib] -- ^ List of libraries to be built
                , man          :: Maybe Text -- ^ Optional (markdown) manpages to be converted using @pandoc@.
                , version      :: Version -- ^ Library version
                , compiler     :: Version -- ^ Compiler version
diff --git a/src/Language/ATS/Package/Upgrade.hs b/src/Language/ATS/Package/Upgrade.hs
--- a/src/Language/ATS/Package/Upgrade.hs
+++ b/src/Language/ATS/Package/Upgrade.hs
@@ -5,16 +5,8 @@
 
 import qualified Data.ByteString.Lazy.Char8 as BSL
 import           Data.Char                  (isDigit)
-import           Data.List                  (intersperse)
-import           Data.Maybe                 (fromMaybe)
-import           Data.Semigroup
-import           Development.Shake.FilePath
-import           Network.HTTP.Client
-import           Network.HTTP.Client.TLS    (tlsManagerSettings)
-import           System.Directory           (createDirectoryIfMissing, renameFile)
-import           System.Environment
+import           Quaalude
 import           System.Info
-import           System.Posix.Files
 
 -- https://github.com/vmchale/atspkg/archive/master.zip
 manufacturer :: String
@@ -28,7 +20,7 @@
 
 atspkgPath :: IO String
 atspkgPath = do
-    home <- fromMaybe "." <$> lookupEnv "HOME"
+    home <- getEnv "HOME"
     pure $ home <> "/.local/bin/atspkg"
 
 -- TODO install `pi`?
diff --git a/src/Quaalude.hs b/src/Quaalude.hs
--- a/src/Quaalude.hs
+++ b/src/Quaalude.hs
@@ -1,39 +1,115 @@
 {-# LANGUAGE CPP #-}
 
 module Quaalude ( bool
+                , intersperse
                 , void
                 , unless
                 , when
                 , join
                 , zipWithM
-                , pack
-                , unpack
+                , filterM
                 , encode
                 , decode
                 , fromMaybe
                 , isPrefixOf
                 , isSuffixOf
                 , on
-                , Text
-                , Generic
-                , Binary
-                , (.*)
                 , (<>)
                 , (***)
                 , (&&&)
+                , (<=<)
                 , first
                 , second
+                , getEnv
+                , MonadIO (..)
+                -- * "Data.Text.Lazy" reëxports
+                , Text
+                , pack
+                , unpack
+                , (.*)
+                -- * Dhall reëxports
+                , Interpret
+                , Generic
+                , Binary
+                , input
+                , auto
+                , detailed
+                -- * Shake reëxports
+                , Rules
+                , Action
+                , command
+                , command_
+                , (%>)
+                , need
+                , want
+                , shake
+                , Rebuild (..)
+                , (~>)
+                , cmd
+                , cmd_
+                , ShakeOptions (..)
+                , shakeOptions
+                , copyFile'
+                , Change (..)
+                , Verbosity (..)
+                , removeFilesAfter
+                , Lint (..)
+                , takeBaseName
+                , takeFileName
+                , takeDirectory
+                , (-<.>)
+                -- * "System.Posix" reëxports
+                , setFileMode
+                , ownerModes
+                -- * "Network.HTTP.Client.TLS" reëxports
+                , tlsManagerSettings
+                -- "Network.HTTP.Client" reëxports
+                , newManager
+                , parseRequest
+                , httpLbs
+                , Response (..)
+                , Request (method, redirectCount)
+                -- * ByteString reëxports
+                , ByteString
+                -- * Helpers for pretty-printing
+                , (<#>)
+                -- * "Text.PrettyPrint.ANSI.Leijen" reëxports
+                , (<+>)
+                , text
+                , red
+                , hang
+                , putDoc
+                , Pretty (pretty)
+                , module X
                 ) where
 
-import           Control.Arrow
+import           Control.Arrow                hiding ((<+>))
+import           Control.Lens                 as X
+import           Control.Monad.IO.Class
+import           Data.ByteString.Lazy         (ByteString)
+import           Network.HTTP.Client
+import           Network.HTTP.Client.TLS      (tlsManagerSettings)
+import           System.Posix.Files
 #if __GLASGOW_HASKELL__ < 804
 import           Data.Semigroup
 #endif
 import           Control.Composition
 import           Control.Monad
 import           Data.Binary
-import           Data.Bool           (bool)
-import           Data.List           (isPrefixOf, isSuffixOf)
-import           Data.Maybe          (fromMaybe)
-import           Data.Text.Lazy      (pack, unpack)
-import           Dhall               hiding (bool)
+import           Data.Bool                    (bool)
+import           Data.List                    (intersperse, isPrefixOf, isSuffixOf)
+import           Data.Maybe                   (fromMaybe)
+import           Data.Text.Lazy               (pack, unpack)
+import           Development.Shake            hiding (getEnv)
+import           Development.Shake.FilePath
+import           Dhall                        hiding (bool)
+import           System.Directory             as X
+import           System.Environment           (getEnv)
+import           Text.PrettyPrint.ANSI.Leijen hiding (bool, (<>))
+
+infixr 5 <#>
+
+-- | Same as "Text.PrettyPrint.ANSI.Leijen"'s @<$>@, but doesn't clash with the
+-- prelude.
+(<#>) :: Doc -> Doc -> Doc
+(<#>) a b = a <> line <> b
diff --git a/stack.yaml b/stack.yaml
--- a/stack.yaml
+++ b/stack.yaml
@@ -6,7 +6,7 @@
   - 'shake-ats'
   - 'hs2ats'
 extra-deps:
-  - shake-ext-2.4.0.0
+  - shake-ext-2.5.0.0
   - composition-prelude-1.1.0.2
   - language-ats-0.3.0.1
   - cli-setup-0.2.0.1
