diff --git a/Distribution/Client/Check.hs b/Distribution/Client/Check.hs
--- a/Distribution/Client/Check.hs
+++ b/Distribution/Client/Check.hs
@@ -58,7 +58,7 @@
         printCheckMessages buildImpossible
 
     unless (null buildWarning) $ do
-        putStrLn "The following warnings are likely affect your build negatively:"
+        putStrLn "The following warnings are likely to affect your build negatively:"
         printCheckMessages buildWarning
 
     unless (null distSuspicious) $ do
diff --git a/Distribution/Client/CmdBuild.hs b/Distribution/Client/CmdBuild.hs
--- a/Distribution/Client/CmdBuild.hs
+++ b/Distribution/Client/CmdBuild.hs
@@ -8,7 +8,8 @@
 
 import Distribution.Client.ProjectOrchestration
          ( PreBuildHooks(..), runProjectPreBuildPhase, selectTargets
-         , ProjectBuildContext(..), runProjectBuildPhase,  printPlan )
+         , ProjectBuildContext(..), runProjectBuildPhase
+         , printPlan, reportBuildFailures )
 import Distribution.Client.ProjectConfig
          ( BuildTimeSettings(..) )
 import Distribution.Client.ProjectPlanning
@@ -52,10 +53,11 @@
 
     printPlan verbosity buildCtx
 
-    unless (buildSettingDryRun buildSettings) $
-      runProjectBuildPhase
-        verbosity
-        buildCtx
+    unless (buildSettingDryRun buildSettings) $ do
+      plan <- runProjectBuildPhase
+                verbosity
+                buildCtx
+      reportBuildFailures plan
   where
     verbosity = fromFlagOrDefault normal (configVerbosity configFlags)
 
diff --git a/Distribution/Client/CmdRepl.hs b/Distribution/Client/CmdRepl.hs
--- a/Distribution/Client/CmdRepl.hs
+++ b/Distribution/Client/CmdRepl.hs
@@ -8,7 +8,8 @@
 
 import Distribution.Client.ProjectOrchestration
          ( PreBuildHooks(..), runProjectPreBuildPhase, selectTargets
-         , ProjectBuildContext(..), runProjectBuildPhase,  printPlan )
+         , ProjectBuildContext(..), runProjectBuildPhase
+         , printPlan, reportBuildFailures )
 import Distribution.Client.ProjectConfig
          ( BuildTimeSettings(..) )
 import Distribution.Client.ProjectPlanning
@@ -56,10 +57,11 @@
 
     printPlan verbosity buildCtx
 
-    unless (buildSettingDryRun buildSettings) $
-      runProjectBuildPhase
-        verbosity
-        buildCtx
+    unless (buildSettingDryRun buildSettings) $ do
+      plan <- runProjectBuildPhase
+                verbosity
+                buildCtx
+      reportBuildFailures plan
   where
     verbosity = fromFlagOrDefault normal (configVerbosity configFlags)
 
diff --git a/Distribution/Client/Config.hs b/Distribution/Client/Config.hs
--- a/Distribution/Client/Config.hs
+++ b/Distribution/Client/Config.hs
@@ -58,7 +58,7 @@
          , ReportFlags(..), reportCommand
          , showRepo, parseRepo, readRepo )
 import Distribution.Utils.NubList
-         ( NubList, fromNubList, toNubList)
+         ( NubList, fromNubList, toNubList, overNubList )
 
 import Distribution.Simple.Compiler
          ( DebugInfoLevel(..), OptimisationLevel(..) )
@@ -104,7 +104,7 @@
 import Data.Maybe
          ( fromMaybe )
 import Control.Monad
-         ( when, unless, foldM, liftM, liftM2 )
+         ( when, unless, foldM, liftM )
 import qualified Distribution.Compat.ReadP as Parse
          ( (<++), option )
 import Distribution.Compat.Semigroup
@@ -438,7 +438,7 @@
   return mempty {
     savedGlobalFlags     = mempty {
       globalCacheDir     = toFlag cacheDir,
-      globalRemoteRepos  = toNubList [addInfoForKnownRepos defaultRemoteRepo],
+      globalRemoteRepos  = toNubList [defaultRemoteRepo],
       globalWorldFile    = toFlag worldFile
     },
     savedConfigureFlags  = mempty {
@@ -507,23 +507,91 @@
 -- we might have only have older info. This lets us fill that in even for old
 -- config files.
 --
--- TODO: Once we migrate from opt-in to opt-out security for the central
--- Hackage repository, we should enable security and specify keys and threshold
--- for repositories that have their security setting as 'Nothing' (default).
 addInfoForKnownRepos :: RemoteRepo -> RemoteRepo
-addInfoForKnownRepos repo@RemoteRepo{ remoteRepoName = "hackage.haskell.org" } =
-      tryHttps
-    $ if isOldHackageURI (remoteRepoURI repo) then defaultRemoteRepo else repo
+addInfoForKnownRepos repo
+  | remoteRepoName repo == remoteRepoName defaultRemoteRepo
+  = useSecure . tryHttps . fixOldURI $ repo
   where
+    fixOldURI r
+      | isOldHackageURI (remoteRepoURI r)
+                  = r { remoteRepoURI = remoteRepoURI defaultRemoteRepo }
+      | otherwise = r
+
     tryHttps r = r { remoteRepoShouldTryHttps = True }
+
+    useSecure r@RemoteRepo{
+                  remoteRepoSecure       = secure,
+                  remoteRepoRootKeys     = [],
+                  remoteRepoKeyThreshold = 0
+                } | secure /= Just False
+            = r {
+              --TODO: When we want to switch us from using opt-in to opt-out
+              -- security for the central hackage server, uncomment the
+              -- following line. That will cause the default (of unspecified)
+              -- to get interpreted as if it were "secure: True". For the
+              -- moment it means the keys get added but you have to manually
+              -- set "secure: True" to opt-in.
+              --remoteRepoSecure       = Just True,
+                remoteRepoRootKeys     = defaultHackageRemoteRepoKeys,
+                remoteRepoKeyThreshold = defaultHackageRemoteRepoKeyThreshold
+              }
+    useSecure r = r
 addInfoForKnownRepos other = other
 
+-- | The current hackage.haskell.org repo root keys that we ship with cabal.
+---
+-- This lets us bootstrap trust in this repo without user intervention.
+-- These keys need to be periodically updated when new root keys are added.
+-- See the root key procedures for details.
 --
+defaultHackageRemoteRepoKeys :: [String]
+defaultHackageRemoteRepoKeys =
+    [ "fe331502606802feac15e514d9b9ea83fee8b6ffef71335479a2e68d84adc6b0",
+      "1ea9ba32c526d1cc91ab5e5bd364ec5e9e8cb67179a471872f6e26f0ae773d42",
+      "2c6c3627bd6c982990239487f1abd02e08a02e6cf16edb105a8012d444d870c3",
+      "0a5c7ea47cd1b15f01f5f51a33adda7e655bc0f0b0615baa8e271f4c3351e21d",
+      "51f0161b906011b52c6613376b1ae937670da69322113a246a09f807c62f6921"
+    ]
+
+-- | The required threshold of root key signatures for hackage.haskell.org
+--
+defaultHackageRemoteRepoKeyThreshold :: Int
+defaultHackageRemoteRepoKeyThreshold = 3
+
+--
 -- * Config file reading
 --
 
+-- | Loads the main configuration, and applies additional defaults to give the
+-- effective configuration. To loads just what is actually in the config file,
+-- use 'loadRawConfig'.
+--
 loadConfig :: Verbosity -> Flag FilePath -> IO SavedConfig
-loadConfig verbosity configFileFlag = addBaseConf $ do
+loadConfig verbosity configFileFlag = do
+  config <- loadRawConfig verbosity configFileFlag
+  extendToEffectiveConfig config
+
+extendToEffectiveConfig :: SavedConfig -> IO SavedConfig
+extendToEffectiveConfig config = do
+  base <- baseSavedConfig
+  let effective0   = base `mappend` config
+      globalFlags0 = savedGlobalFlags effective0
+      effective  = effective0 {
+                     savedGlobalFlags = globalFlags0 {
+                       globalRemoteRepos =
+                         overNubList (map addInfoForKnownRepos)
+                                     (globalRemoteRepos globalFlags0)
+                     }
+                   }
+  return effective
+
+-- | Like 'loadConfig' but does not apply any additional defaults, it just
+-- loads what is actually in the config file. This is thus suitable for
+-- comparing or editing a config file, but not suitable for using as the
+-- effective configuration.
+--
+loadRawConfig :: Verbosity -> Flag FilePath -> IO SavedConfig
+loadRawConfig verbosity configFileFlag = do
   (source, configFile) <- getConfigFilePathAndSource configFileFlag
   minp <- readConfigFile mempty configFile
   case minp of
@@ -531,7 +599,6 @@
       notice verbosity $ "Config file path source is " ++ sourceMsg source ++ "."
       notice verbosity $ "Config file " ++ configFile ++ " not found."
       createDefaultConfigFile verbosity configFile
-      loadConfig verbosity configFileFlag
     Just (ParseOk ws conf) -> do
       unless (null ws) $ warn verbosity $
         unlines (map (showPWarning configFile) ws)
@@ -543,11 +610,6 @@
         ++ maybe "" (\n -> ':' : show n) line ++ ":\n" ++ msg
 
   where
-    addBaseConf body = do
-      base  <- baseSavedConfig
-      extra <- body
-      return (base `mappend` extra)
-
     sourceMsg CommandlineOption =   "commandline option"
     sourceMsg EnvironmentVariable = "env var CABAL_CONFIG"
     sourceMsg Default =             "default config file"
@@ -585,12 +647,13 @@
         then return Nothing
         else ioError ioe
 
-createDefaultConfigFile :: Verbosity -> FilePath -> IO ()
+createDefaultConfigFile :: Verbosity -> FilePath -> IO SavedConfig
 createDefaultConfigFile verbosity filePath = do
   commentConf <- commentSavedConfig
   initialConf <- initialSavedConfig
   notice verbosity $ "Writing default configuration to " ++ filePath
   writeConfigFile filePath commentConf initialConf
+  return initialConf
 
 writeConfigFile :: FilePath -> SavedConfig -> SavedConfig -> IO ()
 writeConfigFile file comments vals = do
@@ -854,8 +917,7 @@
           knownSections
 
   let remoteRepoSections =
-          map addInfoForKnownRepos
-        . reverse
+          reverse
         . nubBy ((==) `on` remoteRepoName)
         $ remoteRepoSections0
 
@@ -1026,7 +1088,7 @@
                            name  = fieldName field
                      , name `notElem` exclusions ]
   where
-    exclusions = ["verbose", "builddir"]
+    exclusions = ["verbose", "builddir", "for-hackage"]
 
 -- | Fields for the 'program-locations' section.
 withProgramsFields :: [FieldDescr [(String, FilePath)]]
@@ -1045,8 +1107,8 @@
 -- '~/.cabal/config' and the one that cabal would generate if it didn't exist.
 userConfigDiff :: GlobalFlags -> IO [String]
 userConfigDiff globalFlags = do
-  userConfig <- loadConfig normal (globalConfigFile globalFlags)
-  testConfig <- liftM2 mappend baseSavedConfig initialSavedConfig
+  userConfig <- loadRawConfig normal (globalConfigFile globalFlags)
+  testConfig <- initialSavedConfig
   return $ reverse . foldl' createDiff [] . M.toList
                 $ M.unionWith combine
                     (M.fromList . map justFst $ filterShow testConfig)
@@ -1090,8 +1152,8 @@
 -- | Update the user's ~/.cabal/config' keeping the user's customizations.
 userConfigUpdate :: Verbosity -> GlobalFlags -> IO ()
 userConfigUpdate verbosity globalFlags = do
-  userConfig <- loadConfig normal (globalConfigFile globalFlags)
-  newConfig <- liftM2 mappend baseSavedConfig initialSavedConfig
+  userConfig  <- loadRawConfig normal (globalConfigFile globalFlags)
+  newConfig   <- initialSavedConfig
   commentConf <- commentSavedConfig
   cabalFile <- getConfigFilePath $ globalConfigFile globalFlags
   let backup = cabalFile ++ ".backup"
diff --git a/Distribution/Client/GlobalFlags.hs b/Distribution/Client/GlobalFlags.hs
--- a/Distribution/Client/GlobalFlags.hs
+++ b/Distribution/Client/GlobalFlags.hs
@@ -250,8 +250,15 @@
     cache :: Sec.Cache
     cache = Sec.Cache {
         cacheRoot   = cachePath
-      , cacheLayout = Sec.cabalCacheLayout
+      , cacheLayout = Sec.cabalCacheLayout {
+            Sec.cacheLayoutIndexTar   = cacheFn "01-index.tar"
+          , Sec.cacheLayoutIndexIdx   = cacheFn "01-index.tar.idx"
+          , Sec.cacheLayoutIndexTarGz = cacheFn "01-index.tar.gz"
+          }
       }
+
+    cacheFn :: FilePath -> Sec.CachePath
+    cacheFn = Sec.rootPath . Sec.fragment
 
     -- We display any TUF progress only in verbose mode, including any transient
     -- verification errors. If verification fails, then the final exception that
diff --git a/Distribution/Client/HttpUtils.hs b/Distribution/Client/HttpUtils.hs
--- a/Distribution/Client/HttpUtils.hs
+++ b/Distribution/Client/HttpUtils.hs
@@ -363,6 +363,7 @@
                    , "--user-agent", userAgent
                    , "--silent", "--show-error"
                    , "--header", "Accept: text/plain"
+                   , "--location"
                    ]
         resp <- getProgramInvocationOutput verbosity $ addAuthConfig auth
                   (programInvocation prog args)
