diff --git a/shake-ext.cabal b/shake-ext.cabal
--- a/shake-ext.cabal
+++ b/shake-ext.cabal
@@ -1,6 +1,6 @@
 cabal-version: 1.18
 name: shake-ext
-version: 2.12.0.0
+version: 3.0.0.0
 license: BSD3
 license-file: LICENSE
 copyright: Copyright: (c) 2018 Vanessa McHale
@@ -32,22 +32,18 @@
         Development.Shake.Check
         Development.Shake.Clean
         Development.Shake.Version
-        Development.Shake.C
     hs-source-dirs: src
-    other-modules:
-        Development.Shake.TH
     default-language: Haskell2010
-    other-extensions: GeneralizedNewtypeDeriving PatternSynonyms
-                      TypeFamilies DeriveAnyClass DeriveGeneric DerivingStrategies
-                      TemplateHaskell RankNTypes
     ghc-options: -Wall
     build-depends:
-        base >=4.9 && <5,
-        cdeps -any,
-        composition-prelude -any,
+        base >=4.8 && <5,
         directory -any,
-        shake >=0.14,
-        template-haskell -any
+        shake >=0.14
+    
+    if !impl(ghc >=8.0)
+        build-depends:
+            transformers -any,
+            semigroups -any
     
     if flag(development)
         ghc-options: -Werror
diff --git a/src/Development/Shake/C.hs b/src/Development/Shake/C.hs
deleted file mode 100644
--- a/src/Development/Shake/C.hs
+++ /dev/null
@@ -1,269 +0,0 @@
-{-# 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
diff --git a/src/Development/Shake/Check.hs b/src/Development/Shake/Check.hs
--- a/src/Development/Shake/Check.hs
+++ b/src/Development/Shake/Check.hs
@@ -1,5 +1,3 @@
-{-# LANGUAGE TemplateHaskell #-}
-
 -- | Functions in this module check for the presence of various build tools.
 module Development.Shake.Check ( checkExecutable
                                -- * Helper functions for specific programs
@@ -10,14 +8,34 @@
                                , compleat
                                , cabal
                                , madlang
-                               -- * Types
-                               , MBool
                                ) where
 
-import           Development.Shake.TH
+import           Control.Monad.IO.Class
+import           Data.Maybe             (isJust)
+import           System.Directory       (findExecutable)
 
-$(mkExecChecks ["compleat", "pandoc", "autoconf", "cabal", "ghc", "madlang"])
+-- | Check for the presence of some executable.
+checkExecutable :: (MonadIO m) => String -> m Bool
+checkExecutable = fmap isJust . liftIO . findExecutable
 
+compleat :: MonadIO m => m Bool
+compleat = checkExecutable "compleat"
+
+cabal :: MonadIO m => m Bool
+cabal = checkExecutable "cabal"
+
+autoconf :: MonadIO m => m Bool
+autoconf = checkExecutable "autoconf"
+
+ghc :: MonadIO m => m Bool
+ghc = checkExecutable "ghc"
+
+pandoc :: MonadIO m => m Bool
+pandoc = checkExecutable "pandoc"
+
+madlang :: MonadIO m => m Bool
+madlang = checkExecutable "madlang"
+
 -- | Check for presence of @pats-filter@.
-patsFilter :: MBool
+patsFilter :: MonadIO m => m Bool
 patsFilter = checkExecutable "pats-filter"
diff --git a/src/Development/Shake/TH.hs b/src/Development/Shake/TH.hs
deleted file mode 100644
--- a/src/Development/Shake/TH.hs
+++ /dev/null
@@ -1,50 +0,0 @@
-{-# LANGUAGE RankNTypes      #-}
-{-# LANGUAGE TemplateHaskell #-}
-
-module Development.Shake.TH ( checkExecutable
-                            , mkVersions
-                            , mkExecChecks
-                            , commonVersion
-                            , MBool
-                            ) where
-
-import           Control.Monad.IO.Class
-import           Data.Maybe             (isJust)
-import           Development.Shake
-import           Language.Haskell.TH
-import           System.Directory       (findExecutable)
-
-type MBool = forall m. MonadIO m => m Bool
-
--- | Attempt to get version information from a given exectuable.
-commonVersion :: String -- ^ Executable name
-              -> Action String
-commonVersion prog = do
-    ~(Stdout out) <- command mempty prog ["--version"]
-    pure . last . words . head . lines $ out
-
-mkSigVersion :: String -> Dec
-mkSigVersion s = SigD (mkName $ s ++ "Version") (ConT ''Action `AppT` ConT ''String)
-
-mkVersion :: String -> Dec
-mkVersion s = FunD (mkName $ s ++ "Version") [Clause mempty (NormalB expr) mempty]
-    where expr = VarE 'commonVersion `AppE` (LitE $ StringL s)
-
-mkVersions :: [String] -> Q [Dec]
-mkVersions = pure . (g =<<)
-    where g s = [mkVersion s, mkSigVersion s]
-
-mkSig :: String -> Dec
-mkSig s = SigD (mkName s) (ConT ''MBool)
-
--- | Check for the presence of some executable.
-checkExecutable :: (MonadIO m) => String -> m Bool
-checkExecutable = fmap isJust . liftIO . findExecutable
-
-mkExecCheck :: String -> Dec
-mkExecCheck s = FunD (mkName s) [Clause mempty (NormalB expr) mempty]
-    where expr = VarE 'checkExecutable `AppE` (LitE $ StringL s)
-
-mkExecChecks :: [String] -> Q [Dec]
-mkExecChecks = pure . (=<<) g
-    where g s = [mkExecCheck s, mkSig s]
diff --git a/src/Development/Shake/Version.hs b/src/Development/Shake/Version.hs
--- a/src/Development/Shake/Version.hs
+++ b/src/Development/Shake/Version.hs
@@ -1,5 +1,3 @@
-{-# LANGUAGE TemplateHaskell #-}
-
 module Development.Shake.Version ( ghcVersion
                                  , cabalVersion
                                  , commonVersion
@@ -7,11 +5,21 @@
                                  ) where
 
 import           Development.Shake
-import           Development.Shake.TH
 
+-- | Attempt to get version information from a given exectuable.
+commonVersion :: String -- ^ Executable name
+              -> Action String
+commonVersion prog = do
+    ~(Stdout out) <- command [] prog ["--version"]
+    pure . last . words . head . lines $ out
+
 ghcVersion :: Action String
 ghcVersion = do
-    ~(Stdout o) <- command mempty "ghc" ["--numeric-version"]
+    ~(Stdout o) <- command [] "ghc" ["--numeric-version"]
     pure (head (lines o))
 
-$(mkVersions ["pandoc", "cabal"])
+cabalVersion :: Action String
+cabalVersion = commonVersion "cabal"
+
+pandocVersion :: Action String
+pandocVersion = commonVersion "pandoc"
