diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,12 @@
+# ats-pkg
+
+## 3.2.1.2
+
+Bug Fixes:
+
+  * Don't default to 4 processors
+  * Use `getAppUserDirectory` for better portability
+
+Breaking Changes:
+
+  * Only build C sources when sensible to do so
diff --git a/app/Main.hs b/app/Main.hs
--- a/app/Main.hs
+++ b/app/Main.hs
@@ -248,7 +248,7 @@
 
 installActions :: IO ()
 installActions = do
-    path <- getDataFileName "man/atspkg.1"
+    path <- getDataFileName ("man" </> "atspkg.1")
     fold
         [ writeManpages path "atspkg.1"
         , writeTheFuck
diff --git a/ats-pkg.cabal b/ats-pkg.cabal
--- a/ats-pkg.cabal
+++ b/ats-pkg.cabal
@@ -1,6 +1,6 @@
 cabal-version: 2.0
 name: ats-pkg
-version: 3.1.0.12
+version: 3.2.1.2
 license: BSD3
 license-file: LICENSE
 copyright: Copyright: (c) 2018 Vanessa McHale
@@ -21,6 +21,7 @@
     dhall/atspkg-prelude.dhall
 extra-doc-files: README.md
                  docs/manual.tex
+                 CHANGELOG.md
 
 source-repository head
     type: git
@@ -58,7 +59,6 @@
         Language.ATS.Package.Config
         Language.ATS.Package.Dependency
         Language.ATS.Package.Error
-        Language.ATS.Package.Generic
         Language.ATS.Package.PackageSet
         Language.ATS.Package.Type
         Language.ATS.Package.Debian
@@ -66,10 +66,9 @@
     autogen-modules:
         Paths_ats_pkg
     default-language: Haskell2010
-    other-extensions: OverloadedStrings GADTs
-                      GeneralizedNewtypeDeriving DeriveAnyClass DeriveGeneric
-                      TemplateHaskell RecordWildCards TupleSections StandaloneDeriving
-                      DerivingStrategies
+    other-extensions: OverloadedStrings GeneralizedNewtypeDeriving
+                      DeriveAnyClass DeriveGeneric TemplateHaskell RecordWildCards
+                      TupleSections StandaloneDeriving DerivingStrategies
     ghc-options: -Wall -Wincomplete-uni-patterns
                  -Wincomplete-record-updates
     build-depends:
@@ -86,7 +85,6 @@
         http-client-tls -any,
         text -any,
         process -any,
-        hashable -any,
         containers -any,
         parallel-io -any,
         mtl -any,
@@ -117,7 +115,7 @@
         http-client -any,
         http-client-tls -any,
         process -any,
-        directory -any,
+        directory >=1.2.3.0,
         filepath -any,
         microlens -any,
         dhall -any,
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.2.2.1
+.\" Automatically generated by Pandoc 2.2.3.2
 .\"
 .TH "atspkg (1)" "" "" "" ""
 .hy
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
@@ -8,8 +8,6 @@
                             , atspkgVersion
                             -- * Functions involving the compiler
                             , packageCompiler
-                            -- * Functions for generic packaging
-                            , atsInstallDirs
                             -- * Types
                             , Version (..)
                             , Pkg (..)
@@ -24,12 +22,6 @@
                             , LibDep
                             , DepSelector
                             , PackageError (..)
-                            -- * Generic Packaging
-                            , Package (..)
-                            , InstallDirs (..)
-                            , CacheValid
-                            -- * Typeclasses
-                            , GenericPackage (..)
                             -- * Lenses
                             , dirLens
                             ) where
@@ -39,6 +31,5 @@
 import           Language.ATS.Package.Compiler
 import           Language.ATS.Package.Dependency
 import           Language.ATS.Package.Error
-import           Language.ATS.Package.Generic
 import           Language.ATS.Package.PackageSet
 import           Language.ATS.Package.Type
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
@@ -21,6 +21,7 @@
 import           Development.Shake.Clean
 import           Development.Shake.Man
 import           Distribution.ATS.Version
