diff --git a/Cabal/Cabal.cabal b/Cabal/Cabal.cabal
index 0f2b6edef4c84d7d827d76eaa6c23170a890ee72..42731fd9b5228df7118bd6728b301e4efe5785f1 100644
--- a/Cabal/Cabal.cabal
+++ b/Cabal/Cabal.cabal
@@ -183,6 +183,7 @@ library
     Distribution.Simple.Program.Ar
     Distribution.Simple.Program.Builtin
     Distribution.Simple.Program.Db
+    Distribution.Simple.Program.Find
     Distribution.Simple.Program.GHC
     Distribution.Simple.Program.HcPkg
     Distribution.Simple.Program.Hpc
diff --git a/Cabal/Distribution/Simple/GHC.hs b/Cabal/Distribution/Simple/GHC.hs
index 0500465f661a07998cf7697b7a0427b7bf083b8b..ffc1bc7206b4dc9262e20512c3a5f2ab892d12b7 100644
--- a/Cabal/Distribution/Simple/GHC.hs
+++ b/Cabal/Distribution/Simple/GHC.hs
@@ -98,7 +98,8 @@ import Distribution.Package
 import qualified Distribution.ModuleName as ModuleName
 import Distribution.Simple.Program
          ( Program(..), ConfiguredProgram(..), ProgramConfiguration
-         , ProgramLocation(..), rawSystemProgram
+         , ProgramLocation(..), ProgramSearchPath
+         , rawSystemProgram
          , rawSystemProgramStdout, rawSystemProgramStdoutConf
          , getProgramInvocationOutput
          , requireProgramVersion, requireProgram, getProgramOutput
@@ -214,28 +215,30 @@ targetPlatform ghcInfo = platformFromTriple =<< lookup "Target platform" ghcInfo
 -- > /usr/local/bin/ghc-pkg-6.6.1(.exe)
 -- > /usr/local/bin/ghc-pkg(.exe)
 --
-guessToolFromGhcPath :: FilePath -> ConfiguredProgram -> Verbosity
+guessToolFromGhcPath :: Program -> ConfiguredProgram
+                     -> Verbosity -> ProgramSearchPath
                      -> IO (Maybe FilePath)
-guessToolFromGhcPath tool ghcProg verbosity
-  = do let path              = programPath ghcProg
+guessToolFromGhcPath tool ghcProg verbosity searchpath
+  = do let toolname          = programName tool
+           path              = programPath ghcProg
            dir               = takeDirectory path
            versionSuffix     = takeVersionSuffix (dropExeExtension path)
-           guessNormal       = dir </> tool <.> exeExtension
-           guessGhcVersioned = dir </> (tool ++ "-ghc" ++ versionSuffix)
+           guessNormal       = dir </> toolname <.> exeExtension
+           guessGhcVersioned = dir </> (toolname ++ "-ghc" ++ versionSuffix)
                                <.> exeExtension
-           guessVersioned    = dir </> (tool ++ versionSuffix) <.> exeExtension
+           guessVersioned    = dir </> (toolname ++ versionSuffix) <.> exeExtension
            guesses | null versionSuffix = [guessNormal]
                    | otherwise          = [guessGhcVersioned,
                                            guessVersioned,
                                            guessNormal]
-       info verbosity $ "looking for tool " ++ show tool
+       info verbosity $ "looking for tool " ++ toolname
          ++ " near compiler in " ++ dir
        exists <- mapM doesFileExist guesses
        case [ file | (file, True) <- zip guesses exists ] of
                    -- If we can't find it near ghc, fall back to the usual
                    -- method.
-         []     -> findProgramLocation verbosity tool
-         (fp:_) -> do info verbosity $ "found " ++ tool ++ " in " ++ fp
+         []     -> programFindLocation tool verbosity searchpath
+         (fp:_) -> do info verbosity $ "found " ++ toolname ++ " in " ++ fp
                       return (Just fp)
 
   where takeVersionSuffix :: FilePath -> String
@@ -256,8 +259,9 @@ guessToolFromGhcPath tool ghcProg verbosity
 -- > /usr/local/bin/ghc-pkg-6.6.1(.exe)
 -- > /usr/local/bin/ghc-pkg(.exe)
 --
-guessGhcPkgFromGhcPath :: ConfiguredProgram -> Verbosity -> IO (Maybe FilePath)
-guessGhcPkgFromGhcPath = guessToolFromGhcPath "ghc-pkg"
+guessGhcPkgFromGhcPath :: ConfiguredProgram
+                       -> Verbosity -> ProgramSearchPath -> IO (Maybe FilePath)
+guessGhcPkgFromGhcPath = guessToolFromGhcPath ghcPkgProgram
 
 -- | Given something like /usr/local/bin/ghc-6.6.1(.exe) we try and find a
 -- corresponding hsc2hs, we try looking for both a versioned and unversioned
@@ -267,8 +271,9 @@ guessGhcPkgFromGhcPath = guessToolFromGhcPath "ghc-pkg"
 -- > /usr/local/bin/hsc2hs-6.6.1(.exe)
 -- > /usr/local/bin/hsc2hs(.exe)
 --
-guessHsc2hsFromGhcPath :: ConfiguredProgram -> Verbosity -> IO (Maybe FilePath)
-guessHsc2hsFromGhcPath = guessToolFromGhcPath "hsc2hs"
+guessHsc2hsFromGhcPath :: ConfiguredProgram
+                       -> Verbosity -> ProgramSearchPath -> IO (Maybe FilePath)
+guessHsc2hsFromGhcPath = guessToolFromGhcPath hsc2hsProgram
 
 -- | Adjust the way we find and configure gcc and ld
 --
@@ -313,19 +318,19 @@ configureToolchain ghcProg ghcInfo =
     binPrefix   = ""
 
     -- on Windows finding and configuring ghc's gcc and ld is a bit special
-    findProg :: Program -> [FilePath] -> Verbosity -> IO (Maybe FilePath)
+    findProg :: Program -> [FilePath] -> Verbosity -> ProgramSearchPath -> IO (Maybe FilePath)
     findProg prog locations
       | isWindows = \verbosity -> look locations verbosity
       | otherwise = programFindLocation prog
       where
-        look [] verbosity = do
+        look [] verbosity searchpath = do
           warn verbosity ("Couldn't find " ++ programName prog
                           ++ " where I expected it. Trying the search path.")
-          programFindLocation prog verbosity
-        look (f:fs) verbosity = do
+          programFindLocation prog verbosity searchpath
+        look (f:fs) verbosity searchpath = do
           exists <- doesFileExist f
           if exists then return (Just f)
-                    else look fs verbosity
+                    else look fs verbosity searchpath
 
     ccFlags        = getFlags "C compiler flags"
     gccLinkerFlags = getFlags "Gcc Linker flags"
diff --git a/Cabal/Distribution/Simple/LHC.hs b/Cabal/Distribution/Simple/LHC.hs
index 6697de3bacce14af9627a326f84e71b518c6a91b..a0420de7096ae37a18316dcc8e76114bcf887460 100644
--- a/Cabal/Distribution/Simple/LHC.hs
+++ b/Cabal/Distribution/Simple/LHC.hs
@@ -90,8 +90,9 @@ import Distribution.Package
          ( Package(..) )
 import qualified Distribution.ModuleName as ModuleName
 import Distribution.Simple.Program
-         ( Program(..), ConfiguredProgram(..), ProgramConfiguration, ProgArg
-         , ProgramLocation(..), rawSystemProgram, rawSystemProgramConf
+         ( Program(..), ConfiguredProgram(..), ProgramConfiguration
+         , ProgramSearchPath, ProgramLocation(..)
+         , rawSystemProgram, rawSystemProgramConf
          , rawSystemProgramStdout, rawSystemProgramStdoutConf
          , requireProgramVersion
          , userMaybeSpecifyPath, programPath, lookupProgram, addKnownProgram
@@ -181,12 +182,13 @@ configureToolchain lhcProg =
     isWindows   = case buildOS of Windows -> True; _ -> False
 
     -- on Windows finding and configuring ghc's gcc and ld is a bit special
-    findProg :: Program -> FilePath -> Verbosity -> IO (Maybe FilePath)
-    findProg prog location | isWindows = \verbosity -> do
+    findProg :: Program -> FilePath
+             -> Verbosity -> ProgramSearchPath -> IO (Maybe FilePath)
+    findProg prog location | isWindows = \verbosity searchpath -> do
         exists <- doesFileExist location
         if exists then return (Just location)
                   else do warn verbosity ("Couldn't find " ++ programName prog ++ " where I expected it. Trying the search path.")
-                          programFindLocation prog verbosity
+                          programFindLocation prog verbosity searchpath
       | otherwise = programFindLocation prog
 
     configureGcc :: Verbosity -> ConfiguredProgram -> IO ConfiguredProgram
diff --git a/Cabal/Distribution/Simple/Program.hs b/Cabal/Distribution/Simple/Program.hs
index c57d5534d5fcc2a1c606e8294ffcd891ad8c6cc3..b43edc2e2a15286b8c79bf94ca0182c2ca15e738 100644
--- a/Cabal/Distribution/Simple/Program.hs
+++ b/Cabal/Distribution/Simple/Program.hs
@@ -35,6 +35,8 @@
 module Distribution.Simple.Program (
     -- * Program and functions for constructing them
       Program(..)
+    , ProgramSearchPath
+    , ProgramSearchPathEntry(..)
     , simpleProgram
     , findProgramLocation
     , findProgramVersion
@@ -67,6 +69,8 @@ module Distribution.Simple.Program (
     , addKnownPrograms
     , lookupKnownProgram
     , knownPrograms
+    , getProgramSearchPath
+    , setProgramSearchPath
     , userSpecifyPath
     , userSpecifyPaths
     , userMaybeSpecifyPath
diff --git a/Cabal/Distribution/Simple/Program/Builtin.hs b/Cabal/Distribution/Simple/Program/Builtin.hs
index 48446fab6cbbd5461bcdf54119f8417f699fd753..b8789ca4b14a3bd5959da2d592bc3556e09abac4 100644
--- a/Cabal/Distribution/Simple/Program/Builtin.hs
+++ b/Cabal/Distribution/Simple/Program/Builtin.hs
@@ -47,8 +47,10 @@ module Distribution.Simple.Program.Builtin (
 
 import Distribution.Simple.Program.Types
          ( Program(..), simpleProgram )
+import Distribution.Simple.Program.Find
+         ( findProgramOnSearchPath )
 import Distribution.Simple.Utils
-         ( findProgramLocation, findProgramVersion )
+         ( findProgramVersion )
 
 -- ------------------------------------------------------------
 -- * Known programs
@@ -233,7 +235,7 @@ cpphsProgram = (simpleProgram "cpphs") {
 
 hscolourProgram :: Program
 hscolourProgram = (simpleProgram "hscolour") {
-    programFindLocation = \v -> findProgramLocation v "HsColour",
+    programFindLocation = \v p -> findProgramOnSearchPath v p "HsColour",
     programFindVersion  = findProgramVersion "-version" $ \str ->
       -- Invoking "HsColour -version" gives a string like "HsColour 1.7"
       case words str of
diff --git a/Cabal/Distribution/Simple/Program/Db.hs b/Cabal/Distribution/Simple/Program/Db.hs
index c41897faccbd921bfc1888f6bb0dc93d579520c2..43678fcc1e470baf127065bb5d06f103d2b33152 100644
--- a/Cabal/Distribution/Simple/Program/Db.hs
+++ b/Cabal/Distribution/Simple/Program/Db.hs
@@ -32,6 +32,8 @@ module Distribution.Simple.Program.Db (
     addKnownPrograms,
     lookupKnownProgram,
     knownPrograms,
+    getProgramSearchPath,
+    setProgramSearchPath,
     userSpecifyPath,
     userSpecifyPaths,
     userMaybeSpecifyPath,
@@ -52,10 +54,13 @@ module Distribution.Simple.Program.Db (
 
 import Distribution.Simple.Program.Types
          ( Program(..), ProgArg, ConfiguredProgram(..), ProgramLocation(..) )
+import Distribution.Simple.Program.Find
+         ( ProgramSearchPath, defaultProgramSearchPath
+         , findProgramOnSearchPath, programSearchPathAsPATHVar )
 import Distribution.Simple.Program.Builtin
          ( builtinPrograms )
 import Distribution.Simple.Utils
-         ( die, findProgramLocation )
+         ( die )
 import Distribution.Version
          ( Version, VersionRange, isAnyVersion, withinRange )
 import Distribution.Text
@@ -88,6 +93,7 @@ import System.Directory
 -- 'Program' but also any user-provided arguments and location for the program.
 data ProgramDb = ProgramDb {
         unconfiguredProgs :: UnconfiguredProgs,
+        progSearchPath    :: ProgramSearchPath,
         configuredProgs   :: ConfiguredProgs
     }
 
@@ -97,8 +103,7 @@ type ConfiguredProgs     = Map.Map String ConfiguredProgram
 
 
 emptyProgramDb :: ProgramDb
-emptyProgramDb = ProgramDb Map.empty Map.empty
-
+emptyProgramDb = ProgramDb Map.empty defaultProgramSearchPath Map.empty
 
 defaultProgramDb :: ProgramDb
 defaultProgramDb = restoreProgramDb builtinPrograms emptyProgramDb
@@ -166,6 +171,21 @@ knownPrograms conf =
   [ (p,p') | (p,_,_) <- Map.elems (unconfiguredProgs conf)
            , let p' = Map.lookup (programName p) (configuredProgs conf) ]
 
+-- | Get the current 'ProgramSearchPath' used by the 'ProgramDb'.
+-- This is the default list of locations where programs are looked for when
+-- configuring them. This can be overriden for specific programs (with
+-- 'userSpecifyPath'), and specific known programs can modify or ignore this
+-- search path in their own configuration code.
+--
+getProgramSearchPath :: ProgramDb -> ProgramSearchPath
+getProgramSearchPath = progSearchPath
+
+-- | Change the current 'ProgramSearchPath' used by the 'ProgramDb'.
+-- This will affect programs that are configured from here on, so you
+-- should usually set it before configuring any programs.
+--
+setProgramSearchPath :: ProgramSearchPath -> ProgramDb -> ProgramDb
+setProgramSearchPath searchpath db = db { progSearchPath = searchpath }
 
 -- |User-specify this path.  Basically override any path information
 -- for this program in the configuration. If it's not a known
@@ -272,13 +292,13 @@ configureProgram :: Verbosity
 configureProgram verbosity prog conf = do
   let name = programName prog
   maybeLocation <- case userSpecifiedPath prog conf of
-    Nothing   -> programFindLocation prog verbosity
+    Nothing   -> programFindLocation prog verbosity (progSearchPath conf)
              >>= return . fmap FoundOnSystem
     Just path -> do
       absolute <- doesFileExist path
       if absolute
         then return (Just (UserSpecified path))
-        else findProgramLocation verbosity path
+        else findProgramOnSearchPath verbosity (progSearchPath conf) path
          >>= maybe (die notFound) (return . Just . UserSpecified)
       where notFound = "Cannot find the program '" ++ name ++ "' at '"
                      ++ path ++ "' or on the path"
@@ -286,12 +306,13 @@ configureProgram verbosity prog conf = do
     Nothing -> return conf
     Just location -> do
       version <- programFindVersion prog verbosity (locationPath location)
+      newPath <- programSearchPathAsPATHVar (progSearchPath conf)
       let configuredProg        = ConfiguredProgram {
             programId           = name,
             programVersion      = version,
             programDefaultArgs  = [],
             programOverrideArgs = userSpecifiedArgs prog conf,
-            programOverrideEnv  = [],
+            programOverrideEnv  = [("PATH", Just newPath)],
             programLocation     = location
           }
       configuredProg' <- programPostConf prog verbosity configuredProg
diff --git a/Cabal/Distribution/Simple/Program/Find.hs b/Cabal/Distribution/Simple/Program/Find.hs
new file mode 100644
index 0000000000000000000000000000000000000000..8e7b4eb334d8657a3e5b6998e0ac319a457a5d1e
--- /dev/null
+++ b/Cabal/Distribution/Simple/Program/Find.hs
@@ -0,0 +1,117 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Distribution.Simple.Program.Types
+-- Copyright   :  Duncan Coutts 2013
+--
+-- Maintainer  :  cabal-devel@haskell.org
+-- Portability :  portable
+--
+-- A somewhat extended notion of the normal program search path concept.
+--
+-- Usually when finding executables we just want to look in the usual places
+-- using the OS's usual method for doing so. In Haskell the normal OS-specific
+-- method is captured by 'findExecutable'. On all common OSs that makes use of
+-- a @PATH@ environment variable, (though on Windows it is not just the @PATH@).
+--
+-- However it is sometimes useful to be able to look in additional locations
+-- without having to change the process-global @PATH@ environment variable.
+-- So we need an extension of the usual 'findExecutable' that can look in
+-- additional locations, either before, after or instead of the normal OS
+-- locations.
+--
+module Distribution.Simple.Program.Find (
+    -- * Program search path
+    ProgramSearchPath,
+    ProgramSearchPathEntry(..),
+    defaultProgramSearchPath,
+    findProgramOnSearchPath,
+    programSearchPathAsPATHVar,
+  ) where
+
+import Distribution.Verbosity
+         ( Verbosity )
+import Distribution.Simple.Utils
+         ( debug )
+import Distribution.System
+         ( OS(..), buildOS )
+import System.Directory
+         ( findExecutable, doesFileExist, Permissions(..), getPermissions )
+import System.Environment
+         ( getEnvironment )
+import System.FilePath
+         ( (</>), (<.>), splitSearchPath, searchPathSeparator )
+import Data.List
+         ( intercalate )
+
+
+-- | A search path to use when locating executables. This is analagous
+-- to the unix @$PATH@ or win32 @%PATH%@ but with the ability to use
+-- the system default method for finding executables ('findExecutable' which
+-- on unix is simply looking on the @$PATH@ but on win32 is a bit more
+-- complicated).
+--
+-- The default to use is @[ProgSearchPathDefault]@ but you can add extra dirs
+-- either before, after or instead of the default, e.g. here we add an extra
+-- dir to search after the usual ones.
+--
+-- > ['ProgramSearchPathDefault', 'ProgramSearchPathDir' dir]
+--
+type ProgramSearchPath = [ProgramSearchPathEntry]
+data ProgramSearchPathEntry =
+         ProgramSearchPathDir FilePath  -- ^ A specific dir
+       | ProgramSearchPathDefault       -- ^ The system default
+
+defaultProgramSearchPath :: ProgramSearchPath
+defaultProgramSearchPath = [ProgramSearchPathDefault]
+
+findProgramOnSearchPath :: Verbosity -> ProgramSearchPath
+                        -> FilePath -> IO (Maybe FilePath)
+findProgramOnSearchPath verbosity searchpath prog = do
+    debug verbosity $ "Searching for " ++ prog ++ " in path."
+    res <- tryPathElems searchpath
+    case res of
+      Nothing   -> debug verbosity ("Cannot find " ++ prog ++ " on the path")
+      Just path -> debug verbosity ("Found " ++ prog ++ " at "++ path)
+    return res
+  where
+    tryPathElems []       = return Nothing
+    tryPathElems (pe:pes) = do
+      res <- tryPathElem pe
+      case res of
+        Nothing -> tryPathElems pes
+        Just _  -> return res
+
+    tryPathElem (ProgramSearchPathDir dir) =
+        findFirstExe [ dir </> prog <.> ext | ext <- extensions ]
+      where
+        extensions = case buildOS of
+                       Windows -> ["", "exe"]
+                       _       -> [""]
+
+    tryPathElem ProgramSearchPathDefault =
+      findExecutable prog
+
+    findFirstExe []     = return Nothing
+    findFirstExe (f:fs) = do
+      exists <- doesFileExist f
+      if exists
+        then do perms <- getPermissions f
+                if executable perms
+                  then return (Just f)
+                  else findFirstExe fs
+        else findFirstExe fs
+
+
+-- | Interpret a 'ProgramSearchPath' to construct a new @$PATH@ env var.
+-- Note that this is close but not perfect because on Windows the search
+-- algorithm looks at more than just the @%PATH%@.
+programSearchPathAsPATHVar :: ProgramSearchPath -> IO String
+programSearchPathAsPATHVar searchpath = do
+    ess <- mapM getEntries searchpath
+    return (intercalate [searchPathSeparator] (concat ess))
+  where
+    getEntries (ProgramSearchPathDir dir) = return [dir]
+    getEntries ProgramSearchPathDefault   = do
+      env <- getEnvironment
+      return (maybe [] splitSearchPath (lookup "PATH" env))
+
diff --git a/Cabal/Distribution/Simple/Program/Types.hs b/Cabal/Distribution/Simple/Program/Types.hs
index f816817626cd15e716af38596dd14f4e1a1e8d7a..1bf51ce082264c8304a5eb06324385b90363d65d 100644
--- a/Cabal/Distribution/Simple/Program/Types.hs
+++ b/Cabal/Distribution/Simple/Program/Types.hs
@@ -17,6 +17,8 @@
 module Distribution.Simple.Program.Types (
     -- * Program and functions for constructing them
     Program(..),
+    ProgramSearchPath,
+    ProgramSearchPathEntry(..),
     simpleProgram,
 
     -- * Configured program and related functions
@@ -27,8 +29,9 @@ module Distribution.Simple.Program.Types (
     simpleConfiguredProgram,
   ) where
 
-import Distribution.Simple.Utils
-         ( findProgramLocation )
+import Distribution.Simple.Program.Find
+         ( ProgramSearchPath, ProgramSearchPathEntry(..)
+         , findProgramOnSearchPath )
 import Distribution.Version
          ( Version )
 import Distribution.Verbosity
@@ -45,8 +48,11 @@ data Program = Program {
 
        -- | A function to search for the program if its location was not
        -- specified by the user. Usually this will just be a call to
-       -- @findProgramLocation@.
-       programFindLocation :: Verbosity -> IO (Maybe FilePath),
+       -- 'findProgramOnSearchPath'.
+       --
+       -- It is supplied with the prevailing search path which will typically
+       -- just be used as-is, but can be extended or ignored as needed.
+       programFindLocation :: Verbosity -> ProgramSearchPath -> IO (Maybe FilePath),
 
        -- | Try to find the version of the program. For many programs this is
        -- not possible or is not necessary so it's ok to return Nothing.
@@ -116,7 +122,7 @@ programPath = locationPath . programLocation
 simpleProgram :: String -> Program
 simpleProgram name = Program {
     programName         = name,
-    programFindLocation = \v   -> findProgramLocation v name,
+    programFindLocation = \v p -> findProgramOnSearchPath v p name,
     programFindVersion  = \_ _ -> return Nothing,
     programPostConf     = \_ p -> return p
   }