diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Aditya Siram (c) 2020
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * 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.
+
+    * Neither the name of Aditya Siram nor the names of other
+      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
+OWNER 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.org b/README.org
new file mode 100644
--- /dev/null
+++ b/README.org
@@ -0,0 +1,9 @@
+* cabal-build-programs
+  A Cabal library that allows build time dependencies on non-Haskell
+  executables. As of this writing there is no convenient Cabal field for
+  non-Haskell programs that are sometimes useful in a polyglot build like
+  'cmake' or 'gprof'. This library solves that by providing a custom Cabal field
+  "x-build-programs" which contains a list of such dependencies.
+
+  See the [[https://hackage.haskell.org/package/cabal-build-programs/docs/Distribution-Simple-BuildPrograms.html][Haddock documentation]] for much more detail.
+
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/cabal-build-programs.cabal b/cabal-build-programs.cabal
new file mode 100644
--- /dev/null
+++ b/cabal-build-programs.cabal
@@ -0,0 +1,39 @@
+cabal-version: 1.12
+
+-- This file has been generated from package.yaml by hpack version 0.31.2.
+--
+-- see: https://github.com/sol/hpack
+--
+-- hash: fc55553ca764af941d36f1d2ab303878f4af5e82f36b24cf7d98008ec0dbbc4e
+
+name:           cabal-build-programs
+version:        0.1.0.0
+synopsis:       Adds executable dependencies to the Cabal build
+description:    Please see the README on GitHub at <https://github.com/deech/cabal-build-programs#readme>
+category:       Distribution
+homepage:       https://github.com/deech/cabal-build-programs#readme
+bug-reports:    https://github.com/deech/cabal-build-programs/issues
+author:         Aditya Siram
+maintainer:     aditya.siram@gmail.com
+copyright:      Aditya Siram, 2019
+license:        BSD3
+license-file:   LICENSE
+build-type:     Simple
+extra-source-files:
+    README.org
+
+source-repository head
+  type: git
+  location: https://github.com/deech/cabal-build-programs
+
+library
+  exposed-modules:
+      Distribution.Simple.BuildPrograms
+  other-modules:
+      Paths_cabal_build_programs
+  hs-source-dirs:
+      src
+  build-depends:
+      Cabal >=2.2.0.0 && <4
+    , base >=4.7 && <5
+  default-language: Haskell2010
diff --git a/src/Distribution/Simple/BuildPrograms.hs b/src/Distribution/Simple/BuildPrograms.hs
new file mode 100644
--- /dev/null
+++ b/src/Distribution/Simple/BuildPrograms.hs
@@ -0,0 +1,376 @@
+{-# LANGUAGE ScopedTypeVariables #-}
+module Distribution.Simple.BuildPrograms
+    ( -- * Introduction
+      --
+      -- $introduction
+
+      -- * Why?
+      --
+      -- $why
+
+      -- * Getting Started
+      --
+      -- $gettingstarted
+
+      -- * Limitations
+      --
+      -- $limitations
+
+      -- * Stack & HPack Gotchas
+      --
+      -- $stackHPackGotchas
+
+      buildProgramsCustomField
+    , defaultMain
+    , buildProgramsUserHooks
+    , localBuildInfoWithBuildPrograms
+    , componentBuildPrograms
+    ) where
+
+import Distribution.Simple(UserHooks(..),simpleUserHooks, defaultMainWithHooks)
+import Distribution.Simple.Setup(BuildFlags(..), fromFlag,ReplFlags(..))
+import Distribution.Types.LocalBuildInfo(LocalBuildInfo(..), neededTargetsInBuildOrder')
+import Distribution.Types.PackageDescription(PackageDescription(..))
+import Distribution.Types.Component(Component(..), componentBuildInfo, componentName)
+import Distribution.Compat.Graph(nodeKey)
+import Distribution.Types.BuildInfo(BuildInfo(customFieldsBI))
+import Distribution.Types.TargetInfo(TargetInfo(..))
+import Distribution.Simple.UserHooks(Args)
+import Distribution.Simple.BuildTarget(readTargetInfos)
+import Data.List(concatMap,unfoldr,nub,intersperse)
+import Distribution.Verbosity(Verbosity)
+import Control.Exception(catch,IOException)
+import Control.Monad(foldM)
+import Distribution.Pretty(prettyShow)
+import Distribution.Simple.Program.Db(ProgramDb,requireProgram)
+import Distribution.Simple.Program.Types(simpleProgram, Program(programName))
+import Distribution.Simple.Utils(die')
+
+{-|
+The custom field to use in Cabal stanza to specify external programs.
+In a ~.cabal~ file use:
+
+@
+x-build-programs: p1,p2,p3
+@
+
+whereas in the ~package.yaml~ of a <https://docs.haskellstack.org/en/stable/README/ Stack> or <https://hackage.haskell.org/package/hpack hpack> project you must use
+(note that "p1,p2,p3" are quoted):
+
+@
+verbatim:
+  x-build-programs: "p1,p2,p3"
+@
+-}
+buildProgramsCustomField :: String
+buildProgramsCustomField = "x-build-programs"
+
+{-|
+This function is the easiest way to use this library in your @Setup.hs@.
+
+The default @Setup.hs@:
+
+@
+import Distribution.Simple
+main = defaultMain
+@
+
+becomes:
+
+@
+import Distribution.Simple.BuildPrograms -- <- only change
+main = defaultMain
+@
+
+-}
+defaultMain :: IO ()
+defaultMain = defaultMainWithHooks buildProgramsUserHooks
+
+{-|
+Directly access the 'UserHooks' that back 'defaultMain' when you need finer grained control, they are backed by 'simpleUserHooks':
+
+@
+import Distribution.Simple.BuildPrograms
+import Distribution.Simple(defaultMainWithHooks)
+main = defaultMainWithHooks buildProgramUserHooks
+@
+-}
+buildProgramsUserHooks :: UserHooks
+buildProgramsUserHooks = overlayUserHooks simpleUserHooks
+
+{-|
+If your @Setup.hs@ uses non-default or custom 'UserHooks' ,eg. 'autoconfUserHooks' this function will augment the 'buildHook' and 'replHook' to
+first check for the external programs.
+
+@
+import Distribution.Simple.BuildPrograms
+import Distribution.Simple(defaultMainWithHooks,autoconfUserHooks)
+main = defaultMainWithHooks (overlayUserHooks autoconfUserHooks)
+@
+-}
+overlayUserHooks :: UserHooks -> UserHooks
+overlayUserHooks hooksToOverlay =
+  let bh :: PackageDescription -> LocalBuildInfo -> UserHooks -> BuildFlags -> IO ()
+      bh pd lbi uhs bfs = do
+        newLbi <- localBuildInfoWithBuildPrograms (buildArgs bfs) (fromFlag (buildVerbosity bfs)) (hookedPrograms uhs) pd lbi
+        case newLbi of
+          Left err -> die' (fromFlag (buildVerbosity bfs)) err
+          Right newLbi' -> (buildHook hooksToOverlay) pd newLbi' uhs bfs
+      rh ::  PackageDescription -> LocalBuildInfo -> UserHooks -> ReplFlags -> [String] -> IO ()
+      rh pd lbi uhs rfs args = do
+        newLbi <- localBuildInfoWithBuildPrograms args (fromFlag (replVerbosity rfs)) (hookedPrograms uhs) pd lbi
+        case newLbi of
+          Left err -> die' (fromFlag (replVerbosity rfs)) err
+          Right newLbi' -> (replHook hooksToOverlay) pd newLbi' uhs rfs args
+  in hooksToOverlay { buildHook = bh , replHook = rh }
+
+splitProgramField :: String -> [String]
+splitProgramField =
+  let isComma t = t == ','
+      isCommaOrSpace t = t == ' ' || isComma t
+      split s =
+        if null s
+        then Nothing
+        else Just (break isComma (dropWhile isCommaOrSpace s))
+  in unfoldr split
+
+programs :: [(String,String)] -> [String]
+programs = nub . concatMap (splitProgramField . snd) . filter (\(field,_) -> field == buildProgramsCustomField)
+
+customFields :: TargetInfo -> [(String,String)]
+customFields = customFieldsBI . componentBuildInfo . targetComponent
+
+{-|
+Used internally it figures out which components to build, extracts the required
+external programs into a lookup table. To make debugging easier I made it public
+so you print the table.
+-}
+componentBuildPrograms :: Verbosity -> PackageDescription -> LocalBuildInfo -> Args -> IO [(Component, [String])]
+componentBuildPrograms verb pd lbi args =
+  let programFields :: TargetInfo -> (Component,[String])
+      programFields t = (targetComponent t, programs (customFields t))
+  in (map programFields . neededTargetsInBuildOrder' pd lbi . map nodeKey) <$> readTargetInfos verb pd lbi args
+
+{-|
+This is the lowest level function provided by this library for use in a highly
+customized @Setup.hs@ scripts. Most of the other functions wrap it in some way.
+
+'LocalBuildInfo' is a large datastructure that holds all the information
+required to build a project, this function gathers up only the components that
+need to be built ( or loaded in GHCi ), extracts the programs in the
+"x-build-programs" fields, checks that they exist and adds them as
+'ConfiguredProgram' to the 'ProgramDb' of the provided 'LocalBuildInfo' and
+returns a new 'LocalBuildInfo' with the new 'ProgramDb'.
+
+If any of the programs are cannot be found a formatted error message is returned.
+
+The expectation is that it is called from a 'buildHook' or a 'replHook' at some
+point before the components are built.
+-}
+localBuildInfoWithBuildPrograms  ::
+  Args -- ^ 'buildHook' ( extracted from 'BuildFlags') or 'replHook' arguments
+  -> Verbosity
+  -> [Program] -- ^ The 'hookedPrograms' from 'UserHooks', used to make sure we don't double check built-in build programs like 'c2hs' or 'ghc'
+  -> PackageDescription
+  -> LocalBuildInfo
+  -> IO (Either String LocalBuildInfo) -- ^ Local build info with the external build programs configured or an error message
+localBuildInfoWithBuildPrograms args verbosity hookedPs pd lbi =
+  let pdFields = programs (customFieldsPD pd)
+      combineAll :: [(Component, [String])] -> [(Maybe Component,[String])]
+      combineAll cs = [(Nothing,nub pdFields)] ++ map (\(c,ps) -> (Just c,ps)) cs
+      addOrLog :: [String] -> ProgramDb -> [String] -> IO ([String],ProgramDb)
+      addOrLog errsSoFar programDb =
+        foldM (\(errPs,db) p ->
+                 let logError = pure (errPs ++ [p], db)
+                 in
+                 if p `elem` errsSoFar
+                 then logError
+                 else
+                   if p `elem` (map programName hookedPs)
+                   then pure (errPs,db)
+                   else
+                     catch
+                       (do
+                         (_,newDb) <- requireProgram verbosity (simpleProgram p) db
+                         pure (errPs, newDb))
+                       (\(_ :: IOException) -> logError))
+              ([],programDb)
+      check :: [(Maybe Component,[String])] -> IO ([(Maybe Component, [String])],ProgramDb)
+      check =
+        foldM (\(compErrs,db) (comp,ps) -> do
+                  (errs,newDb) <- addOrLog (concatMap snd compErrs) db ps
+                  pure (compErrs ++ [(comp,errs)], newDb))
+              ([],withPrograms lbi)
+      compLabel :: Maybe Component -> String
+      compLabel Nothing = "global"
+      compLabel (Just c) = prettyShow (componentName c)
+      commaSep :: [String] -> String
+      commaSep = concat . intersperse ","
+      printErr :: (Maybe Component, [String]) -> String
+      printErr (comp,missing) = "- " ++ compLabel comp ++ ": " ++ commaSep missing
+  in do
+    allPrograms <- combineAll <$> componentBuildPrograms verbosity pd lbi args
+    (compErrs, newDb) <- check allPrograms
+    let errs = filter (not . null . snd) compErrs
+    pure $
+      if (not (null errs))
+      then Left $ "\n" ++ (unlines ("These build programs are required but could not be found:"
+                          : ("- " ++ (commaSep . nub . concatMap snd) errs)
+                          : "Broken down by build component: "
+                          : map printErr errs))
+      else Right $ lbi { withPrograms = newDb }
+
+-- $introduction
+-- This is a Cabal library that lets you annotate your
+-- @.cabal@ (or @package.yaml@) file with external programs that must be
+-- available at build time. It does this using a custom Cabal field,
+-- @x-build-programs@ which takes a list of executables that are checked
+-- whenever the project is built or when starting GHCi (unfortunately the
+-- latter does not work with Stack, see "Stack & HPack Gotchas" below). It can
+-- also be specified per build component (library, executables, benchmarks, test
+-- suite etc.) so that, for instance, a library does not have to depend on an
+-- external program used just for benchmarking (eg. 'gprof').
+
+-- $why
+-- This library exists because currently there is no field
+-- in Cabal that checks for the existence of non-Haskell programs (eg. '7z.exe'
+-- or 'cmake') at build time. The closest ,
+-- <https://www.haskell.org/cabal/users-guide/developing-packages.html#pkg-field-build-tool-depends 'build-tool-depends'>
+-- only allows Haskell-buildable exectuables like 'c2hs'.
+
+-- $gettingstarted
+-- First off you will need to set up a custom build in your @.cabal@:
+--
+-- @
+-- build-type:     Custom
+-- custom-setup
+--   setup-depends:
+--       Cabal >=2.2.0.0 && <4
+--     , base >=4.7 && <5
+--     , cabal-build-programs
+-- @
+--
+-- or @package.yaml@ file:
+--
+-- @
+-- build-type:          Custom
+-- custom-setup:
+--   dependencies:
+--   - base >= 4.7 && < 5
+--   - Cabal >= 2.2.0.0 && < 4
+--   - cabal-build-programs
+-- @
+--
+--
+-- Then add the external program dependencies, as in this example @package.yaml@:
+--
+-- @
+-- verbatim:
+--   x-build-programs: "cmake"
+--
+-- library:
+--   ...
+--   verbatim:
+--     x-build-programs: "llmv-config"
+--   when:
+--     - condition: os(windows)
+--       then:
+--         verbatim:
+--           x-build-programs: "7z.exe"
+--       else:
+--         verbatim:
+--           x-build-programs: "zip"
+--
+-- benchmarks:
+--   my-benchmarks:
+--     ...
+--     verbatim:
+--       x-build-programs: "gprof,valgrind"
+-- @
+--
+--
+-- A project that uses the snippet above always depends on @cmake@ no matter
+-- which artifact is being built but only the library needs @llvm-config@. On
+-- Windows the library needs @7z.exe@ for extracting archives, otherwise @zip@
+-- and the benchmarks always need the GNU profiling @gprof@ tool and @valgrind@.
+--
+-- Now we need a custom @Setup.hs@ that can use this library to check those
+-- dependencies.
+--
+-- The easiest way is to use the provided 'defaultMain'. For more advanced use
+-- check the docs for 'buildProgramsUserHooks' and
+-- 'localBuildInfoWithBuildPrograms'.
+--
+--
+
+-- $stackHPackGotchas
+-- <https://docs.haskellstack.org/en/stable/README/ Stack> and <https://github.com/sol/hpack Hpack> have
+-- are a few gotchas to keep in mind and since Stack uses HPack it inherits all the issues as well.
+--
+--    * Stack seems to completely ignore the 'preRepl' and 'replHook' so
+--      when using Stack external programs are not checked when using @stack
+--      ghci@ or @stack repl@, @stack build@ seems to work fine.
+--
+--   * HPack requires that all custom fields be in a "verbatim:" block
+--     so the first snippet below is rejected but the second is not:
+--
+-- @
+-- name:                my-awesome-program
+-- ...
+-- x-build-programs:    "cmake,gprof,someOtherDep"
+-- ...
+-- @
+--
+-- @
+-- name:                my-awesome-program
+-- ...
+-- verbatim:
+--   x-build-programs:  "cmake,gprof,someOtherDep"
+-- ...
+-- @
+--
+--   * Unlike Cabal, HPack will not accumulate across duplicate custom fields
+--     and picks the last one it encounters but only at the same level. For
+--     example in the first snippet (a) will be ignored by HPack and you will
+--     only see (b) in your @.cabal@ file. But in the second snippet since (a)
+--     is inside a conditional it does make it in. To be fair HPack
+--     will warn in the first case but it's pretty easy to miss.
+--
+-- @
+-- executables:
+--   my-awesome-executable
+--     main:                Main.hs
+--     verbatim:
+--       x-build-programs: "cmake,prof"   (a)
+--     ghc-options:
+--     - ...
+--     verbatim:
+--       x-build-programs: "someOtherDep" (b)
+-- @
+--
+-- @
+-- executables:
+--   my-awesome-executable
+--     main:                Main.hs
+--     when:
+--     - condition: os(linux)
+--       verbatim:
+--         x-build-programs: "cmake,prof" (a)
+--     ghc-options:
+--     - ...
+--     verbatim:
+--       x-build-programs: "someOtherDep" (b)
+-- @
+--
+
+-- $limitations
+-- The biggest limitations of this library is it cannot do any kind of version
+-- checking of external programs. For example, it is currently not possible to
+-- depend on eg. @cmake > 3.0.0@. It simply looks around in the environment for
+-- the first executable that matches the name.
+--
+-- The 'Program' datastructure provided by Cabal is a
+-- lot richer providing a way of extracting versions and doing some post
+-- configuration, see the builtin
+-- <https://hackage.haskell.org/package/Cabal-3.0.0.0/docs/Distribution-Simple-Program.html#v:tarProgram tar> as
+-- an example. But it is also more complicated use.