+import           GHC.Conc
 import           Language.ATS.Package.Build.C
 import           Language.ATS.Package.Compiler
 import           Language.ATS.Package.Config
@@ -31,9 +32,8 @@
 
 check :: Maybe String -> Maybe FilePath -> IO Bool
 check mStr p = do
-    home <- getEnv "HOME"
     v <- wants mStr p
-    doesFileExist (home </> ".atspkg" </> show v </> "bin" </> "patscc")
+    doesFileExist =<< getAppUserDataDirectory ("atspkg" </> show v </> "bin" </> "patscc")
 
 wants :: Maybe String -> Maybe FilePath -> IO Version
 wants mStr p = compiler <$> getConfig mStr p
@@ -84,14 +84,15 @@
             libDir = maybe mempty (<> [pathSeparator]) tgt
         need (bins <> libs')
         home <- liftIO $ getEnv "HOME"
+        atspkgDir <- liftIO $ getAppUserDataDirectory "atspkg"
         let g str = fmap (((home </> str) </>) . takeFileName)
             binDest =  g (".local" </> "bin") bins
-            libDest = ((home </> ".atspkg" </> libDir </> "lib") </>) . takeFileName <$> libs'
-            inclDest = ((home </> ".atspkg" </> "include") </>) . takeFileName <$> incs
+            libDest = ((atspkgDir </> libDir </> "lib") </>) . takeFileName <$> libs'
+            inclDest = ((atspkgDir </> "include") </>) . takeFileName <$> incs
         zipWithM_ copyFile' (bins ++ libs' ++ incs) (binDest ++ libDest ++ inclDest)
         pa <- pandoc
         case man config of
-            Just mt -> if not pa then pure () else do
+            Just mt -> when pa $ do
                 let mt' = manTarget mt
                     manDest = home </> ".local" </> "share" </> "man" </> "man1" </> takeFileName mt'
                 need [mt']
@@ -99,7 +100,7 @@
             Nothing -> pure ()
         co <- compleat
         case completions config of
-            Just com -> if not co then pure () else do
+            Just com -> when co $ do
                 let com' = unpack com
                     comDest = home </> ".compleat" </> takeFileName com'
                 need [com'] -- FIXME do this all in one step
@@ -168,18 +169,19 @@
 options :: Bool -- ^ Whether to rebuild all targets
         -> Bool -- ^ Whether to run the linter
         -> Bool -- ^ Whether to display profiling information for the build
+        -> Int -- ^ Number of CPUs
         -> Int -- ^ Verbosity level
         -> [String] -- ^ A list of targets
         -> ShakeOptions
-options rba lint tim v rs = shakeOptions { shakeFiles = ".atspkg"
-                                         , shakeThreads = 4
-                                         , shakeLint = bool Nothing (Just LintBasic) lint
-                                         , shakeVersion = showVersion atspkgVersion
-                                         , shakeRebuild = rebuildTargets rba rs
-                                         , shakeChange = ChangeModtimeAndDigestInput
-                                         , shakeVerbosity = toVerbosity v
-                                         , shakeTimings = tim
-                                         }
+options rba lint tim cpus v rs = shakeOptions { shakeFiles = ".atspkg"
+                                              , shakeThreads = cpus
+                                              , shakeLint = bool Nothing (Just LintBasic) lint
+                                              , shakeVersion = showVersion atspkgVersion
+                                              , shakeRebuild = rebuildTargets rba rs
+                                              , shakeChange = ChangeModtimeAndDigestInput
+                                              , shakeVerbosity = toVerbosity v
+                                              , shakeTimings = tim
+                                              }
 
 rebuildTargets :: Bool -- ^ Force rebuild of all targets
                -> [String] -- ^ Targets
@@ -204,7 +206,9 @@
       -> IO ()
 mkPkg mStr rba lint tim setup rs tgt v = do
     cfg <- cleanConfig mStr rs
-    let opt = options rba lint tim v $ pkgToTargets cfg tgt rs
+    setNumCapabilities =<< getNumProcessors
+    cpus <- getNumCapabilities
+    let opt = options rba lint tim cpus v $ pkgToTargets cfg tgt rs
     shake opt $
         mconcat
             [ want (pkgToTargets cfg tgt rs)
@@ -241,7 +245,7 @@
     bisequence' [ mkRun, mkTest, mkValgrind ] mStr rs
 
 pkgToTargets :: Pkg -> Maybe String -> [FilePath] -> [FilePath]
-pkgToTargets ~Pkg{..} tgt [] = (toTgt tgt . target <$> bin) <> (unpack . libTarget <$> libraries)
+pkgToTargets ~Pkg{..} tgt [] = (toTgt tgt . target <$> bin) <> (unpack . libTarget <$> libraries) <> (unpack . cTarget <$> atsSource)
 pkgToTargets _  _ ts         = ts
 
 noConstr :: ATSConstraint
@@ -263,7 +267,7 @@
 
 -- | The directory @~/.atspkg@
 pkgHome :: MonadIO m => CCompiler -> m String
-pkgHome cc' = liftIO $ (</> (".atspkg" </> ccToDir cc')) <$> getEnv "HOME"
+pkgHome cc' = liftIO $ getAppUserDataDirectory ("atspkg" </> ccToDir cc')
 
 -- | The directory that will be @PATSHOME@.
 patsHomeAtsPkg :: MonadIO m => Version -> m String
