diff --git a/ChangeLog.md b/ChangeLog.md index 33de384409..b378021fc6 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -11,6 +11,16 @@ Major changes: autogen files and run preprocessors. The `--no-build` flag is now deprecated because it should no longer be necessary. See [#1364](https://github.com/commercialhaskell/stack/issues/1364) +* Stack will now always use its own GHC installation, even when a suitable GHC + installation is available on the PATH. To get the old behaviour, use + the `--system-ghc` flag or run `stack config set system-ghc --global true`. + Docker- and Nix-enabled projects continue to use the GHC installations + in their environment by default. + + NB: Scripts that previously used stack in combination with a system GHC + installation should now include a `stack setup` line or use the `--install-ghc` + flag. + [#2221](https://github.com/commercialhaskell/stack/issues/2221) Behavior changes: diff --git a/doc/GUIDE.md b/doc/GUIDE.md index d17f6de407..604f84d025 100644 --- a/doc/GUIDE.md +++ b/doc/GUIDE.md @@ -332,8 +332,7 @@ stack ghc, stack ghci, stack runghc, or stack exec ``` Thankfully, the command is smart enough to know not to perform an installation -twice. `setup` will either use the first GHC it finds on your PATH, or a sandboxed -version after installing it. As the command output above indicates, you can use `stack +twice. As the command output above indicates, you can use `stack path` for quite a bit of path information (which we'll play with more later). For now, we'll just look at where GHC is installed: diff --git a/doc/docker_integration.md b/doc/docker_integration.md index 7a82f6451c..191e04895c 100644 --- a/doc/docker_integration.md +++ b/doc/docker_integration.md @@ -78,6 +78,13 @@ The most basic configuration is to add this to your project's `stack.yaml`: See [configuration](#configuration) for additional options. You can enable it on the command-line using `stack --docker`. +Please note that in a docker-enabled configuration, stack uses the GHC installed +in the Docker container by default. To use a compiler installed by stack, add + + system-ghc: false + +(see [`system-ghc`](yaml_configuration.md#system-ghc)). + ### Use stack as normal With Docker enabled, most stack sub-commands will automatically launch diff --git a/doc/faq.md b/doc/faq.md index e48d802b35..89b2f6a53d 100644 --- a/doc/faq.md +++ b/doc/faq.md @@ -155,23 +155,39 @@ the following line to your .cabal file: ## I already have GHC installed, can I still use stack? -Yes. stack will default to using whatever GHC is on your `PATH`. If that GHC is -a compatible version with the snapshot you're using, it will simply use it. -Otherwise, it will prompt you to run `stack setup`. Note that `stack setup` -installs GHC into `~/.stack/programs/$platform/ghc-$version/` and not a global -location. +Yes. In its default configuration, stack will simply ignore any system GHC +installation and use a sandboxed GHC that it has installed itself (typically +via the `stack setup` command). You can find these sandboxed GHC installations +in `~/.stack/programs/$platform/ghc-$version/`. -Note that GHC installation doesn't work for all OSes, so in some cases the -first option will need to install GHC yourself. +If you would like stack to use your system GHC installation, use the +[`--system-ghc` flag](yaml_configuration.md#system-ghc) or run +`stack config set system-ghc --global true` to make stack check your +`PATH` for a suitable GHC by default. + +Note that stack can only use a system GHC installation if its version is +compatible with the configuration of the current project, particularly the +[`resolver` setting](yaml_configuration.md#resolver). + +Note that GHC installation doesn't work for all OSes, so in some cases you +will need to use `system-ghc` and install GHC yourself. ## How does stack determine what GHC to use? -It uses the first GHC that it finds on the `PATH`. If that GHC does not comply -with the various requirements (version, architecture) that your project needs, -it will prompt you to run `stack setup` to get it. `stack` is fully aware of -all GHCs that it has installed itself. +In its default configuration, stack determines from the current project which +GHC version, architecture etc. it needs. It then looks in +`~/.stack/programs/$platform/ghc-$version/` for a compatible GHC, requesting +to install one via `stack setup` if none is found. + +If you are using the [`--system-ghc` flag](yaml_configuration.md/#system-ghc) or +have configured `system-ghc: true` either in the project `stack.yaml` +or the global `~/.stack/config.yaml`, stack will use the first GHC that it finds +on your `PATH`, falling back on its sandboxed installations only if the found GHC +doesn't comply with the various requirements (version, architecture) that your +project needs. -See [this issue](https://github.com/commercialhaskell/stack/issues/420) for a detailed discussion. +See [this issue](https://github.com/commercialhaskell/stack/issues/420) for a +detailed discussion of stack's behavior when `system-ghc` is enabled. ## How do I upgrade to GHC 7.10.2 with stack? diff --git a/doc/travis_ci.md b/doc/travis_ci.md index ad19feca20..4ea66e79cb 100644 --- a/doc/travis_ci.md +++ b/doc/travis_ci.md @@ -92,6 +92,10 @@ situation is simple: ```yaml before_install: + # Install stack as above + # ... + # Configure stack to use the system GHC installation + - stack config set system-ghc --global true - export PATH=/opt/ghc/7.10.2/bin:$PATH addons: diff --git a/doc/yaml_configuration.md b/doc/yaml_configuration.md index f49c04421c..82d16a0117 100644 --- a/doc/yaml_configuration.md +++ b/doc/yaml_configuration.md @@ -306,13 +306,14 @@ other projects by installing into your shared snapshot database. ### system-ghc -Enables or disables using the GHC available on the PATH. Useful to disable if -you want to force stack to use its own installed GHC (via `stack setup`), in -cases where your system GHC my be incomplete for some reason. Default is `true`. +Enables or disables using the GHC available on the PATH. +Useful to disable if you want to save the time, bandwidth or storage space needed to setup an isolated GHC. +Default is `false` unless the [Docker](docker_integration.md) or [Nix](nix_integration.md) integration is enabled. +In a Nix-enabled configuration, stack is incompatible with `system-ghc: false`. ```yaml -# Turn off system GHC -system-ghc: false +# Turn on system GHC +system-ghc: true ``` ### install-ghc @@ -452,6 +453,8 @@ Specify a variant binary distribution of GHC to use. Known values: [setup-info](#setup-info) so `stack setup` knows where to download it, or pass the `stack setup --ghc-bindist` argument on the command-line +This option is incompatible with `system-ghc: true`. + ### ghc-build (Since 1.2.1) diff --git a/src/Stack/Config.hs b/src/Stack/Config.hs index 6a9aeb9a12..03eeb1dd81 100644 --- a/src/Stack/Config.hs +++ b/src/Stack/Config.hs @@ -88,6 +88,7 @@ import Stack.Types.BuildPlan import Stack.Types.Docker import Stack.Types.Compiler import Stack.Types.Internal +import Stack.Types.Nix import Stack.Types.Urls import Stack.Types.Version import System.Environment @@ -240,8 +241,6 @@ configFromConfigMonoid configStackRoot configUserConfigPath mresolver mproject C configGHCVariant0 = getFirst configMonoidGHCVariant configGHCBuild = getFirst configMonoidGHCBuild - - configSystemGHC = fromFirst (isNothing configGHCVariant0) configMonoidSystemGHC configInstallGHC = fromFirst False configMonoidInstallGHC configSkipGHCCheck = fromFirst False configMonoidSkipGHCCheck configSkipMsys = fromFirst False configMonoidSkipMsys @@ -272,6 +271,19 @@ configFromConfigMonoid configStackRoot configUserConfigPath mresolver mproject C dockerOptsFromMonoid (fmap fst mproject) configStackRoot mresolver configMonoidDockerOpts configNix <- nixOptsFromMonoid configMonoidNixOpts os + configSystemGHC <- + case (getFirst configMonoidSystemGHC, nixEnable configNix) of + (Just False, True) -> + throwM NixRequiresSystemGhc + _ -> + return + (fromFirst + (dockerEnable configDocker || nixEnable configNix) + configMonoidSystemGHC) + + when (isJust configGHCVariant0 && configSystemGHC) $ + throwM ManualGHCVariantSettingsAreIncompatibleWithSystemGHC + rawEnv <- liftIO getEnvironment pathsEnv <- augmentPathMap configMonoidExtraPath (Map.fromList (map (T.pack *** T.pack) rawEnv)) diff --git a/src/Stack/Options/ConfigParser.hs b/src/Stack/Options/ConfigParser.hs index 8d629789e0..f4aa2dd51a 100644 --- a/src/Stack/Options/ConfigParser.hs +++ b/src/Stack/Options/ConfigParser.hs @@ -57,7 +57,7 @@ configOptsParser hide0 = <*> nixOptsParser True <*> firstBoolFlags "system-ghc" - "using the system installed GHC (on the PATH) if available and a matching version" + "using the system installed GHC (on the PATH) if available and a matching version. Disabled by default." hide <*> firstBoolFlags "install-ghc" diff --git a/src/Stack/Options/DockerParser.hs b/src/Stack/Options/DockerParser.hs index 2511b53a38..8843c788f2 100644 --- a/src/Stack/Options/DockerParser.hs +++ b/src/Stack/Options/DockerParser.hs @@ -21,7 +21,7 @@ dockerOptsParser hide0 = DockerOptsMonoid <$> pure (Any False) <*> firstBoolFlags dockerCmdName - "using a Docker container" + "using a Docker container. Implies 'system-ghc: true'" hide <*> fmap First ((Just . DockerMonoidRepo) <$> option str (long (dockerOptName dockerRepoArgName) <> diff --git a/src/Stack/Options/GhcVariantParser.hs b/src/Stack/Options/GhcVariantParser.hs index 0270a27c3a..91a0978396 100644 --- a/src/Stack/Options/GhcVariantParser.hs +++ b/src/Stack/Options/GhcVariantParser.hs @@ -13,7 +13,7 @@ ghcVariantParser hide = readGHCVariant (long "ghc-variant" <> metavar "VARIANT" <> help - "Specialized GHC variant, e.g. integersimple (implies --no-system-ghc)" <> + "Specialized GHC variant, e.g. integersimple (incompatible with --system-ghc)" <> hideMods hide ) where diff --git a/src/Stack/Options/NixParser.hs b/src/Stack/Options/NixParser.hs index 9b3791cb8b..f1b0fcfd4a 100644 --- a/src/Stack/Options/NixParser.hs +++ b/src/Stack/Options/NixParser.hs @@ -14,10 +14,10 @@ nixOptsParser hide0 = overrideActivation <$> (NixOptsMonoid <$> pure (Any False) <*> firstBoolFlags nixCmdName - "use of a Nix-shell" + "use of a Nix-shell. Implies 'system-ghc: true'" hide <*> firstBoolFlags "nix-pure" - "use of a pure Nix-shell" + "use of a pure Nix-shell. Implies 'system-ghc: true'" hide <*> optionalFirst (textArgsOption diff --git a/src/Stack/Setup.hs b/src/Stack/Setup.hs index 6511a395b7..308e3cbef8 100644 --- a/src/Stack/Setup.hs +++ b/src/Stack/Setup.hs @@ -109,6 +109,7 @@ defaultStackSetupYaml = data SetupOpts = SetupOpts { soptsInstallIfMissing :: !Bool , soptsUseSystem :: !Bool + -- ^ Should we use a system compiler installation, if available? , soptsWantedCompiler :: !CompilerVersion , soptsCompilerCheck :: !VersionCheck , soptsStackYaml :: !(Maybe (Path Abs File)) @@ -357,13 +358,11 @@ ensureCompiler sopts = do Platform expectedArch _ <- asks getPlatform - let needLocal = case msystem of - Nothing -> True - Just _ | soptsSkipGhcCheck sopts -> False - Just (system, arch) -> - not (isWanted system) || - arch /= expectedArch + let canUseCompiler compilerVersion arch + | soptsSkipGhcCheck sopts = True + | otherwise = isWanted compilerVersion && arch == expectedArch isWanted = isWantedCompiler (soptsCompilerCheck sopts) (soptsWantedCompiler sopts) + needLocal = not (any (uncurry canUseCompiler) msystem) getSetupInfo' <- runOnce (getSetupInfo (soptsStackSetupYaml sopts) =<< asks getHttpManager) @@ -422,7 +421,23 @@ ensureCompiler sopts = do (soptsWantedCompiler sopts) (soptsCompilerCheck sopts) (soptsGHCBindistURL sopts) - | otherwise -> + | otherwise -> do + recommendSystemGhc <- + if soptsUseSystem sopts + then return False + else do + msystemGhc <- getSystemCompiler menv0 wc + return (any (uncurry canUseCompiler) msystemGhc) + let suggestion = fromMaybe + (mconcat + ([ "To install the correct GHC into " + , T.pack (toFilePath (configLocalPrograms config)) + , ", try running \"stack setup\" or use the \"--install-ghc\" flag." + ] ++ + [ " To use your system GHC installation, run \"stack config set system-ghc --global true\", or use the \"--system-ghc\" flag." + | recommendSystemGhc + ])) + (soptsResolveMissingGHC sopts) throwM $ CompilerVersionMismatch msystem (soptsWantedCompiler sopts, expectedArch) @@ -430,10 +445,7 @@ ensureCompiler sopts = do compilerBuild (soptsCompilerCheck sopts) (soptsStackYaml sopts) - (fromMaybe - ("Try running \"stack setup\" to install the correct GHC into " - <> T.pack (toFilePath (configLocalPrograms config))) - $ soptsResolveMissingGHC sopts) + suggestion -- Install msys2 on windows, if necessary mmsys2Tool <- getMmsys2Tool diff --git a/src/Stack/SetupCmd.hs b/src/Stack/SetupCmd.hs index b228d36d76..ddfc04156a 100644 --- a/src/Stack/SetupCmd.hs +++ b/src/Stack/SetupCmd.hs @@ -46,7 +46,7 @@ setupParser = SetupCmdOpts "The default is to install the version implied by the resolver."))) <*> OA.boolFlags False "reinstall" - "reinstalling GHC, even if available (implies no-system-ghc)" + "reinstalling GHC, even if available (incompatible with --system-ghc)" OA.idm <*> OA.boolFlags False "upgrade-cabal" diff --git a/src/Stack/Types/Build.hs b/src/Stack/Types/Build.hs index fd555f7764..05a9f510ce 100644 --- a/src/Stack/Types/Build.hs +++ b/src/Stack/Types/Build.hs @@ -52,7 +52,7 @@ import qualified Data.ByteString as S import Data.Char (isSpace) import Data.Data import Data.Hashable -import Data.List (dropWhileEnd, intercalate) +import Data.List.Extra import qualified Data.Map as Map import Data.Map.Strict (Map) import Data.Maybe @@ -93,14 +93,13 @@ import System.Process.Log (showProcessArgDebug) data StackBuildException = Couldn'tFindPkgId PackageName | CompilerVersionMismatch - (Maybe (CompilerVersion, Arch)) - (CompilerVersion, Arch) - GHCVariant - CompilerBuild + (Maybe (CompilerVersion, Arch)) -- found + (CompilerVersion, Arch) -- expected + GHCVariant -- expected + CompilerBuild -- expected VersionCheck - (Maybe (Path Abs File)) + (Maybe (Path Abs File)) -- Path to the stack.yaml file Text -- recommended resolution - -- ^ Path to the stack.yaml file | Couldn'tParseTargets [Text] | UnknownTargets (Set PackageName) -- no known version diff --git a/src/Stack/Types/Config.hs b/src/Stack/Types/Config.hs index 6ab8ae6ce0..79bc9c5bf5 100644 --- a/src/Stack/Types/Config.hs +++ b/src/Stack/Types/Config.hs @@ -1111,6 +1111,8 @@ data ConfigException | Won'tCreateStackRootInDirectoryOwnedByDifferentUser (Path Abs Dir) (Path Abs Dir) -- ^ @$STACK_ROOT@, parent dir | UserDoesn'tOwnDirectory (Path Abs Dir) | FailedToCloneRepo String + | ManualGHCVariantSettingsAreIncompatibleWithSystemGHC + | NixRequiresSystemGhc deriving Typeable instance Show ConfigException where show (ParseConfigFileException configFile exception) = concat @@ -1213,6 +1215,19 @@ instance Show ConfigException where , commandName , " is installed and available to stack on your PATH environment variable." ] + show ManualGHCVariantSettingsAreIncompatibleWithSystemGHC = T.unpack $ T.concat + [ "stack can only control the " + , configMonoidGHCVariantName + , " of its own GHC installations. Please use '--no-" + , configMonoidSystemGHCName + , "'." + ] + show NixRequiresSystemGhc = T.unpack $ T.concat + [ "stack's Nix integration is incompatible with '--no-system-ghc'. " + , "Please use '--" + , configMonoidSystemGHCName + , "' or disable the Nix integration." + ] instance Exception ConfigException showOptions :: WhichSolverCmd -> String diff --git a/test/integration/IntegrationSpec.hs b/test/integration/IntegrationSpec.hs index b12d79fea1..0acccf6c2b 100644 --- a/test/integration/IntegrationSpec.hs +++ b/test/integration/IntegrationSpec.hs @@ -73,7 +73,9 @@ test :: FilePath -- ^ runghc test runghc env' currDir origStackRoot newHome name = it name $ withDir $ \dir -> do newHomeExists <- doesDirectoryExist newHome when newHomeExists (removeDirectoryRecursive newHome) - copyTree toCopyRoot origStackRoot (newHome takeFileName origStackRoot) + let newStackRoot = newHome takeFileName origStackRoot + copyTree toCopyRoot origStackRoot newStackRoot + writeFile (newStackRoot "config.yaml") "system-ghc: true" let testDir = currDir "tests" name mainFile = testDir "Main.hs" libDir = currDir "lib"