@@ -58,7 +58,7 @@ import qualified Data.Text.Encoding.Error as T
5858import Data.Time.Clock (NominalDiffTime , diffUTCTime , getCurrentTime )
5959import Data.Typeable (Typeable )
6060import qualified Data.Yaml as Yaml
61- import Distribution.System (OS , Arch (.. ), Platform (.. ))
61+ import Distribution.System (OS ( Linux ) , Arch (.. ), Platform (.. ))
6262import qualified Distribution.System as Cabal
6363import Distribution.Text (simpleParse )
6464import Lens.Micro (set )
@@ -70,7 +70,7 @@ import Path.Extra (toFilePathNoTrailingSep)
7070import Path.IO hiding (findExecutable )
7171import qualified Paths_stack as Meta
7272import Prelude hiding (concat , elem , any ) -- Fix AMP warning
73- import Safe (readMay )
73+ import Safe (headMay , readMay )
7474import Stack.Build (build )
7575import Stack.Config (resolvePackageEntry , loadConfig )
7676import Stack.Constants (distRelativeDir , stackProgName )
@@ -215,7 +215,7 @@ setupEnv mResolveMissingGHC = do
215215 , soptsGHCBindistURL = Nothing
216216 }
217217
218- mghcBin <- ensureCompiler sopts
218+ ( mghcBin, compilerBuild) <- ensureCompiler sopts
219219
220220 -- Modify the initial environment to include the GHC path, if a local GHC
221221 -- is being used
@@ -237,6 +237,7 @@ setupEnv mResolveMissingGHC = do
237237 { envConfigBuildConfig = bconfig
238238 , envConfigCabalVersion = cabalVer
239239 , envConfigCompilerVersion = compilerVer
240+ , envConfigCompilerBuild = compilerBuild
240241 , envConfigPackages = Map. fromList $ concat packages
241242 }
242243
@@ -315,6 +316,7 @@ setupEnv mResolveMissingGHC = do
315316 }
316317 , envConfigCabalVersion = cabalVer
317318 , envConfigCompilerVersion = compilerVer
319+ , envConfigCompilerBuild = compilerBuild
318320 , envConfigPackages = envConfigPackages envConfig0
319321 }
320322
@@ -332,7 +334,7 @@ addIncludeLib (ExtraDirs _bins includes libs) config = config
332334-- | Ensure compiler (ghc or ghcjs) is installed and provide the PATHs to add if necessary
333335ensureCompiler :: (MonadIO m , MonadMask m , MonadLogger m , MonadReader env m , HasConfig env , HasHttpManager env , HasTerminal env , HasReExec env , HasLogLevel env , HasGHCVariant env , MonadBaseControl IO m )
334336 => SetupOpts
335- -> m (Maybe ExtraDirs )
337+ -> m (Maybe ExtraDirs , CompilerBuild )
336338ensureCompiler sopts = do
337339 let wc = whichCompiler (soptsWantedCompiler sopts)
338340 when (getGhcVersion (soptsWantedCompiler sopts) < $ (mkVersion " 7.8" )) $ do
@@ -363,7 +365,7 @@ ensureCompiler sopts = do
363365
364366 -- If we need to install a GHC or MSYS, try to do so
365367 -- Return the additional directory paths of GHC & MSYS.
366- mtools <- if needLocal
368+ ( mtools, compilerBuild) <- if needLocal
367369 then do
368370 getSetupInfo' <- runOnce (getSetupInfo (soptsStackSetupYaml sopts) =<< asks getHttpManager)
369371
@@ -373,17 +375,20 @@ ensureCompiler sopts = do
373375 -- Install GHC
374376 ghcVariant <- asks getGHCVariant
375377 config <- asks getConfig
376- ghcPkgName <- parsePackageNameFromString (" ghc" ++ ghcVariantSuffix ghcVariant)
377- let installedCompiler =
378+ (installedCompiler, compilerBuild) <-
378379 case wc of
379- Ghc -> getInstalledTool installed ghcPkgName (isWanted . GhcVersion )
380- Ghcjs -> getInstalledGhcjs installed isWanted
380+ Ghc -> do
381+ ghcBuild <- getGhcBuild menv0
382+ ghcPkgName <- parsePackageNameFromString (" ghc" ++ ghcVariantSuffix ghcVariant ++ compilerBuildSuffix ghcBuild)
383+ return (getInstalledTool installed ghcPkgName (isWanted . GhcVersion ), ghcBuild)
384+ Ghcjs -> return (getInstalledGhcjs installed isWanted, CompilerBuildStandard )
381385 compilerTool <- case installedCompiler of
382386 Just tool -> return tool
383387 Nothing
384388 | soptsInstallIfMissing sopts -> do
385389 si <- getSetupInfo'
386390 downloadAndInstallCompiler
391+ compilerBuild
387392 si
388393 (soptsWantedCompiler sopts)
389394 (soptsCompilerCheck sopts)
@@ -393,6 +398,7 @@ ensureCompiler sopts = do
393398 msystem
394399 (soptsWantedCompiler sopts, expectedArch)
395400 ghcVariant
401+ compilerBuild
396402 (soptsCompilerCheck sopts)
397403 (soptsStackYaml sopts)
398404 (fromMaybe
@@ -421,8 +427,8 @@ ensureCompiler sopts = do
421427 return Nothing
422428 _ -> return Nothing
423429
424- return $ Just (compilerTool, mmsys2Tool)
425- else return Nothing
430+ return ( Just (compilerTool, mmsys2Tool), compilerBuild )
431+ else return ( Nothing , CompilerBuildStandard )
426432
427433 mpaths <- case mtools of
428434 Nothing -> return Nothing
@@ -452,9 +458,56 @@ ensureCompiler sopts = do
452458
453459 when (soptsSanityCheck sopts) $ sanityCheck menv wc
454460
455- return mpaths
461+ return (mpaths, compilerBuild)
462+
463+ -- | Determine which GHC build to use dependong on which shared libraries are available
464+ -- on the system.
465+ getGhcBuild
466+ :: (MonadIO m , MonadBaseControl IO m , MonadCatch m , MonadLogger m , HasPlatform env , MonadReader env m )
467+ => EnvOverride -> m CompilerBuild
468+ getGhcBuild menv = do
469+
470+ -- TODO: a more reliable, flexible, and data driven approach would be to actually download small
471+ -- "test" executables (from setup-info) that link to the same gmp/tinfo versions
472+ -- that GHC does (i.e. built in same environment as the GHC bindist). The algorithm would go
473+ -- something like this:
474+ --
475+ -- check for previous 'uname -a' plus compiler version/variant in cache
476+ -- if cached, then use that as suffix
477+ -- otherwise:
478+ -- download setup-info
479+ -- go through all with right prefix for os/version/variant
480+ -- first try "standard" (no extra suffix), then the rest
481+ -- download "compatibility check" exe if not already downloaded
482+ -- try running it
483+ -- if successful, then choose that
484+ -- cache compiler suffix with the uname -a and ldconfig -p output hash plus compiler version
456485
457- -- Ensure Docker container-compatible 'stack' executable is downloaded
486+ platform <- asks getPlatform
487+ case platform of
488+ Platform _ Linux -> do
489+ eldconfigOut <- tryProcessStdout Nothing menv " ldconfig" [" -p" ]
490+ let efirstWords = fmap (mapMaybe (headMay . T. words ) .
491+ T. lines . T. decodeUtf8With T. lenientDecode) eldconfigOut
492+ case efirstWords of
493+ Right firstWords
494+ | " libtinfo.so.6" `elem` firstWords
495+ && not (" libtinfo.so.5" `elem` firstWords) -> do
496+ $ logDebug " Found libtinfo.so.6; using tinfo6 GHC build"
497+ return (CompilerBuildSpecialized " tinfo6" )
498+ | " libgmp.so.3" `elem` firstWords
499+ && not (" libgmp.so.10" `elem` firstWords) -> do
500+ $ logDebug " Found libgmp.so.3; using gmp4 GHC build"
501+ return (CompilerBuildSpecialized " gmp4" )
502+ | otherwise -> do
503+ $ logDebug " Did not find libtinfo.so.6 or libgmp.so.3; using standard GHC build"
504+ return CompilerBuildStandard
505+ Left _ -> do
506+ $ logDebug " ldconfig -p failed; falling back to using standard GHC build"
507+ return CompilerBuildStandard
508+ _ -> return CompilerBuildStandard
509+
510+ -- | Ensure Docker container-compatible 'stack' executable is downloaded
458511ensureDockerStackExe
459512 :: (MonadIO m , MonadMask m , MonadLogger m , MonadReader env m , HasConfig env , HasHttpManager env , MonadBaseControl IO m )
460513 => Platform -> m (Path Abs File )
@@ -669,12 +722,13 @@ downloadAndInstallTool programsDir si downloadInfo tool installer = do
669722 return tool
670723
671724downloadAndInstallCompiler :: (MonadIO m , MonadMask m , MonadLogger m , MonadReader env m , HasConfig env , HasGHCVariant env , HasHttpManager env , HasTerminal env , HasReExec env , HasLogLevel env , MonadBaseControl IO m )
672- => SetupInfo
725+ => CompilerBuild
726+ -> SetupInfo
673727 -> CompilerVersion
674728 -> VersionCheck
675729 -> Maybe String
676730 -> m Tool
677- downloadAndInstallCompiler si wanted@ GhcVersion {} versionCheck mbindistURL = do
731+ downloadAndInstallCompiler ghcBuild si wanted@ GhcVersion {} versionCheck mbindistURL = do
678732 ghcVariant <- asks getGHCVariant
679733 (selectedVersion, downloadInfo) <- case mbindistURL of
680734 Just bindistURL -> do
@@ -687,7 +741,7 @@ downloadAndInstallCompiler si wanted@GhcVersion{} versionCheck mbindistURL = do
687741 _ ->
688742 throwM WantedMustBeGHC
689743 _ -> do
690- ghcKey <- getGhcKey
744+ ghcKey <- getGhcKey ghcBuild
691745 case Map. lookup ghcKey $ siGHCs si of
692746 Nothing -> throwM $ UnknownOSKey ghcKey
693747 Just pairs_ -> getWantedCompilerInfo ghcKey versionCheck wanted GhcVersion pairs_
@@ -701,16 +755,19 @@ downloadAndInstallCompiler si wanted@GhcVersion{} versionCheck mbindistURL = do
701755 (case ghcVariant of
702756 GHCStandard -> " "
703757 v -> " (" <> T. pack (ghcVariantName v) <> " )" ) <>
758+ (case ghcBuild of
759+ CompilerBuildStandard -> " "
760+ b -> " (" <> T. pack (compilerBuildName b) <> " )" ) <>
704761 " to an isolated location."
705762 $ logInfo " This will not interfere with any system-level installation."
706- ghcPkgName <- parsePackageNameFromString (" ghc" ++ ghcVariantSuffix ghcVariant)
763+ ghcPkgName <- parsePackageNameFromString (" ghc" ++ ghcVariantSuffix ghcVariant ++ compilerBuildSuffix ghcBuild )
707764 let tool = Tool $ PackageIdentifier ghcPkgName selectedVersion
708765 downloadAndInstallTool (configLocalPrograms config) si downloadInfo tool installer
709- downloadAndInstallCompiler si wanted versionCheck _mbindistUrl = do
766+ downloadAndInstallCompiler compilerBuild si wanted versionCheck _mbindistUrl = do
710767 config <- asks getConfig
711768 ghcVariant <- asks getGHCVariant
712- case ghcVariant of
713- GHCStandard -> return ()
769+ case ( ghcVariant, compilerBuild) of
770+ ( GHCStandard , CompilerBuildStandard ) -> return ()
714771 _ -> throwM GHCJSRequiresStandardVariant
715772 (selectedVersion, downloadInfo) <- case Map. lookup " source" $ siGHCJSs si of
716773 Nothing -> throwM $ UnknownOSKey " source"
@@ -738,12 +795,12 @@ getWantedCompilerInfo key versionCheck wanted toCV pairs_ =
738795 filter (isWantedCompiler versionCheck wanted . toCV . fst ) (Map. toList pairs_)
739796
740797getGhcKey :: (MonadReader env m , HasPlatform env , HasGHCVariant env , MonadCatch m )
741- => m Text
742- getGhcKey = do
798+ => CompilerBuild -> m Text
799+ getGhcKey ghcBuild = do
743800 ghcVariant <- asks getGHCVariant
744801 platform <- asks getPlatform
745802 osKey <- getOSKey platform
746- return $ osKey <> T. pack (ghcVariantSuffix ghcVariant)
803+ return $ osKey <> T. pack (ghcVariantSuffix ghcVariant) <> T. pack (compilerBuildSuffix ghcBuild)
747804
748805getOSKey :: (MonadThrow m )
749806 => Platform -> m Text
0 commit comments