@@ -301,8 +305,6 @@
 
         mkUserConfig
 
-        want (unpack . cTarget <$> as)
-
         newFlag <- shouldWrite tgt flags
 
         -- this is dumb but w/e
@@ -315,7 +317,7 @@
 
         -- TODO depend on tgt somehow?
         specialDeps %> \out -> do
-            (_, cfgBin') <- cfgBin
+            cfgBin' <- cfgBin
             need [ cfgBin', flags, cfgFile]
             v'' <- getVerbosity
             liftIO $ fetchDeps v'' (ccFromString cc') mStr setup (first unpack <$> ds) (first unpack <$> cdps) (first unpack <$> bdeps) cfgBin' atslibSetup False *> writeFile out ""
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
@@ -5,10 +5,11 @@
 
 import           Development.Shake.ATS
 import           Development.Shake.C
+import           GHC.Conc
 import           Quaalude
 
 cpkgHome :: CCompiler -> IO FilePath
-cpkgHome cc' = (</> (".atspkg" </> ccToDir cc')) <$> getEnv "HOME"
+cpkgHome cc' = getAppUserDataDirectory ("atspkg" </> ccToDir cc')
 
 allSubdirs :: FilePath -> IO [FilePath]
 allSubdirs [] = pure mempty
@@ -70,7 +71,8 @@
 make v lib' p = do
     putStrLn ("building " ++ lib' ++ "...")
     p' <- findMakefile p
-    silentCreateProcess v ((proc makeExe ["-j4"]) { cwd = Just p' })
+    cpus <- getNumCapabilities
+    silentCreateProcess v ((proc makeExe ["-j" ++ show cpus]) { cwd = Just p' })
 
 install :: Verbosity -> String -> FilePath -> IO ()
 install v lib' p = do
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
@@ -21,7 +21,6 @@
 import           Network.HTTP.Client     hiding (decompress)
 import           Network.HTTP.Client.TLS (tlsManagerSettings)
 import           Quaalude
-import           System.Environment      (getEnv)
 import           System.FilePath.Find    (find)
 
 libatsCfg :: String
@@ -29,7 +28,7 @@
 
 compilerDir :: Version -> IO FilePath
 compilerDir v = makeAbsolute =<< dir
-    where dir = (</> (".atspkg" </> show v)) <$> getEnv "HOME"
+    where dir = getAppUserDataDirectory ("atspkg" </> show v)
 
 -- | Make a tarball from a directory containing the compiler.
 packageCompiler :: FilePath -> IO ()
@@ -110,7 +109,7 @@
 
 cleanAll :: IO ()
 cleanAll = do
-    d <- (</> ".atspkg") <$> getEnv "HOME"
+    d <- getAppUserDataDirectory "atspkg"
     b <- doesDirectoryExist d
     when b $ do
         putStrLn "Cleaning everything..."
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
@@ -21,44 +21,43 @@
 cfgFile :: String
 cfgFile = $(embedStringFile ("dhall" </> "config.dhall"))
 
-defaultFileConfig :: FilePath -> IO ()
-defaultFileConfig p = do
-    let dir = p </> ".config" </> "atspkg"
+defaultFileConfig :: IO ()
+defaultFileConfig = do
+    dir <- getXdgDirectory XdgConfig "atspkg"
     createDirectoryIfMissing True dir
     writeFile (dir </> "config.dhall") cfgFile
 
-cfgBin :: (MonadIO m) => m (FilePath, FilePath)
-cfgBin = liftIO io
-    where io = (id &&& (</> (".atspkg" </> "config"))) <$> getEnv "HOME"
+cfgBin :: (MonadIO m) => m FilePath
+cfgBin = liftIO $ getAppUserDataDirectory ("atspkg" </> "config")
 
 mkUserConfig :: Rules ()
 mkUserConfig = do
 
-    (h, cfgBin') <- cfgBin
+    cfgBin' <- cfgBin
 
     join (unless
         <$> liftIO (doesFileExist cfgBin')
-        <*> pure (g h cfgBin'))
+        <*> pure (g cfgBin'))
 
-    where g h cfgBin' = do
+    where g cfgBin' = do
 
-            let cfg = h </> ".config" </> "atspkg" </> "config.dhall"
+            cfg <- liftIO (getXdgDirectory XdgConfig ("atspkg" </> "config.dhall"))
 
             want [cfgBin']
 
-            readUserConfig h cfg
+            readUserConfig cfg
 
             cfgBin' %> \_ -> do
                 need [cfg]
                 cfgContents <- liftIO $ input auto (T.pack cfg)
                 liftIO $ BSL.writeFile cfgBin' (encode (cfgContents :: UserConfig))
 
-readUserConfig :: FilePath -> FilePath -> Rules ()
-readUserConfig h cfg = do
+readUserConfig :: FilePath -> Rules ()
+readUserConfig cfg = do
 
     want [cfg]
 
     e <- liftIO $ doesFileExist cfg
 
     cfg %> \_ -> unless e $
-        liftIO (defaultFileConfig h)
+        liftIO defaultFileConfig
diff --git a/src/Language/ATS/Package/Debian.hs b/src/Language/ATS/Package/Debian.hs
--- a/src/Language/ATS/Package/Debian.hs
+++ b/src/Language/ATS/Package/Debian.hs
@@ -11,7 +11,6 @@
                                    ) where
 
 import           Data.Dependency            (Version (..))
-import           Data.Hashable              (Hashable)
 import           Data.List                  (intercalate)
 import           Development.Shake          hiding ((*>))
 import           Development.Shake.FilePath
@@ -27,10 +26,9 @@
                      , binaries    :: [Text]
                      , libraries   :: [Text]
                      }
-                     deriving (Generic, Hashable, Binary, Interpret)
+                     deriving (Generic, Binary, Interpret)
 
 deriving newtype instance Interpret Version
-deriving newtype instance Hashable Version
 
 control :: Debian -> String
 control Debian{..} = intercalate "\n"
diff --git a/src/Language/ATS/Package/Generic.hs b/src/Language/ATS/Package/Generic.hs
deleted file mode 100644
--- a/src/Language/ATS/Package/Generic.hs
+++ /dev/null
@@ -1,50 +0,0 @@
-{-# LANGUAGE GADTs                      #-}
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-
--- | Module containing types and functions for generic package installs.
-module Language.ATS.Package.Generic ( GenericPackage (..)
-                                    , InstallDirs (..)
-                                    , Package (..)
-                                    , CacheValid
-                                    -- * Functions
-                                    , atsInstallDirs
-                                    ) where
-
-import           Control.Monad.Reader (ReaderT)
-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 -> String -> FilePath
-                                 , includeDeps :: a -> [FilePath]
-                                 , libDeps     :: a -> [FilePath]
-                                 }
-
--- | The default set of install directories for an ATS package.
-atsInstallDirs :: Hashable a => IO (InstallDirs a)
-atsInstallDirs = do
-    h <- getEnv "HOME"
-    let binDir' = h ++ "/.local/bin"
-        includeDir' = h ++ "/.atspkg/include"
-        libDeps' = ["/.atspkg/lib"]
-        includeDeps' = ["/.atspkg/include"]
-    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
--- dependencies.
-newtype Package a b = Package { unPack :: ReaderT (InstallDirs a) IO b }
-    deriving (Functor, Applicative, Monad)
-
--- | Any type implementing 'GenericPackage' can be depended on by other
--- packages.
-class Hashable a => GenericPackage a where
-
-    binRules :: a -> Package a ()
-    libRules :: a -> Package a ()
-    includeRules :: a -> Package a ()
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
@@ -25,7 +25,6 @@
                                  ) where
 
 import           Data.Dependency
-import           Data.Hashable               (Hashable)
 import           Development.Shake.ATS
 import           Language.ATS.Package.Debian
 import           Quaalude
@@ -33,7 +32,7 @@
 data ATSConstraint = ATSConstraint { lower :: Maybe Version
                                    , upper :: Maybe Version
                                    }
-                deriving (Eq, Show, Generic, Binary, Interpret, Hashable)
+                deriving (Eq, Show, Generic, Binary, Interpret)
 
 deriving newtype instance Inject Version
 
@@ -54,7 +53,7 @@
                                    , libCDeps    :: [LibDep] -- ^ C dependencies to be built
                                    , script      :: [Text] -- ^ Optional build script for C library
                                    }
-                   deriving (Generic, Interpret, Binary, Hashable)
+                   deriving (Generic, Interpret, Binary)
 
 dirLens :: Lens' ATSDependency Text
 dirLens f s = fmap (\x -> s { dir = x }) (f (dir s))
@@ -63,11 +62,10 @@
 data TargetPair = TargetPair { hs    :: Text
                              , ats   :: Text
                              , cpphs :: Bool
-                             } deriving (Generic, Interpret, Binary, Hashable)
+                             } deriving (Generic, Interpret, Binary)
 
 deriving instance Interpret ForeignCabal
 
-deriving instance Hashable Solver
 deriving instance Interpret Solver
 
 data Src = Src { atsSrc  :: Text
@@ -75,7 +73,7 @@
                , atsGen  :: [TargetPair]
                , extras  :: [Text]
                }
-         deriving (Generic, Interpret, Binary, Hashable)
+         deriving (Generic, Interpret, Binary)
 
 data Bin = Bin { src    :: Text -- ^ Source file (should end with @.dats@)
                , target :: Text -- ^ Binary to be built
@@ -85,7 +83,7 @@
                , gcBin  :: Bool -- ^ Whether to use the garbage collector
                , extras :: [Text] -- ^ Extra source files the build depends on
                }
-         deriving (Generic, Interpret, Binary, Hashable)
+         deriving (Generic, Interpret, Binary)
 
 data Lib = Lib { name      :: Text -- ^ Name of library being provided
                , src       :: [Text] -- ^ Source files (should end with @.dats@) to be compiled to object files
@@ -98,7 +96,7 @@
                , extras    :: [Text] -- ^ Other source files the build depends on
                , static    :: Bool -- ^ Whether to make a static library
                }
-         deriving (Generic, Interpret, Binary, Hashable)
+         deriving (Generic, Interpret, Binary)
 
 -- | Data type associated with @atspkg.dhall@ file.
 data Pkg = Pkg { bin          :: [Bin] -- ^ List of binaries to be built
@@ -120,4 +118,4 @@
                , debPkg       :: Maybe Debian -- ^ Optional specificiation as a debian package.
                , atsLib       :: Bool -- ^ Whether to link/build @atslib@.
                }
-         deriving (Generic, Interpret, Binary, Hashable)
+         deriving (Generic, Interpret, Binary)