@@ -375,6 +376,7 @@
                    , "--write-out", "\n%{http_code}"
                    , "--user-agent", userAgent
                    , "--silent", "--show-error"
+                   , "--location"
                    , "--header", "Accept: text/plain"
                    ]
                 ++ concat
@@ -415,7 +417,7 @@
   where
     gethttp verbosity uri etag destPath reqHeaders = do
         resp <- runWGet verbosity uri args
-        (code, _err, etag') <- parseResponse uri resp
+        (code, etag') <- parseOutput uri resp
         return (code, etag')
       where
         args = [ "--output-document=" ++ destPath
@@ -433,31 +435,39 @@
 
     posthttpfile verbosity  uri path auth =
         withTempFile (takeDirectory path)
-                     (takeFileName path) $ \tmpFile tmpHandle -> do
+                     (takeFileName path) $ \tmpFile tmpHandle ->
+        withTempFile (takeDirectory path) "response" $ \responseFile responseHandle -> do
+          hClose responseHandle
           (body, boundary) <- generateMultipartBody path
           BS.hPut tmpHandle body
-          BS.writeFile "wget.in" body
           hClose tmpHandle
           let args = [ "--post-file=" ++ tmpFile
                      , "--user-agent=" ++ userAgent
                      , "--server-response"
+                     , "--output-document=" ++ responseFile
+                     , "--header=Accept: text/plain"
                      , "--header=Content-type: multipart/form-data; " ++
                                               "boundary=" ++ boundary ]
-          resp <- runWGet verbosity (addUriAuth auth uri) args
-          (code, err, _etag) <- parseResponse uri resp
-          return (code, err)
+          out <- runWGet verbosity (addUriAuth auth uri) args
+          (code, _etag) <- parseOutput uri out
+          resp <- readFile responseFile
+          return (code, resp)
 
-    puthttpfile verbosity uri path auth headers = do
-        let args = [ "--method=PUT", "--body-file="++path
-                   , "--user-agent=" ++ userAgent
-                   , "--server-response"
-                   , "--header=Accept: text/plain" ]
-                ++ [ "--header=" ++ show name ++ ": " ++ value
-                   | Header name value <- headers ]
+    puthttpfile verbosity uri path auth headers =
+        withTempFile (takeDirectory path) "response" $ \responseFile responseHandle -> do
+            hClose responseHandle
+            let args = [ "--method=PUT", "--body-file="++path
+                       , "--user-agent=" ++ userAgent
+                       , "--server-response"
+                       , "--output-document=" ++ responseFile
+                       , "--header=Accept: text/plain" ]
+                    ++ [ "--header=" ++ show name ++ ": " ++ value
+                       | Header name value <- headers ]
 
-        resp <- runWGet verbosity (addUriAuth auth uri) args
-        (code, err, _etag) <- parseResponse uri resp
-        return (code, err)
+            out <- runWGet verbosity (addUriAuth auth uri) args
+            (code, _etag) <- parseOutput uri out
+            resp <- readFile responseFile
+            return (code, resp)
 
     addUriAuth Nothing uri = uri
     addUriAuth (Just (user, pass)) uri = uri
@@ -487,23 +497,19 @@
     -- http server response with all headers, we want to find a line like
     -- "HTTP/1.1 200 OK", but only the last one, since we can have multiple
     -- requests due to redirects.
-    --
-    -- Unfortunately wget apparently cannot be persuaded to give us the body
-    -- of error responses, so we just return the human readable status message
-    -- like "Forbidden" etc.
-    parseResponse uri resp =
-      let codeerr = listToMaybe
-                    [ (code, unwords err)
-                    | (protocol:codestr:err) <- map words (reverse (lines resp))
-                    , "HTTP/" `isPrefixOf` protocol
-                    , code <- maybeToList (readMaybe codestr) ]
+    parseOutput uri resp =
+      let parsedCode = listToMaybe
+                     [ code
+                     | (protocol:codestr:_err) <- map words (reverse (lines resp))
+                     , "HTTP/" `isPrefixOf` protocol
+                     , code <- maybeToList (readMaybe codestr) ]
           mb_etag :: Maybe ETag
           mb_etag  = listToMaybe
                     [ etag
                     | ["ETag:", etag] <- map words (reverse (lines resp)) ]
-       in case codeerr of
-            Just (i, err) -> return (i, err, mb_etag)
-            _             -> statusParseFail uri resp
+       in case parsedCode of
+            Just i -> return (i, mb_etag)
+            _      -> statusParseFail uri resp
 
 
 powershellTransport :: ConfiguredProgram -> HttpTransport
diff --git a/Distribution/Client/IndexUtils.hs b/Distribution/Client/IndexUtils.hs
--- a/Distribution/Client/IndexUtils.hs
+++ b/Distribution/Client/IndexUtils.hs
@@ -88,7 +88,7 @@
 import Distribution.Client.Compat.Time (getFileAge, getModTime)
 import System.Directory (doesFileExist, doesDirectoryExist)
 import System.FilePath
-         ( (</>), takeExtension, replaceExtension, splitDirectories, normalise )
+         ( (</>), (<.>), takeExtension, replaceExtension, splitDirectories, normalise )
 import System.FilePath.Posix as FilePath.Posix
          ( takeFileName )
 import System.IO
@@ -107,6 +107,23 @@
   where
     verbosity'  = lessVerbose verbosity
 
+
+-- | Get filename base (i.e. without file extension) for index-related files
+--
+-- /Secure/ cabal repositories use a new extended & incremental
+-- @01-index.tar@. In order to avoid issues resulting from clobbering
+-- new/old-style index data, we save them locally to different names.
+--
+-- Example: Use @indexBaseName repo <.> "tar.gz"@ to compute the 'FilePath' of the
+-- @00-index.tar.gz@/@01-index.tar.gz@ file.
+indexBaseName :: Repo -> FilePath
+indexBaseName repo = repoLocalDir repo </> fn
+  where
+    fn = case repo of
+           RepoSecure {} -> "01-index"
+           RepoRemote {} -> "00-index"
+           RepoLocal  {} -> "00-index"
+
 ------------------------------------------------------------------------
 -- Reading the source package index
 --
@@ -204,15 +221,14 @@
 
 -- | Return the age of the index file in days (as a Double).
 getIndexFileAge :: Repo -> IO Double
-getIndexFileAge repo = getFileAge $ repoLocalDir repo </> "00-index.tar"
+getIndexFileAge repo = getFileAge $ indexBaseName repo <.> "tar"
 
 -- | A set of files (or directories) that can be monitored to detect when
 -- there might have been a change in the source packages.
 --
 getSourcePackagesMonitorFiles :: [Repo] -> [FilePath]
 getSourcePackagesMonitorFiles repos =
-    [ repoLocalDir repo </> "00-index.cache"
-    | repo <- repos ]
+    [ indexBaseName repo <.> "cache" | repo <- repos ]
 
 -- | It is not necessary to call this, as the cache will be updated when the
 -- index is read normally. However you can do the work earlier if you like.
@@ -384,11 +400,11 @@
   | SandboxIndex FilePath
 
 indexFile :: Index -> FilePath
-indexFile (RepoIndex _ctxt repo) = repoLocalDir repo </> "00-index.tar"
+indexFile (RepoIndex _ctxt repo) = indexBaseName repo <.> "tar"
 indexFile (SandboxIndex index)   = index
 
 cacheFile :: Index -> FilePath
-cacheFile (RepoIndex _ctxt repo) = repoLocalDir repo </> "00-index.cache"
+cacheFile (RepoIndex _ctxt repo) = indexBaseName repo <.> "cache"
 cacheFile (SandboxIndex index)   = index `replaceExtension` "cache"
 
 updatePackageIndexCacheFile :: Verbosity -> Index -> IO ()
diff --git a/Distribution/Client/PackageHash.hs b/Distribution/Client/PackageHash.hs
--- a/Distribution/Client/PackageHash.hs
+++ b/Distribution/Client/PackageHash.hs
@@ -16,6 +16,9 @@
     hashedInstalledPackageId,
     hashPackageHashInputs,
     renderPackageHashInputs,
+    -- ** Platform-specific variations
+    hashedInstalledPackageIdLong,
+    hashedInstalledPackageIdShort,
 
     -- * Low level hash choice
     HashValue,
@@ -26,9 +29,9 @@
   ) where
 
 import Distribution.Package
-         ( PackageId, mkUnitId )
+         ( PackageId, PackageIdentifier(..), mkUnitId )
 import Distribution.System
-         ( Platform )
+         ( Platform, OS(Windows), buildOS )
 import Distribution.PackageDescription
          ( FlagName(..), FlagAssignment )
 import Distribution.Simple.Compiler
@@ -65,12 +68,65 @@
 -- | Calculate a 'InstalledPackageId' for a package using our nix-style
 -- inputs hashing method.
 --
+-- Note that due to path length limitations on Windows, this function uses
+-- a different method on Windows that produces shorted package ids.
+-- See 'hashedInstalledPackageIdLong' vs 'hashedInstalledPackageIdShort'.
+--
 hashedInstalledPackageId :: PackageHashInputs -> InstalledPackageId
-hashedInstalledPackageId pkghashinputs@PackageHashInputs{pkgHashPkgId} =
+hashedInstalledPackageId
+  | buildOS == Windows = hashedInstalledPackageIdShort
+  | otherwise          = hashedInstalledPackageIdLong
+
+-- | Calculate a 'InstalledPackageId' for a package using our nix-style
+-- inputs hashing method.
+--
+-- This produces large ids with big hashes. It is only suitable for systems
+-- without significant path length limitations (ie not Windows).
+--
+hashedInstalledPackageIdLong :: PackageHashInputs -> InstalledPackageId
+hashedInstalledPackageIdLong pkghashinputs@PackageHashInputs{pkgHashPkgId} =
     mkUnitId $
          display pkgHashPkgId   -- to be a bit user friendly
       ++ "-"
       ++ showHashValue (hashPackageHashInputs pkghashinputs)
+
+-- | On Windows we have serious problems with path lengths. Windows imposes a
+-- maximum path length of 260 chars, and even if we can use the windows long
+-- path APIs ourselves, we cannot guarantee that ghc, gcc, ld, ar, etc etc all
+-- do so too.
+--
+-- So our only choice is to limit the lengths of the paths, and the only real
+-- way to do that is to limit the size of the 'InstalledPackageId's that we
+-- generate. We do this by truncating the package names and versions and also
+-- by truncating the hash sizes.
+--
+-- Truncating the package names and versions is technically ok because they are
+-- just included for human convenience, the full source package id is included
+-- in the hash.
+--
+-- Truncating the hash size is disappointing but also technically ok. We
+-- rely on the hash primarily for collision avoidance not for any securty
+-- properties (at least for now).
+--
+hashedInstalledPackageIdShort :: PackageHashInputs -> InstalledPackageId
+hashedInstalledPackageIdShort pkghashinputs@PackageHashInputs{pkgHashPkgId} =
+    mkUnitId $
+      intercalate "-"
+        -- max length now 64
+        [ truncateStr 14 (display name)
+        , truncateStr  8 (display version)
+        , showHashValue (truncateHash (hashPackageHashInputs pkghashinputs))
+        ]
+  where
+    PackageIdentifier name version = pkgHashPkgId
+
+    -- Truncate a 32 byte SHA256 hash to 160bits, 20 bytes :-(
+    -- It'll render as 40 hex chars.
+    truncateHash (HashValue h) = HashValue (BS.take 20 h)
+
+    -- Truncate a string, with a visual indication that it is truncated.
+    truncateStr n s | length s <= n = s
+                    | otherwise     = take (n-1) s ++ "_"
 
 -- | All the information that contribues to a package's hash, and thus its
 -- 'InstalledPackageId'.
diff --git a/Distribution/Client/ProjectBuilding.hs b/Distribution/Client/ProjectBuilding.hs
--- a/Distribution/Client/ProjectBuilding.hs
+++ b/Distribution/Client/ProjectBuilding.hs
@@ -1119,7 +1119,8 @@
         -- Configure phase
         --
         whenReConfigure $ do
-          setup configureCommand configureFlags []
+          annotateFailure ConfigureFailed $
+            setup configureCommand configureFlags []
           invalidatePackageRegFileMonitor packageFileMonitor
           updatePackageConfigFileMonitor packageFileMonitor srcdir pkg
 
@@ -1133,7 +1134,8 @@
 
         whenRebuild $ do
           timestamp <- beginUpdateFileMonitor
-          setup buildCommand buildFlags buildArgs
+          annotateFailure BuildFailed $
+            setup buildCommand buildFlags buildArgs
 
           --TODO: [required eventually] this doesn't track file
           --non-existence, so we could fail to rebuild if someone
@@ -1144,7 +1146,7 @@
                                         pkg buildStatus
                                         allSrcFiles buildSuccess
 
-        mipkg <- whenReRegister $ do
+        mipkg <- whenReRegister $ annotateFailure InstallFailed $ do
           -- Register locally
           mipkg <- if pkgRequiresRegistration pkg
             then do
@@ -1166,10 +1168,12 @@
         -- Repl phase
         --
         whenRepl $
+          annotateFailure BuildFailed $
           setup replCommand replFlags replArgs
 
         -- Haddock phase
         whenHaddock $
+          annotateFailure BuildFailed $
           setup haddockCommand haddockFlags []
 
         return (BuildSuccess mipkg buildSuccess)
@@ -1255,8 +1259,12 @@
     ]
   where
     handler :: Exception e => e -> IO a
-    handler = throwIO . annotate . show
-                       --TODO: [nice to have] use displayException when available
+    handler = throwIO . annotate
+#if MIN_VERSION_base(4,8,0)
+            . displayException
+#else
+            . show
+#endif
 
 
 withTempInstalledPackageInfoFile :: Verbosity -> FilePath
diff --git a/Distribution/Client/ProjectConfig.hs b/Distribution/Client/ProjectConfig.hs
--- a/Distribution/Client/ProjectConfig.hs
+++ b/Distribution/Client/ProjectConfig.hs
@@ -21,6 +21,7 @@
 
     -- * Packages within projects
     ProjectPackageLocation(..),
+    BadPackageLocations(..),
     BadPackageLocation(..),
     BadPackageLocationMatch(..),
     findProjectPackages,
diff --git a/Distribution/Client/ProjectOrchestration.hs b/Distribution/Client/ProjectOrchestration.hs
--- a/Distribution/Client/ProjectOrchestration.hs
+++ b/Distribution/Client/ProjectOrchestration.hs
@@ -50,6 +50,9 @@
 
     -- * Build phase: now do it.
     runProjectBuildPhase,
+
+    -- * Post build actions
+    reportBuildFailures,
   ) where
 
 import           Distribution.Client.ProjectConfig
@@ -83,6 +86,7 @@
 import           Data.Map (Map)
 import           Data.List
 import           Data.Either
+import           System.Exit (exitFailure)
 
 
 -- | Command line configuration flags. These are used to extend\/override the
@@ -190,16 +194,14 @@
 --
 runProjectBuildPhase :: Verbosity
                      -> ProjectBuildContext
-                     -> IO ()
-runProjectBuildPhase verbosity ProjectBuildContext {..} = do
-    _ <- rebuildTargets verbosity
-                        distDirLayout
-                        elaboratedPlan
-                        elaboratedShared
-                        pkgsBuildStatus
-                        buildSettings
-    --TODO return the result plan and use it for other status reporting
-    return ()
+                     -> IO ElaboratedInstallPlan
+runProjectBuildPhase verbosity ProjectBuildContext {..} =
+    rebuildTargets verbosity
+                   distDirLayout
+                   elaboratedPlan
+                   elaboratedShared
+                   pkgsBuildStatus
+                   buildSettings
 
     -- Note that it is a deliberate design choice that the 'buildTargets' is
     -- not passed to phase 1, and the various bits of input config is not
@@ -474,4 +476,18 @@
                      (InstallPlan.processing [pkg] plan)
     --TODO: [code cleanup] This is a bit of a hack, pretending that each package is installed
     -- could we use InstallPlan.topologicalOrder?
+
+
+reportBuildFailures :: ElaboratedInstallPlan -> IO ()
+reportBuildFailures plan =
+
+  case [ (pkg, reason)
+       | InstallPlan.Failed pkg reason <- InstallPlan.toList plan ] of
+    []      -> return ()
+    _failed -> exitFailure
+    --TODO: [required eventually] see the old printBuildFailures for an example
+    -- of the kind of things we could report, but we want to handle the special
+    -- case of the current package better, since if you do "cabal build" then
+    -- you don't need a lot of context to explain where the ghc error message
+    -- comes from, and indeed extra noise would just be annoying.
 
diff --git a/Distribution/Client/ProjectPlanning.hs b/Distribution/Client/ProjectPlanning.hs
--- a/Distribution/Client/ProjectPlanning.hs
+++ b/Distribution/Client/ProjectPlanning.hs
@@ -848,7 +848,7 @@
 
       . removeUpperBounds solverSettingAllowNewer
 
-      . addDefaultSetupDependencies (defaultSetupDeps platform
+      . addDefaultSetupDependencies (defaultSetupDeps comp platform
                                    . PD.packageDescription
                                    . packageDescription)
 
@@ -1681,8 +1681,10 @@
 -- we still need to distinguish the case of explicit and implict setup deps.
 -- See 'rememberImplicitSetupDeps'.
 --
-defaultSetupDeps :: Platform -> PD.PackageDescription -> Maybe [Dependency]
-defaultSetupDeps platform pkg =
+defaultSetupDeps :: Compiler -> Platform
+                 -> PD.PackageDescription
+                 -> Maybe [Dependency]
+defaultSetupDeps compiler platform pkg =
     case packageSetupScriptStylePreSolver pkg of
 
       -- For packages with build type custom that do not specify explicit
@@ -1691,26 +1693,30 @@
       SetupCustomImplicitDeps ->
         Just $
         [ Dependency depPkgname anyVersion
-        | depPkgname <- legacyCustomSetupPkgs platform ] ++
-        -- The Cabal dep is slightly special:
-        --  * we omit the dep for the Cabal lib itself (since it bootstraps),
-        --  * we constrain it to be less than 1.23 since all packages
-        --    relying on later Cabal spec versions are supposed to use
-        --    explit setup deps. Having this constraint also allows later
-        --    Cabal lib versions to make breaking API changes without breaking
-        --    all old Setup.hs scripts.
+        | depPkgname <- legacyCustomSetupPkgs compiler platform ] ++
         [ Dependency cabalPkgname cabalConstraint
         | packageName pkg /= cabalPkgname ]
         where
-          cabalConstraint   = orLaterVersion (PD.specVersion pkg)
+          -- The Cabal dep is slightly special:
+          -- * We omit the dep for the Cabal lib itself, since it bootstraps.
+          -- * We constrain it to be >= 1.18 < 2
+          --
+          cabalConstraint   = orLaterVersion cabalCompatMinVer
                                 `intersectVersionRanges`
+                              orLaterVersion (PD.specVersion pkg)
+                                `intersectVersionRanges`
                               earlierVersion cabalCompatMaxVer
-        -- TODO/FIXME: turns out that constraining to less than 1.23 causes
-        --             problems with GHC8 as there's too many important packages
-        --             with Custom build-type, for which there wouldn't be any
-        --             install-plan (as GHC8 requires Cabal-1.24+). So let's
-        --             set an implicit upper bound `Cabal < 2` instead.
-          cabalCompatMaxVer = Version [2] []
+          -- The idea here is that at some point we will make significant
+          -- breaking changes to the Cabal API that Setup.hs scripts use.
+          -- So for old custom Setup scripts that do not specify explicit
+          -- constraints, we constrain them to use a compatible Cabal version.
+          cabalCompatMaxVer = Version [1,25] []
+          -- In principle we can talk to any old Cabal version, and we need to
+          -- be able to do that for custom Setup scripts that require older
+          -- Cabal lib versions. However in practice we have currently have
+          -- problems with Cabal-1.16. (1.16 does not know about build targets)
+          -- If this is fixed we can relax this constraint.
+          cabalCompatMinVer = Version [1,18] []
 
       -- For other build types (like Simple) if we still need to compile an
       -- external Setup.hs, it'll be one of the simple ones that only depends
@@ -1822,14 +1828,25 @@
 basePkgname  = PackageName "base"
 
 
-legacyCustomSetupPkgs :: Platform -> [PackageName]
-legacyCustomSetupPkgs (Platform _ os) =
+legacyCustomSetupPkgs :: Compiler -> Platform -> [PackageName]
+legacyCustomSetupPkgs compiler (Platform _ os) =
     map PackageName $
         [ "array", "base", "binary", "bytestring", "containers"
-        , "deepseq", "directory", "filepath", "pretty"
-        , "process", "time" ]
+        , "deepseq", "directory", "filepath", "old-time", "pretty"
+        , "process", "time", "transformers" ]
      ++ [ "Win32" | os == Windows ]
      ++ [ "unix"  | os /= Windows ]
+     ++ [ "ghc-prim"         | isGHC ]
+     ++ [ "template-haskell" | isGHC ]
+  where
+    isGHC = compilerCompatFlavor GHC compiler
+
+    -- This util is copied here just in this branch to avoid requiring a new
+    -- Cabal version. The master branch already does the right thing.
+    compilerCompatFlavor :: CompilerFlavor -> Compiler -> Bool
+    compilerCompatFlavor flavor comp =
+        flavor == compilerFlavor comp
+     || flavor `elem` [ flavor' | CompilerId flavor' _ <- compilerCompat comp ]
 
 -- The other aspects of our Setup.hs policy lives here where we decide on
 -- the 'SetupScriptOptions'.
diff --git a/Distribution/Client/Setup.hs b/Distribution/Client/Setup.hs
--- a/Distribution/Client/Setup.hs
+++ b/Distribution/Client/Setup.hs
@@ -73,6 +73,7 @@
          ( defaultProgramConfiguration )
 import Distribution.Simple.Command hiding (boolOpt, boolOpt')
 import qualified Distribution.Simple.Command as Command
+import Distribution.Simple.Configure ( computeEffectiveProfiling )
 import qualified Distribution.Simple.Setup as Cabal
 import Distribution.Simple.Setup
          ( ConfigFlags(..), BuildFlags(..), ReplFlags
@@ -83,7 +84,7 @@
          , optionVerbosity, boolOpt, boolOpt', trueArg, falseArg
          , readPToMaybe, optionNumJobs )
 import Distribution.Simple.InstallDirs
-         ( PathTemplate, InstallDirs(sysconfdir)
+         ( PathTemplate, InstallDirs(dynlibdir, sysconfdir)
          , toPathTemplate, fromPathTemplate )
 import Distribution.Version
          ( Version(Version), anyVersion, thisVersion )
@@ -349,7 +350,7 @@
 
 filterConfigureFlags :: ConfigFlags -> Version -> ConfigFlags
 filterConfigureFlags flags cabalLibVersion
-  | cabalLibVersion >= Version [1,23,0] [] = flags_latest
+  | cabalLibVersion >= Version [1,24,1] [] = flags_latest
   -- ^ NB: we expect the latest version to be the most common case.
   | cabalLibVersion <  Version [1,3,10] [] = flags_1_3_10
   | cabalLibVersion <  Version [1,10,0] [] = flags_1_10_0
@@ -361,8 +362,10 @@
   | cabalLibVersion <  Version [1,21,1] [] = flags_1_20_0
   | cabalLibVersion <  Version [1,22,0] [] = flags_1_21_0
   | cabalLibVersion <  Version [1,23,0] [] = flags_1_22_0
+  | cabalLibVersion <  Version [1,24,1] [] = flags_1_24_0
   | otherwise = flags_latest
   where
+    (profEnabledLib, profEnabledExe) = computeEffectiveProfiling flags
     flags_latest = flags        {
       -- Cabal >= 1.19.1 uses '--dependency' and does not need '--constraint'.
       configConstraints = [],
@@ -371,22 +374,29 @@
       configAllowNewer  = Just Cabal.AllowNewerNone
       }
 
+    -- Cabal < 1.24.1 doesn't know about --dynlibdir.
+    flags_1_24_0 = flags_latest { configInstallDirs = configInstallDirs_1_24_0}
+    configInstallDirs_1_24_0 = (configInstallDirs flags) { dynlibdir = NoFlag }
+
     -- Cabal < 1.23 doesn't know about '--profiling-detail'.
-    flags_1_22_0 = flags_latest { configProfDetail    = NoFlag
+    -- Cabal < 1.23 has a hacked up version of 'enable-profiling'
+    -- which we shouldn't use.
+    flags_1_22_0 = flags_1_24_0 { configProfDetail    = NoFlag
                                 , configProfLibDetail = NoFlag
-                                , configIPID          = NoFlag }
+                                , configIPID          = NoFlag
+                                , configProf          = NoFlag
+                                , configProfExe       = Flag profEnabledExe
+                                , configProfLib       = Flag profEnabledLib
+                                }
 
     -- Cabal < 1.22 doesn't know about '--disable-debug-info'.
     flags_1_21_0 = flags_1_22_0 { configDebugInfo = NoFlag }
 
     -- Cabal < 1.21.1 doesn't know about 'disable-relocatable'
     -- Cabal < 1.21.1 doesn't know about 'enable-profiling'
+    -- (but we already dealt with it in flags_1_22_0)
     flags_1_20_0 =
       flags_1_21_0 { configRelocatable = NoFlag
-                   , configProf = NoFlag
-                   , configProfExe = configProf flags
-                   , configProfLib =
-                     mappend (configProf flags) (configProfLib flags)
                    , configCoverage = NoFlag
                    , configLibCoverage = configCoverage flags
                    }
@@ -400,7 +410,7 @@
     -- Cabal < 1.18.0 doesn't know about --extra-prog-path and --sysconfdir.
     flags_1_18_0 = flags_1_19_0 { configProgramPathExtra = toNubList []
                                 , configInstallDirs = configInstallDirs_1_18_0}
-    configInstallDirs_1_18_0 = (configInstallDirs flags) { sysconfdir = NoFlag }
+    configInstallDirs_1_18_0 = (configInstallDirs flags_1_19_0) { sysconfdir = NoFlag }
     -- Cabal < 1.14.0 doesn't know about '--disable-benchmarks'.
     flags_1_14_0 = flags_1_18_0 { configBenchmarks  = NoFlag }
     -- Cabal < 1.12.0 doesn't know about '--enable/disable-executable-dynamic'
diff --git a/Distribution/Client/SetupWrapper.hs b/Distribution/Client/SetupWrapper.hs
--- a/Distribution/Client/SetupWrapper.hs
+++ b/Distribution/Client/SetupWrapper.hs
@@ -105,7 +105,7 @@
 import Data.Monoid         ( mempty )
 #endif
 import Control.Monad       ( when, unless )
-import Data.List           ( foldl1' )
+import Data.List           ( find, foldl1' )
 import Data.Maybe          ( fromMaybe, isJust )
 import Data.Char           ( isSpace )
 import Distribution.Client.Compat.ExecutablePath  ( getExecutablePath )
@@ -381,26 +381,45 @@
       Nothing    -> getInstalledPackages verbosity
                     comp (usePackageDB options') conf
 
-  cabalLibVersionToUse :: IO (Version, (Maybe UnitId)
+  -- Choose the version of Cabal to use if the setup script has a dependency on
+  -- Cabal, and possibly update the setup script options. The version also
+  -- determines how to filter the flags to Setup.
+  --
+  -- We first check whether the dependency solver has specified a Cabal version.
+  -- If it has, we use the solver's version without looking at the installed
+  -- package index (See issue #3436). Otherwise, we pick the Cabal version by
+  -- checking 'useCabalSpecVersion', then the saved version, and finally the
+  -- versions available in the index.
+  --
+  -- The version chosen here must match the one used in 'compileSetupExecutable'
+  -- (See issue #3433).
+  cabalLibVersionToUse :: IO (Version, Maybe UnitId
                              ,SetupScriptOptions)
   cabalLibVersionToUse =
-    case useCabalSpecVersion options of
-      Just version -> do
+    case find (hasCabal . snd) (useDependencies options) of
+      Just (unitId, pkgId) -> do
+        let version = pkgVersion pkgId
         updateSetupScript version bt
-        writeFile setupVersionFile (show version ++ "\n")
-        return (version, Nothing, options)
-      Nothing  -> do
-        savedVer <- savedVersion
-        case savedVer of
-          Just version | version `withinRange` useCabalVersion options
-            -> do updateSetupScript version bt
-                  -- Does the previously compiled setup executable still exist
-                  -- and is it up-to date?
-                  useExisting <- canUseExistingSetup version
-                  if useExisting
-                    then return (version, Nothing, options)
-                    else installedVersion
-          _ -> installedVersion
+        writeSetupVersionFile version
+        return (version, Just unitId, options)
+      Nothing ->
+        case useCabalSpecVersion options of
+          Just version -> do
+            updateSetupScript version bt
+            writeSetupVersionFile version
+            return (version, Nothing, options)
+          Nothing  -> do
+            savedVer <- savedVersion
+            case savedVer of
+              Just version | version `withinRange` useCabalVersion options
+                -> do updateSetupScript version bt
+                      -- Does the previously compiled setup executable still exist
+                      -- and is it up-to date?
+                      useExisting <- canUseExistingSetup version
+                      if useExisting
+                        then return (version, Nothing, options)
+                        else installedVersion
+              _ -> installedVersion
     where
       -- This check duplicates the checks in 'getCachedSetupExecutable' /
       -- 'compileSetupExecutable'. Unfortunately, we have to perform it twice
@@ -416,13 +435,20 @@
           (&&) <$> setupProgFile `existsAndIsMoreRecentThan` setupHs
                <*> setupProgFile `existsAndIsMoreRecentThan` setupVersionFile
 
+      writeSetupVersionFile :: Version -> IO ()
+      writeSetupVersionFile version =
+          writeFile setupVersionFile (show version ++ "\n")
+
+      hasCabal (PackageIdentifier (PackageName "Cabal") _) = True
+      hasCabal _                                           = False
+
       installedVersion :: IO (Version, Maybe UnitId
                              ,SetupScriptOptions)
       installedVersion = do
         (comp,    conf,    options')  <- configureCompiler options
         (version, mipkgid, options'') <- installedCabalVersion options' comp conf
         updateSetupScript version bt
-        writeFile setupVersionFile (show version ++ "\n")
+        writeSetupVersionFile version
         return (version, mipkgid, options'')
 
       savedVersion :: IO (Maybe Version)
diff --git a/Distribution/Client/SrcDist.hs b/Distribution/Client/SrcDist.hs
--- a/Distribution/Client/SrcDist.hs
+++ b/Distribution/Client/SrcDist.hs
@@ -90,6 +90,7 @@
     distPref        = fromFlag (sDistDistPref flags)
     tmpTargetDir    = fromFlagOrDefault (srcPref distPref) (sDistDirectory flags)
     setupOpts       = defaultSetupScriptOptions {
+      useDistPref     = distPref,
       -- The '--output-directory' sdist flag was introduced in Cabal 1.12, and
       -- '--list-sources' in 1.17.
       useCabalVersion = if isListSources
diff --git a/Main.hs b/Main.hs
--- a/Main.hs
+++ b/Main.hs
@@ -46,7 +46,8 @@
          , manpageCommand
          )
 import Distribution.Simple.Setup
-         ( HaddockFlags(..), haddockCommand, defaultHaddockFlags
+         ( HaddockTarget(..)
+         , HaddockFlags(..), haddockCommand, defaultHaddockFlags
          , HscolourFlags(..), hscolourCommand
          , ReplFlags(..)
          , CopyFlags(..), copyCommand
@@ -179,7 +180,8 @@
 import Data.Monoid              (Monoid(..))
 import Control.Applicative      (pure, (<$>))
 #endif
-import Control.Monad            (when, unless)
+import Control.Exception        (SomeException(..), try)
+import Control.Monad            (when, unless, void)
 
 -- | Entry point
 --
@@ -311,7 +313,8 @@
   commandAddAction command
     { commandDefaultFlags = mempty } $ \flags extraArgs globalFlags -> do
     let verbosity = fromFlagOrDefault normal (verbosityFlag flags)
-    (_, config) <- loadConfigOrSandboxConfig verbosity globalFlags
+    load <- try (loadConfigOrSandboxConfig verbosity globalFlags)
+    let config = either (\(SomeException _) -> mempty) snd load
     distPref <- findSavedDistPref config (distPrefFlag flags)
     let setupScriptOptions = defaultSetupScriptOptions { useDistPref = distPref }
     setupWrapper verbosity setupScriptOptions Nothing
@@ -695,7 +698,8 @@
 installAction (configFlags, _, installFlags, _) _ globalFlags
   | fromFlagOrDefault False (installOnly installFlags) = do
       let verbosity = fromFlagOrDefault normal (configVerbosity configFlags)
-      (_, config) <- loadConfigOrSandboxConfig verbosity globalFlags
+      load <- try (loadConfigOrSandboxConfig verbosity globalFlags)
+      let config = either (\(SomeException _) -> mempty) snd load
       distPref <- findSavedDistPref config (configDistPref configFlags)
       let setupOpts = defaultSetupScriptOptions { useDistPref = distPref }
       setupWrapper verbosity setupOpts Nothing installCommand (const mempty) []
@@ -901,7 +905,7 @@
       setupScriptOptions = defaultSetupScriptOptions { useDistPref = distPref }
   setupWrapper verbosity setupScriptOptions Nothing
     haddockCommand (const haddockFlags') extraArgs
-  when (fromFlagOrDefault False $ haddockForHackage haddockFlags) $ do
+  when (haddockForHackage haddockFlags == Flag ForHackage) $ do
     pkg <- fmap LBI.localPkgDescr (getPersistBuildConfig distPref)
     let dest = distPref </> name <.> "tar.gz"
         name = display (packageId pkg) ++ "-docs"
@@ -911,7 +915,8 @@
 
 cleanAction :: CleanFlags -> [String] -> Action
 cleanAction cleanFlags extraArgs globalFlags = do
-  (_, config) <- loadConfigOrSandboxConfig verbosity globalFlags
+  load <- try (loadConfigOrSandboxConfig verbosity globalFlags)
+  let config = either (\(SomeException _) -> mempty) snd load
   distPref <- findSavedDistPref config (cleanDistPref cleanFlags)
   let setupScriptOptions = defaultSetupScriptOptions
                            { useDistPref = distPref
@@ -1101,9 +1106,13 @@
               (file', ".gz") -> takeExtension file' == ".tar"
               _              -> False
     generateDocTarball config = do
-      notice verbosity
-        "No documentation tarball specified. Building documentation tarball..."
-      haddockAction (defaultHaddockFlags { haddockForHackage = Flag True })
+      notice verbosity $
+        "No documentation tarball specified. "
+        ++ "Building a documentation tarball with default settings...\n"
+        ++ "If you need to customise Haddock options, "
+        ++ "run 'haddock --for-hackage' first "
+        ++ "to generate a documentation tarball."
+      haddockAction (defaultHaddockFlags { haddockForHackage = Flag ForHackage })
                     [] globalFlags
       distPref <- findSavedDistPref config NoFlag
       pkg <- fmap LBI.localPkgDescr (getPersistBuildConfig distPref)
@@ -1144,7 +1153,8 @@
   unless (null extraArgs) $
     die $ "'sdist' doesn't take any extra arguments: " ++ unwords extraArgs
   let verbosity = fromFlag (sDistVerbosity sdistFlags)
-  (_, config) <- loadConfigOrSandboxConfig verbosity globalFlags
+  load <- try (loadConfigOrSandboxConfig verbosity globalFlags)
+  let config = either (\(SomeException _) -> mempty) snd load
   distPref <- findSavedDistPref config (sDistDistPref sdistFlags)
   let sdistFlags' = sdistFlags { sDistDistPref = toFlag distPref }
   sdist sdistFlags' sdistExFlags
@@ -1274,7 +1284,7 @@
       path       <- configFile
       fileExists <- doesFileExist path
       if (not fileExists || (fileExists && force))
-      then createDefaultConfigFile verbosity path
+      then void $ createDefaultConfigFile verbosity path
       else die $ path ++ " already exists."
     ("diff":_) -> mapM_ putStrLn =<< userConfigDiff globalFlags
     ("update":_) -> userConfigUpdate verbosity globalFlags
diff --git a/bootstrap.sh b/bootstrap.sh
--- a/bootstrap.sh
+++ b/bootstrap.sh
@@ -99,13 +99,13 @@
 
 ${GHC_PKG} --version     > /dev/null 2>&1  || die "${GHC_PKG} not found."
 
-GHC_VER="$(${GHC} --numeric-version)"
 GHC_PKG_VER="$(${GHC_PKG} --version | cut -d' ' -f 5)"
 
 [ ${GHC_VER} = ${GHC_PKG_VER} ] ||
   die "Version mismatch between ${GHC} and ${GHC_PKG}.
        If you set the GHC variable then set GHC_PKG too."
 
+JOBS="-j1"
 while [ "$#" -gt 0 ]; do
   case "${1}" in
     "--user")
@@ -128,14 +128,28 @@
     "--no-doc")
       NO_DOCUMENTATION=1
       shift;;
+    "-j"|"--jobs")
+        shift
+        # check if there is another argument which doesn't start with - or --
+        if [ "$#" -le 0 ] \
+            || [ ! -z $(echo "${1}" | grep "^-") ] \
+            || [ ! -z $(echo "${1}" | grep "^--") ]
+        then
+            JOBS="-j"
+        else
+            JOBS="-j${1}"
+            shift
+        fi;;
     *)
       echo "Unknown argument or option, quitting: ${1}"
       echo "usage: bootstrap.sh [OPTION]"
       echo
       echo "options:"
+      echo "   -j/--jobs       Number of concurrent workers to use (Default: 1)"
+      echo "                   -j without an argument will use all available cores"
       echo "   --user          Install for the local user (default)"
       echo "   --global        Install systemwide (must be run as root)"
-      echo "   --no-doc        Do not generate documentation for installed "\
+      echo "   --no-doc        Do not generate documentation for installed"\
            "packages"
       echo "   --sandbox       Install to a sandbox in the default location"\
            "(.cabal-sandbox)"
@@ -144,6 +158,15 @@
   esac
 done
 
+# Do not try to use -j with GHC older than 7.8
+case $GHC_VER in
+    7.4*|7.6*)
+        JOBS=""
+        ;;
+    *)
+        ;;
+esac
+
 abspath () { case "$1" in /*)printf "%s\n" "$1";; *)printf "%s\n" "$PWD/$1";;
              esac; }
 
@@ -181,15 +204,28 @@
                        # >= 3.0 && < 3.2
 DEEPSEQ_VER="1.4.2.0"; DEEPSEQ_VER_REGEXP="1\.[1-9]\."
                        # >= 1.1 && < 2
-BINARY_VER="0.8.3.0";  BINARY_VER_REGEXP="[0]\.[78]\."
-                       # >= 0.7 && < 0.9
+
+case "$GHC_VER" in
+    7.4*|7.6*)
+        # GHC 7.4 or 7.6
+        BINARY_VER="0.8.2.1"
+        BINARY_VER_REGEXP="[0]\.[78]\.[0-2]\." # >= 0.7 && < 0.8.3
+        ;;
+    *)
+        # GHC >= 7.8
+        BINARY_VER="0.8.3.0"
+        BINARY_VER_REGEXP="[0]\.[78]\." # >= 0.7 && < 0.9
+        ;;
+esac
+
+
 TEXT_VER="1.2.2.1";    TEXT_VER_REGEXP="((1\.[012]\.)|(0\.([2-9]|(1[0-1]))\.))"
                        # >= 0.2 && < 1.3
 NETWORK_VER="2.6.2.1"; NETWORK_VER_REGEXP="2\.[0-6]\."
                        # >= 2.0 && < 2.7
 NETWORK_URI_VER="2.6.1.0"; NETWORK_URI_VER_REGEXP="2\.6\."
                        # >= 2.6 && < 2.7
-CABAL_VER="1.24.0.0";  CABAL_VER_REGEXP="1\.24\.[0-9]"
+CABAL_VER="1.24.1.0";  CABAL_VER_REGEXP="1\.24\.[0-9]"
                        # >= 1.24 && < 1.25
 TRANS_VER="0.5.2.0";   TRANS_VER_REGEXP="0\.[45]\."
                        # >= 0.2.* && < 0.6
@@ -213,23 +249,25 @@
                        # >=1.0.0.0 && <1.1
 BASE16_BYTESTRING_VER="0.1.1.6"; BASE16_BYTESTRING_VER_REGEXP="0\.1"
                        # 0.1.*
-BASE64_BYTESTRING_VER="1.0.0.1";    BASE64_BYTESTRING_REGEXP="1\."
+BASE64_BYTESTRING_VER="1.0.0.1"; BASE64_BYTESTRING_REGEXP="1\."
                        # >=1.0
 CRYPTOHASH_SHA256_VER="0.11.7.1"; CRYPTOHASH_SHA256_VER_REGEXP="0\.11\.?"
                        # 0.11.*
 ED25519_VER="0.0.5.0"; ED25519_VER_REGEXP="0\.0\.?"
                        # 0.0.*
-HACKAGE_SECURITY_VER="0.5.1.0"; HACKAGE_SECURITY_VER_REGEXP="0\.5\.[1-9]"
-                       # >= 0.5.1 && < 0.6
-TAR_VER="0.5.0.1";     TAR_VER_REGEXP="0\.5\.([1-9]|1[0-9]|0\.1)\.?"
-                       # >= 0.5.0.1  && < 0.6
+HACKAGE_SECURITY_VER="0.5.2.2"; HACKAGE_SECURITY_VER_REGEXP="0\.5\.(2\.[2-9]|[3-9])"
+                       # >= 0.5.2 && < 0.6
+BYTESTRING_BUILDER_VER="0.10.8.1.0"; BYTESTRING_BUILDER_VER_REGEXP="0\.10\.?"
+TAR_VER="0.5.0.3";     TAR_VER_REGEXP="0\.5\.([1-9]|1[0-9]|0\.[3-9]|0\.1[0-9])\.?"
+                       # >= 0.5.0.3  && < 0.6
 HASHABLE_VER="1.2.4.0"; HASHABLE_VER_REGEXP="1\."
                        # 1.*
 
 HACKAGE_URL="https://hackage.haskell.org/package"
 
-# Haddock fails for network-2.5.0.0.
-NO_DOCS_PACKAGES_VER_REGEXP="network-uri-2\.5\.[0-9]+\.[0-9]+"
+# Haddock fails for network-2.5.0.0, and for hackage-security for
+# GHC <8, c.f. https://github.com/well-typed/hackage-security/issues/149
+NO_DOCS_PACKAGES_VER_REGEXP="network-uri-2\.5\.[0-9]+\.[0-9]+|hackage-security-0\.5\.[0-9]+\.[0-9]+"
 
 # Cache the list of packages:
 echo "Checking installed packages for ghc-${GHC_VER}..."
@@ -316,7 +354,7 @@
   [ -x Setup ] && ./Setup clean
   [ -f Setup ] && rm Setup
 
-  ${GHC} --make Setup -o Setup ||
+  ${GHC} --make ${JOBS} Setup -o Setup ||
     die "Compiling the Setup script failed."
 
   [ -x Setup ] || die "The Setup script does not exist or cannot be run"
@@ -327,7 +365,7 @@
 
   ./Setup configure $args || die "Configuring the ${PKG} package failed."
 
-  ./Setup build ${EXTRA_BUILD_OPTS} ${VERBOSE} ||
+  ./Setup build ${JOBS} ${EXTRA_BUILD_OPTS} ${VERBOSE} ||
      die "Building the ${PKG} package failed."
 
   if [ ! ${NO_DOCUMENTATION} ]
@@ -368,6 +406,26 @@
   fi
 }
 
+# If we're bootstrapping from a Git clone, install the local version of Cabal
+# instead of downloading one from Hackage.
+do_Cabal_pkg () {
+    if [ -d "../.git" ]
+    then
+        if need_pkg "Cabal" ${CABAL_VER_REGEXP}
+        then
+            echo "Cabal-${CABAL_VER} will be installed from the local Git clone."
+            cd ../Cabal
+            install_pkg ${CABAL_VER} ${CABAL_VER_REGEXP}
+            cd ../cabal-install
+        else
+            echo "Cabal-${CABAL_VER} is already installed and the version is ok."
+        fi
+    else
+        info_pkg "Cabal"        ${CABAL_VER}   ${CABAL_VER_REGEXP}
+        do_pkg   "Cabal"        ${CABAL_VER}   ${CABAL_VER_REGEXP}
+    fi
+}
+
 # Replicate the flag selection logic for network-uri in the .cabal file.
 do_network_uri_pkg () {
   # Refresh installed package list.
@@ -389,12 +447,22 @@
   fi
 }
 
+# Conditionally install bytestring-builder if bytestring is < 0.10.2.
+do_bytestring_builder_pkg () {
+  if egrep "bytestring-0\.(9|10\.[0,1])\.?" ghc-pkg-stage2.list > /dev/null 2>&1
+  then
+      info_pkg "bytestring-builder" ${BYTESTRING_BUILDER_VER} \
+               ${BYTESTRING_BUILDER_VER_REGEXP}
+      do_pkg   "bytestring-builder" ${BYTESTRING_BUILDER_VER} \
+               ${BYTESTRING_BUILDER_VER_REGEXP}
+  fi
+}
+
 # Actually do something!
 
 info_pkg "deepseq"      ${DEEPSEQ_VER} ${DEEPSEQ_VER_REGEXP}
 info_pkg "binary"       ${BINARY_VER}  ${BINARY_VER_REGEXP}
 info_pkg "time"         ${TIME_VER}    ${TIME_VER_REGEXP}
-info_pkg "Cabal"        ${CABAL_VER}   ${CABAL_VER_REGEXP}
 info_pkg "transformers" ${TRANS_VER}   ${TRANS_VER_REGEXP}
 info_pkg "mtl"          ${MTL_VER}     ${MTL_VER_REGEXP}
 info_pkg "text"         ${TEXT_VER}    ${TEXT_VER_REGEXP}
@@ -415,14 +483,17 @@
     ${CRYPTOHASH_SHA256_VER_REGEXP}
 info_pkg "ed25519"           ${ED25519_VER}          ${ED25519_VER_REGEXP}
 info_pkg "tar"               ${TAR_VER}              ${TAR_VER_REGEXP}
-info_pkg "hashable"          ${HASHABLE_VER}          ${HASHABLE_VER_REGEXP}
+info_pkg "hashable"          ${HASHABLE_VER}         ${HASHABLE_VER_REGEXP}
 info_pkg "hackage-security"  ${HACKAGE_SECURITY_VER} \
     ${HACKAGE_SECURITY_VER_REGEXP}
 
 do_pkg   "deepseq"      ${DEEPSEQ_VER} ${DEEPSEQ_VER_REGEXP}
 do_pkg   "binary"       ${BINARY_VER}  ${BINARY_VER_REGEXP}
 do_pkg   "time"         ${TIME_VER}    ${TIME_VER_REGEXP}
-do_pkg   "Cabal"        ${CABAL_VER}   ${CABAL_VER_REGEXP}
+
+# Install the Cabal library from the local Git clone if possible.
+do_Cabal_pkg
+
 do_pkg   "transformers" ${TRANS_VER}   ${TRANS_VER_REGEXP}
 do_pkg   "mtl"          ${MTL_VER}     ${MTL_VER_REGEXP}
 do_pkg   "text"         ${TEXT_VER}    ${TEXT_VER_REGEXP}
@@ -446,6 +517,11 @@
 do_pkg   "cryptohash-sha256" ${CRYPTOHASH_SHA256_VER} \
     ${CRYPTOHASH_SHA256_VER_REGEXP}
 do_pkg   "ed25519"           ${ED25519_VER}          ${ED25519_VER_REGEXP}
+
+# We conditionally install bytestring-builder, depending on the bytestring
+# version.
+do_bytestring_builder_pkg
+
 do_pkg   "tar"               ${TAR_VER}              ${TAR_VER_REGEXP}
 do_pkg   "hashable"          ${HASHABLE_VER}         ${HASHABLE_VER_REGEXP}
 do_pkg   "hackage-security"  ${HACKAGE_SECURITY_VER} \
diff --git a/cabal-install.cabal b/cabal-install.cabal
--- a/cabal-install.cabal
+++ b/cabal-install.cabal
@@ -1,5 +1,5 @@
 Name:               cabal-install
-Version:            1.24.0.0
+Version:            1.24.0.1
 Synopsis:           The command-line interface for Cabal and Hackage.
 Description:
     The \'cabal\' command-line program simplifies the process of managing
@@ -30,6 +30,20 @@
   -- Generated with '../Cabal/misc/gen-extra-source-files.sh'
   -- Do NOT edit this section manually; instead, run the script.
   -- BEGIN gen-extra-source-files
+  tests/IntegrationTests/custom-setup/common.sh
+  tests/IntegrationTests/custom-setup/should_run/Cabal-99998/Cabal.cabal
+  tests/IntegrationTests/custom-setup/should_run/Cabal-99998/CabalMessage.hs
+  tests/IntegrationTests/custom-setup/should_run/Cabal-99999/Cabal.cabal
+  tests/IntegrationTests/custom-setup/should_run/Cabal-99999/CabalMessage.hs
+  tests/IntegrationTests/custom-setup/should_run/custom-setup-without-cabal-defaultMain/Setup.hs
+  tests/IntegrationTests/custom-setup/should_run/custom-setup-without-cabal-defaultMain/custom-setup-without-cabal-defaultMain.cabal
+  tests/IntegrationTests/custom-setup/should_run/custom-setup-without-cabal/Setup.hs
+  tests/IntegrationTests/custom-setup/should_run/custom-setup-without-cabal/custom-setup-without-cabal.cabal
+  tests/IntegrationTests/custom-setup/should_run/custom-setup/Setup.hs
+  tests/IntegrationTests/custom-setup/should_run/custom-setup/custom-setup.cabal
+  tests/IntegrationTests/custom-setup/should_run/custom_setup_without_Cabal_doesnt_allow_Cabal_import.sh
+  tests/IntegrationTests/custom-setup/should_run/custom_setup_without_Cabal_doesnt_require_Cabal.sh
+  tests/IntegrationTests/custom-setup/should_run/installs_Cabal_as_setup_dep.sh
   tests/IntegrationTests/custom/common.sh
   tests/IntegrationTests/custom/should_run/plain.err
   tests/IntegrationTests/custom/should_run/plain.sh
@@ -261,10 +275,10 @@
         pretty     >= 1.1      && < 1.2,
         random     >= 1        && < 1.2,
         stm        >= 2.0      && < 3,
-        tar        >= 0.5.0.1  && < 0.6,
+        tar        >= 0.5.0.3  && < 0.6,
         time       >= 1.4      && < 1.7,
         zlib       >= 0.5.3    && < 0.7,
-        hackage-security >= 0.5.1 && < 0.6
+        hackage-security >= 0.5.2.2 && < 0.6
 
     if flag(old-bytestring)
       build-depends: bytestring <  0.10.2, bytestring-builder >= 0.10 && < 1
@@ -400,5 +414,5 @@
   else
     ghc-options: -threaded
 
-  ghc-options: -Wall
+  ghc-options: -Wall -fwarn-tabs -fno-ignore-asserts
   default-language: Haskell2010
diff --git a/changelog b/changelog
--- a/changelog
+++ b/changelog
@@ -1,4 +1,21 @@
 -*-change-log-*-
+1.24.0.1 Ryan Thomas <ryan@ryant.org> October 2016
+	* Fixed issue with passing '--enable-profiling' when invoking
+	Setup scripts built with older versions of Cabal (#3873).
+	* Fixed various behaviour differences between network transports
+	(#3429).
+	* Updated to depend on the latest hackage-security that fixes
+	various issues on Windows.
+	* Fixed 'new-build' to exit with a non-zero exit code on failure
+	(#3506).
+	* Store secure repo index data as 01-index.* (#3862).
+	* Added new hackage-security root keys for distribution with
+	cabal-install.
+	* Fix an issue where 'cabal install' sometimes had to be run twice
+	for packages with build-type: Custom and a custom-setup stanza
+	(#3723).
+	* 'cabal sdist' no longer ignores '--builddir' when the package's
+	build-type is Custom (#3794).
 
 1.24.0.0 Ryan Thomas <ryan@ryant.org> May 2016
 	* If there are multiple remote repos, 'cabal update' now updates
@@ -54,6 +71,7 @@
 	(#3171).
 	* Improved performance of '--reorder-goals' (#3208).
 	* Fixed space leaks in modular solver (#2916, #2914).
+	* Made the solver aware of pkg-config constraints (#3023).
 	* Added a new command: 'gen-bounds' (#3223). See
 	http://softwaresimply.blogspot.se/2015/08/cabal-gen-bounds-easy-generation-of.html.
 	* Tech preview of new nix-style isolated project-based builds.
diff --git a/tests/IntegrationTests/custom-setup/common.sh b/tests/IntegrationTests/custom-setup/common.sh
new file mode 100644
--- /dev/null
+++ b/tests/IntegrationTests/custom-setup/common.sh
@@ -0,0 +1,9 @@
+# Helper to run Cabal
+cabal() {
+    "$CABAL" $CABAL_ARGS "$@"
+}
+
+die() {
+    echo "die: $@"
+    exit 1
+}
diff --git a/tests/IntegrationTests/custom-setup/should_run/Cabal-99998/Cabal.cabal b/tests/IntegrationTests/custom-setup/should_run/Cabal-99998/Cabal.cabal
new file mode 100644
--- /dev/null
+++ b/tests/IntegrationTests/custom-setup/should_run/Cabal-99998/Cabal.cabal
@@ -0,0 +1,8 @@
+name: Cabal
+version: 99998
+build-type: Simple
+cabal-version: >= 1.2
+
+library
+  build-depends: base
+  exposed-modules: CabalMessage
diff --git a/tests/IntegrationTests/custom-setup/should_run/Cabal-99998/CabalMessage.hs b/tests/IntegrationTests/custom-setup/should_run/Cabal-99998/CabalMessage.hs
new file mode 100644
--- /dev/null
+++ b/tests/IntegrationTests/custom-setup/should_run/Cabal-99998/CabalMessage.hs
@@ -0,0 +1,3 @@
+module CabalMessage where
+
+message = "This is Cabal-99998"
diff --git a/tests/IntegrationTests/custom-setup/should_run/Cabal-99999/Cabal.cabal b/tests/IntegrationTests/custom-setup/should_run/Cabal-99999/Cabal.cabal
new file mode 100644
--- /dev/null
+++ b/tests/IntegrationTests/custom-setup/should_run/Cabal-99999/Cabal.cabal
@@ -0,0 +1,8 @@
+name: Cabal
+version: 99999
+build-type: Simple
+cabal-version: >= 1.2
+
+library
+  build-depends: base
+  exposed-modules: CabalMessage
diff --git a/tests/IntegrationTests/custom-setup/should_run/Cabal-99999/CabalMessage.hs b/tests/IntegrationTests/custom-setup/should_run/Cabal-99999/CabalMessage.hs
new file mode 100644
--- /dev/null
+++ b/tests/IntegrationTests/custom-setup/should_run/Cabal-99999/CabalMessage.hs
@@ -0,0 +1,3 @@
+module CabalMessage where
+
+message = "This is Cabal-99999"
diff --git a/tests/IntegrationTests/custom-setup/should_run/custom-setup-without-cabal-defaultMain/Setup.hs b/tests/IntegrationTests/custom-setup/should_run/custom-setup-without-cabal-defaultMain/Setup.hs
new file mode 100644
--- /dev/null
+++ b/tests/IntegrationTests/custom-setup/should_run/custom-setup-without-cabal-defaultMain/Setup.hs
@@ -0,0 +1,3 @@
+import Distribution.Simple
+
+main = defaultMain
diff --git a/tests/IntegrationTests/custom-setup/should_run/custom-setup-without-cabal-defaultMain/custom-setup-without-cabal-defaultMain.cabal b/tests/IntegrationTests/custom-setup/should_run/custom-setup-without-cabal-defaultMain/custom-setup-without-cabal-defaultMain.cabal
new file mode 100644
--- /dev/null
+++ b/tests/IntegrationTests/custom-setup/should_run/custom-setup-without-cabal-defaultMain/custom-setup-without-cabal-defaultMain.cabal
@@ -0,0 +1,9 @@
+name: custom-setup-without-cabal-defaultMain
+version: 1.0
+build-type: Custom
+cabal-version: >= 1.2
+
+custom-setup
+  setup-depends: base
+
+library
diff --git a/tests/IntegrationTests/custom-setup/should_run/custom-setup-without-cabal/Setup.hs b/tests/IntegrationTests/custom-setup/should_run/custom-setup-without-cabal/Setup.hs
new file mode 100644
--- /dev/null
+++ b/tests/IntegrationTests/custom-setup/should_run/custom-setup-without-cabal/Setup.hs
@@ -0,0 +1,4 @@
+import System.Exit
+import System.IO
+
+main = hPutStrLn stderr "My custom Setup" >> exitFailure
diff --git a/tests/IntegrationTests/custom-setup/should_run/custom-setup-without-cabal/custom-setup-without-cabal.cabal b/tests/IntegrationTests/custom-setup/should_run/custom-setup-without-cabal/custom-setup-without-cabal.cabal
new file mode 100644
--- /dev/null
+++ b/tests/IntegrationTests/custom-setup/should_run/custom-setup-without-cabal/custom-setup-without-cabal.cabal
@@ -0,0 +1,9 @@
+name: custom-setup-without-cabal
+version: 1.0
+build-type: Custom
+cabal-version: >= 99999
+
+custom-setup
+  setup-depends: base
+
+library
diff --git a/tests/IntegrationTests/custom-setup/should_run/custom-setup/Setup.hs b/tests/IntegrationTests/custom-setup/should_run/custom-setup/Setup.hs
new file mode 100644
--- /dev/null
+++ b/tests/IntegrationTests/custom-setup/should_run/custom-setup/Setup.hs
@@ -0,0 +1,5 @@
+import CabalMessage (message)
+import System.Exit
+import System.IO
+
+main = hPutStrLn stderr message >> exitFailure
diff --git a/tests/IntegrationTests/custom-setup/should_run/custom-setup/custom-setup.cabal b/tests/IntegrationTests/custom-setup/should_run/custom-setup/custom-setup.cabal
new file mode 100644
--- /dev/null
+++ b/tests/IntegrationTests/custom-setup/should_run/custom-setup/custom-setup.cabal
@@ -0,0 +1,9 @@
+name: custom-setup
+version: 1.0
+build-type: Custom
+cabal-version: >= 99999
+
+custom-setup
+  setup-depends: base, Cabal >= 99999
+
+library
diff --git a/tests/IntegrationTests/custom-setup/should_run/custom_setup_without_Cabal_doesnt_allow_Cabal_import.sh b/tests/IntegrationTests/custom-setup/should_run/custom_setup_without_Cabal_doesnt_allow_Cabal_import.sh
new file mode 100644
--- /dev/null
+++ b/tests/IntegrationTests/custom-setup/should_run/custom_setup_without_Cabal_doesnt_allow_Cabal_import.sh
@@ -0,0 +1,12 @@
+. ../common.sh
+cd custom-setup-without-cabal-defaultMain
+
+# This package has explicit setup dependencies that do not include Cabal.
+# Compilation should fail because Setup.hs imports Distribution.Simple.
+! cabal new-build custom-setup-without-cabal-defaultMain > output 2>&1
+cat output
+grep -q "\(Could not find module\|Failed to load interface for\).*Distribution\\.Simple" output \
+    || die "Should not have been able to import Cabal"
+
+grep -q "It is a member of the hidden package .*Cabal-" output \
+    || die "Cabal should be available"
diff --git a/tests/IntegrationTests/custom-setup/should_run/custom_setup_without_Cabal_doesnt_require_Cabal.sh b/tests/IntegrationTests/custom-setup/should_run/custom_setup_without_Cabal_doesnt_require_Cabal.sh
new file mode 100644
--- /dev/null
+++ b/tests/IntegrationTests/custom-setup/should_run/custom_setup_without_Cabal_doesnt_require_Cabal.sh
@@ -0,0 +1,11 @@
+. ../common.sh
+cd custom-setup-without-cabal
+
+# This package has explicit setup dependencies that do not include Cabal.
+# new-build should try to build it, even though the cabal-version cannot be
+# satisfied by an installed version of Cabal (cabal-version: >= 99999). However,
+# configure should fail because Setup.hs just prints an error message and exits.
+! cabal new-build custom-setup-without-cabal > output 2>&1
+cat output
+grep -q "My custom Setup" output \
+    || die "Expected output from custom Setup"
diff --git a/tests/IntegrationTests/custom-setup/should_run/installs_Cabal_as_setup_dep.sh b/tests/IntegrationTests/custom-setup/should_run/installs_Cabal_as_setup_dep.sh
new file mode 100644
--- /dev/null
+++ b/tests/IntegrationTests/custom-setup/should_run/installs_Cabal_as_setup_dep.sh
@@ -0,0 +1,15 @@
+# Regression test for issue #3436
+
+. ../common.sh
+cabal sandbox init
+cabal install ./Cabal-99998
+cabal sandbox add-source Cabal-99999
+
+# Install custom-setup, which has a setup dependency on Cabal-99999.
+# cabal should build the setup script with Cabal-99999, but then
+# configure should fail because Setup just prints an error message
+# imported from Cabal and exits.
+! cabal install custom-setup/ > output 2>&1
+
+cat output
+grep -q "This is Cabal-99999" output || die "Expected output from Cabal-99999"
diff --git a/tests/UnitTests/Distribution/Client/ArbitraryInstances.hs b/tests/UnitTests/Distribution/Client/ArbitraryInstances.hs
--- a/tests/UnitTests/Distribution/Client/ArbitraryInstances.hs
+++ b/tests/UnitTests/Distribution/Client/ArbitraryInstances.hs
@@ -67,6 +67,7 @@
 arbitraryShortToken :: Gen String
 arbitraryShortToken = getShortToken <$> arbitrary
 
+#if !MIN_VERSION_QuickCheck(2,9,0)
 instance Arbitrary Version where
   arbitrary = do
     branch <- shortListOf1 4 $
@@ -81,6 +82,7 @@
     [ Version branch' [] | branch' <- shrink branch, not (null branch') ]
   shrink (Version branch _tags) =
     [ Version branch [] ]
+#endif
 
 instance Arbitrary VersionRange where
   arbitrary = canonicaliseVersionRange <$> sized verRangeExp
diff --git a/tests/UnitTests/Distribution/Client/UserConfig.hs b/tests/UnitTests/Distribution/Client/UserConfig.hs
--- a/tests/UnitTests/Distribution/Client/UserConfig.hs
+++ b/tests/UnitTests/Distribution/Client/UserConfig.hs
@@ -48,7 +48,7 @@
     appendFile configFile "verbose: 0\n"
     diff <- userConfigDiff $ globalFlags configFile
     assertBool (unlines $ "Should detect a difference:" : diff) $
-        diff == [ "- verbose: 1", "+ verbose: 0" ]
+        diff == [ "+ verbose: 0" ]
 
 
 canUpdateConfig :: Assertion
@@ -85,7 +85,7 @@
     sysTmpDir <- getTemporaryDirectory
     withTempDirectory silent sysTmpDir "cabal-test" $ \tmpDir -> do
         let configFile  = tmpDir </> "tmp.config"
-        createDefaultConfigFile silent configFile
+        _ <- createDefaultConfigFile silent configFile
         exists <- doesFileExist configFile
         assertBool ("Config file should be written to " ++ configFile) exists
 
