diff --git a/.azure/linux-installhs-stack.yml b/.azure/linux-installhs-stack.yml index 086354113..65dd6d5a8 100644 --- a/.azure/linux-installhs-stack.yml +++ b/.azure/linux-installhs-stack.yml @@ -32,9 +32,5 @@ jobs: displayName: Run help of `install.hs` - bash: | source .azure/linux.bashrc - stack install.hs stack-install-cabal - displayName: Run stack-install-cabal target of `install.hs` - - bash: | - source .azure/linux.bashrc - stack install.hs build-latest - displayName: Run build-latest target of `install.hs` + stack install.hs latest + displayName: Run latest target of `install.hs` diff --git a/.azure/windows-installhs-stack.yml b/.azure/windows-installhs-stack.yml index 4dfed9e9d..aed7a1526 100644 --- a/.azure/windows-installhs-stack.yml +++ b/.azure/windows-installhs-stack.yml @@ -30,9 +30,5 @@ jobs: displayName: Run help of `install.hs` - bash: | source .azure/windows.bashrc - stack install.hs stack-install-cabal - displayName: Run stack-install-cabal target of `install.hs` - - bash: | - source .azure/windows.bashrc - stack install.hs build-latest - displayName: Run build-latest target of `install.hs` + stack install.hs latest + displayName: Run latest target of `install.hs` diff --git a/README.md b/README.md index 27de2171e..6a62dbe1e 100644 --- a/README.md +++ b/README.md @@ -226,47 +226,35 @@ or using the existing alias script Running the script with cabal on windows requires a cabal version greater or equal to `3.0.0.0`. -Unfortunately, it is still required to have `stack` installed so that the install-script can locate the `local-bin` directory (on Linux `~/.local/bin`) and copy the `hie` binaries to `hie-x.y.z`, which is required for the `hie-wrapper` to function as expected. There are plans to remove this requirement and let users build hie only with one build tool or another. - For brevity, only the `stack`-based commands are presented in the following sections. -##### Install cabal using stack - -Although you can use hie for stack based projects (those which have a `stack.yaml` in the project base directory) without having cabal installed, you will need it for cabal based projects (with only a `.cabal` file or a `cabal.project` one in the project base directory). - -You can install an appropriate cabal version using stack by running: - -```bash -stack ./install.hs stack-install-cabal -``` - ##### Install specific GHC Version Install hie for the latest available and supported GHC version (and hoogle docs): ```bash -stack ./install.hs build +stack ./install.hs hie ``` Install hie for a specific GHC version (and hoogle docs): ```bash stack ./install.hs hie-8.6.5 -stack ./install.hs build-data +stack ./install.hs data ``` The Haskell IDE Engine can also be built with `cabal v2-build` instead of `stack build`. This has the advantage that you can decide how the GHC versions have been installed. -To see what GHC versions are available, the command `stack install.hs cabal-ghcs` can be used. +To see what GHC versions are available, the command `cabal-hie-install ghcs` can be used. It will list all GHC versions that are on the path and their respective installation directory. If you think, this list is incomplete, you can try to modify the PATH variable, such that the executables can be found. -Note, that the targets `cabal-build` and `cabal-build-data` depend on the found GHC versions. +Note, that the targets `hie` and `data` depend on the found GHC versions. They install Haskell IDE Engine only for the found GHC versions. An example output is: ```bash -> stack install.hs cabal-ghcs +> cabal-hie-install ghcs ****************************************************************** Found the following GHC paths: ghc-8.4.4: /opt/bin/ghc-8.4.4 @@ -278,11 +266,11 @@ ghc-8.6.2: /opt/bin/ghc-8.6.2 If your desired ghc has been found, you use it to install Haskell IDE Engine. ```bash -stack install.hs cabal-hie-8.4.4 -stack install.hs cabal-build-data +cabal-hie-install hie-8.4.4 +cabal-hie-install data ``` -In general, targets that use `cabal` instead of `stack` are prefixed with `cabal-*` and are identical to their counterpart, except they do not install a GHC if it is missing but fail. +In general, executing targets with `cabal` instead of `stack` have the same behaviour, except they do not install a GHC if it is missing but fail. ##### Multiple versions of HIE (optional) diff --git a/docs/Build.md b/docs/Build.md index 289107ba0..7868fc350 100644 --- a/docs/Build.md +++ b/docs/Build.md @@ -27,18 +27,17 @@ See the project's `README` for detailed information about installing `hie`. The build script `install.hs` defines several targets using the `shake` build system. The targets are roughly: * `hie-*`: builds and installs the `hie` binaries. Also renames the binaries to contain the correct version-number. -* `build-latest`: builds and installs `hie` for the latest available and supported `ghc` version. -* `build-data`: builds the hoogle-db required by `hie` -* `build`: builds and installs `hie` for the latest supported `ghc` version (like `build-latest`) and the hoogle-db (like `build-data`) -* `cabal-*`: execute the same task as the original target, but with `cabal` instead of `stack` +* `latest`: builds and installs `hie` for the latest available and supported `ghc` version. +* `data`: builds the hoogle-db required by `hie` +* `hie`: builds and installs `hie` for the latest supported `ghc` version (like `latest`) and the hoogle-db (like `data`) -Each `stack-*.yaml` contains references to packages in the submodules. Calling `stack` with one of those causes the build to fail if the submodules have not been initialized already. The file `shake.yaml` solves this issue invoking the `git` binary itself to update the submodules. Moreover, it specifies the correct version of `shake` and is used for installing all run-time dependencies such as `cabal` and `hoogle` if necessary. +Each `stack-*.yaml` contains references to packages in the submodules. Calling `stack` with one of those causes the build to fail if the submodules have not been initialized already. The file `shake.yaml` solves this issue invoking the `git` binary itself to update the submodules. Moreover, it specifies the correct version of `shake` and is used for installing all run-time dependencies such as `hoogle` if necessary. ### Run-time dependencies `hie` depends on a correct environment in order to function properly: -* `cabal-install`: This dependency is required by `hie` to handle correctly projects that are not `stack` based. You can install an appropriate version using `stack` with the `stack-install-cabal` target. +* `cabal-install`: This dependency is required by `hie` to handle correctly projects that are not `stack` based. You can install it using one of the methods listed here: https://www.haskell.org/cabal/#install-upgrade * The `hoogle` database: `hoogle generate` needs to be called with the most-recent `hoogle` version. ### Steps to build `hie` @@ -68,12 +67,21 @@ EOF Then `hie` can be compiled for a specific GHC version: +* For cabal prior to 3.0.0.0 ```bash export GHCP= cabal v2-install exe:hie -w $GHCP \ --write-ghc-environment-files=never --symlink-bindir=$HOME/.local/bin \ --overwrite-policy=always --reinstall ``` +* For cabal 3.0.0.0 or newer +```bash +export GHCP= +cabal v2-install exe:hie -w $GHCP \ + --write-ghc-environment-files=never --installdir=$HOME/.local/bin \ + --overwrite-policy=always --reinstall +``` +* For windows you will need cabal 3.0.0.0 and add the argument `--install-method=copy` The final step is to configure the `hie` client to use a custom `hie-wrapper` script that enables the runtime options for profiling. Such a script could look like this: @@ -88,17 +96,13 @@ The final step is to configure the `hie` client to use a custom `hie-wrapper` sc The `install.hs` script performs some checks to ensure that a correct installation is possible and provide meaningful error messages for known issues. -* `stack` needs to be up-to-date. Version `1.9.3` is required +* `stack` needs to be up-to-date. Version `2.1.1` is required * `cabal` needs to be up-to-date. Version `3.0.0.0` is required for windows systems and `2.4.1.0` for other ones. * `ghc-8.6.3` is broken on windows. Trying to install `hie-8.6.3` on windows is not possible. * When the build fails, an error message, that suggests to remove `.stack-work` directory, is displayed. ### Tradeoffs -#### `stack` is a build dependency - -Currently, `stack` is needed even if you run the script with `cabal` to get the path where install the binaries but there are plans to remove that dependency (see #1380). - #### run `install.hs` with `stack` installs a GHC before running Before the code in `install.hs` can be executed, `stack` installs a `GHC`, depending on the `resolver` field in `shake.yaml`. This is necessary if `install.hs` should be completely functional right after a fresh `git clone` without further configuration. diff --git a/install/hie-install.cabal b/install/hie-install.cabal index 47ae55591..013d246fe 100644 --- a/install/hie-install.cabal +++ b/install/hie-install.cabal @@ -31,6 +31,8 @@ library if flag(run-from-stack) cpp-options: -DRUN_FROM_STACK + else + build-depends: cabal-install-parsers flag run-from-stack description: Inform the application that it is run from stack diff --git a/install/src/Cabal.hs b/install/src/Cabal.hs index df08b53f8..5ae3dcb30 100644 --- a/install/src/Cabal.hs +++ b/install/src/Cabal.hs @@ -1,3 +1,5 @@ +{-# LANGUAGE CPP #-} + module Cabal where import Development.Shake @@ -15,16 +17,26 @@ import System.Directory ( findExecutable import Version import Print import Env -import Stack +import Data.Functor.Identity +#if RUN_FROM_STACK +import Control.Exception ( throwIO ) +#else +import Cabal.Config +#endif + +getInstallDir :: IO FilePath +#if RUN_FROM_STACK +-- we should never hit this codepath +getInstallDir = throwIO $ userError "Stack and cabal should never be mixed" +#else +getInstallDir = runIdentity . cfgInstallDir <$> readConfig +#endif execCabal :: CmdResult r => [String] -> Action r -execCabal = execCabalWithOriginalPath +execCabal = command [] "cabal" execCabal_ :: [String] -> Action () -execCabal_ = execCabalWithOriginalPath - -execCabalWithOriginalPath :: CmdResult r => [String] -> Action r -execCabalWithOriginalPath = withoutStackCachedBinaries . (command [] "cabal") +execCabal_ = command [] "cabal" cabalBuildData :: Action () cabalBuildData = do @@ -39,19 +51,9 @@ getGhcPathOfOrThrowError versionNumber = error (ghcVersionNotFoundFailMsg versionNumber) Just p -> return p -cabalBuildHie :: VersionNumber -> Action () -cabalBuildHie versionNumber = do - ghcPath <- getGhcPathOfOrThrowError versionNumber - execCabal_ - [ "v2-build" - , "-w", ghcPath - , "--write-ghc-environment-files=never" - , "--max-backjumps=5000" - , "--disable-tests"] - cabalInstallHie :: VersionNumber -> Action () cabalInstallHie versionNumber = do - localBin <- getLocalBin + localBin <- liftIO $ getInstallDir cabalVersion <- getCabalVersion ghcPath <- getGhcPathOfOrThrowError versionNumber @@ -65,6 +67,7 @@ cabalInstallHie versionNumber = do , "-w", ghcPath , "--write-ghc-environment-files=never" , installDirOpt, localBin + , "--max-backjumps=5000" , "exe:hie" , "--overwrite-policy=always" ] @@ -84,18 +87,6 @@ cabalInstallHie versionNumber = do ++ minorVerExe ++ " to " ++ localBin -installCabalWithStack :: Action () -installCabalWithStack = do - -- try to find existing `cabal` executable with appropriate version - mbc <- withoutStackCachedBinaries (liftIO (findExecutable "cabal")) - - case mbc of - Just c -> do - cabalVersion <- checkCabal - printLine $ "There is already a cabal executable in $PATH with the required minimum version: " ++ cabalVersion - -- install `cabal-install` if not already installed - Nothing -> execStackShake_ ["install", "cabal-install"] - checkCabal_ :: Action () checkCabal_ = checkCabal >> return () diff --git a/install/src/Help.hs b/install/src/Help.hs index 02b529c8e..c0f600bc6 100644 --- a/install/src/Help.hs +++ b/install/src/Help.hs @@ -78,8 +78,7 @@ helpMessage versions@BuildableVersions {..} = do [emptyTarget] [ generalTargets , defaultTargets - , stackTargets - , cabalTargets + , if isRunFromCabal then [cabalGhcsTarget] else [] , [macosIcuTarget] ] @@ -89,22 +88,6 @@ helpMessage versions@BuildableVersions {..} = do defaultTargets = [buildTarget, buildLatestTarget, buildDataTarget] ++ map hieTarget (getDefaultBuildSystemVersions versions) - stackTargets = - [ stackTarget buildTarget - , stackTarget buildLatestTarget - , stackTarget buildDataTarget - ] - ++ (if isRunFromStack then [stackTarget installCabalTarget] else []) - ++ map (stackTarget . hieTarget) stackVersions - - cabalTargets = - [ cabalGhcsTarget - , cabalTarget buildTarget - , cabalTarget buildLatestTarget - , cabalTarget buildDataTarget - ] - ++ map (cabalTarget . hieTarget) cabalVersions - -- | Empty target. Purpose is to introduce a newline between the targets emptyTarget :: (String, String) emptyTarget = ("", "") @@ -112,29 +95,19 @@ emptyTarget = ("", "") templateTarget :: (String, String) templateTarget = ("", "") -targetWithBuildSystem :: String -> TargetDescription -> TargetDescription -targetWithBuildSystem system (target, description) = - (system ++ "-" ++ target, description ++ "; with " ++ system) - -stackTarget :: TargetDescription -> TargetDescription -stackTarget = targetWithBuildSystem "stack" - -cabalTarget :: TargetDescription -> TargetDescription -cabalTarget = targetWithBuildSystem "cabal" - hieTarget :: String -> TargetDescription hieTarget version = ("hie-" ++ version, "Builds hie for GHC version " ++ version) buildTarget :: TargetDescription -buildTarget = ("build", "Build hie with the latest available GHC and the data files") +buildTarget = ("hie", "Build hie with the latest available GHC and the data files") buildLatestTarget :: TargetDescription -buildLatestTarget = ("build-latest", "Build hie with the latest available GHC") +buildLatestTarget = ("latest", "Build hie with the latest available GHC") buildDataTarget :: TargetDescription buildDataTarget = - ("build-data", "Get the required data-files for `hie` (Hoogle DB)") + ("data", "Get the required data-files for `hie` (Hoogle DB)") -- special targets @@ -146,25 +119,6 @@ helpTarget = ("help", "Show help message including all targets") cabalGhcsTarget :: TargetDescription cabalGhcsTarget = - ( "cabal-ghcs" + ( "ghcs" , "Show all GHC versions that can be installed via `cabal-build`." ) - -installCabalTarget :: TargetDescription -installCabalTarget = - ( "install-cabal" - , "Install the cabal executable. It will install the required minimum version for hie (currently " - ++ versionToString requiredCabalVersion - ++ ") if it isn't already present in $PATH" - ) - --- | Creates a message of the form "a, b, c and d", where a,b,c,d are GHC versions. --- If there is no GHC in the list of `hieVersions` -allVersionMessage :: [String] -> String -allVersionMessage wordList = case wordList of - [] -> "" - [a] -> show a - (a : as) -> - let msg = intersperse ", " wordList - lastVersion = last msg - in concat $ init (init msg) ++ [" and ", lastVersion] diff --git a/install/src/HieInstall.hs b/install/src/HieInstall.hs index ba1c03b78..b0e723ac3 100644 --- a/install/src/HieInstall.hs +++ b/install/src/HieInstall.hs @@ -48,88 +48,64 @@ defaultMain = do -- used for cabal-based targets ghcPaths <- findInstalledGhcs - let ghcVersions = map fst ghcPaths + let cabalVersions = map fst ghcPaths -- used for stack-based targets - hieVersions <- getHieVersions + stackVersions <- getHieVersions - let versions = BuildableVersions { stackVersions = hieVersions - , cabalVersions = ghcVersions - } + let versions = if isRunFromStack then stackVersions else cabalVersions - let latestVersion = last hieVersions + let toolsVersions = BuildableVersions stackVersions cabalVersions - putStrLn $ "run from: " ++ buildSystem + let latestVersion = last versions shakeArgs shakeOptions { shakeFiles = "_build" } $ do want ["short-help"] -- general purpose targets phony "submodules" updateSubmodules - phony "cabal" installCabalWithStack phony "short-help" shortHelpMessage - phony "all" shortHelpMessage - phony "help" (helpMessage versions) - phony "check-stack" checkStack - phony "check-cabal" checkCabal_ - - phony "cabal-ghcs" $ do - let - msg = - "Found the following GHC paths: \n" - ++ unlines - (map (\(version, path) -> "ghc-" ++ version ++ ": " ++ path) - ghcPaths - ) - printInStars msg - - -- default-targets - phony "build" $ need [buildSystem ++ "-build"] - phony "build-latest" $ need [buildSystem ++ "-build-latest"] - phony "build-data" $ need [buildSystem ++ "-build-data"] - forM_ - (getDefaultBuildSystemVersions versions) - (\version -> - phony ("hie-" ++ version) $ need [buildSystem ++ "-hie-" ++ version] - ) - - -- stack specific targets - when isRunFromStack (phony "stack-install-cabal" (need ["cabal"])) - phony "stack-build-latest" (need ["stack-hie-" ++ last hieVersions]) - phony "stack-build" (need ["build-data", "stack-build-latest"]) + phony "help" (helpMessage toolsVersions) - phony "stack-build-data" $ do + phony "check" (if isRunFromStack then checkStack else checkCabal_) + + phony "data" $ do need ["submodules"] - need ["check-stack"] - stackBuildData + need ["check"] + if isRunFromStack then stackBuildData else cabalBuildData + forM_ - hieVersions - (\version -> phony ("stack-hie-" ++ version) $ do + versions + (\version -> phony ("hie-" ++ version) $ do need ["submodules"] - need ["check-stack"] - stackBuildHie version - stackInstallHie version + need ["check"] + if isRunFromStack then do + stackBuildHie version + stackInstallHie version + else + cabalInstallHie version ) + phony "latest" (need ["hie-" ++ latestVersion]) + phony "hie" (need ["data", "latest"]) + -- cabal specific targets - phony "cabal-build-latest" (need ["cabal-hie-" ++ last ghcVersions]) - phony "cabal-build" (need ["build-data", "cabal-build-latest"]) - phony "cabal-build-data" $ do - need ["submodules"] - need ["cabal"] - cabalBuildData - forM_ - ghcVersions - (\version -> phony ("cabal-hie-" ++ version) $ do - need ["submodules"] - need ["cabal"] - cabalInstallHie version - ) + when isRunFromCabal $ do + + phony "ghcs" $ do + let + msg = + "Found the following GHC paths: \n" + ++ unlines + (map (\(version, path) -> "ghc-" ++ version ++ ": " ++ path) + ghcPaths + ) + printInStars msg -- macos specific targets phony "icu-macos-fix" (need ["icu-macos-fix-install"] >> need ["icu-macos-fix-build"]) phony "icu-macos-fix-install" (command_ [] "brew" ["install", "icu4c"]) - phony "icu-macos-fix-build" $ mapM_ buildIcuMacosFix hieVersions + phony "icu-macos-fix-build" $ mapM_ buildIcuMacosFix versions buildIcuMacosFix :: VersionNumber -> Action () diff --git a/install/src/Stack.hs b/install/src/Stack.hs index dd054f93e..c33db4432 100644 --- a/install/src/Stack.hs +++ b/install/src/Stack.hs @@ -31,11 +31,6 @@ stackInstallHie versionNumber = do copyFile (localBinDir hie) (localBinDir "hie-" ++ dropExtension versionNumber <.> exe) -buildCopyCompilerTool :: VersionNumber -> Action () -buildCopyCompilerTool versionNumber = - execStackWithGhc_ versionNumber ["build", "--copy-compiler-tool"] - - -- | check `stack` has the required version checkStack :: Action () checkStack = do @@ -101,30 +96,3 @@ stackBuildFailMsg = ++ "If this does not work, open an issue at \n" ++ "\thttps://github.com/haskell/haskell-ide-engine" --- |Run actions without the stack cached binaries -withoutStackCachedBinaries :: Action a -> Action a -withoutStackCachedBinaries action = do - - mbPath <- liftIO (lookupEnv "PATH") - - case (mbPath, isRunFromStack) of - - (Just paths, True) -> do - snapshotDir <- trimmedStdout <$> execStackShake ["path", "--snapshot-install-root"] - localInstallDir <- trimmedStdout <$> execStackShake ["path", "--local-install-root"] - - let cacheBinPaths = [snapshotDir "bin", localInstallDir "bin"] - let origPaths = removePathsContaining cacheBinPaths paths - - liftIO (setEnv "PATH" origPaths) - a <- action - liftIO (setEnv "PATH" paths) - return a - - otherwise -> action - - where removePathsContaining strs path = - joinPaths (filter (not . containsAny) (splitSearchPath path)) - where containsAny p = any (`isInfixOf` p) strs - - joinPaths = intercalate [searchPathSeparator] \ No newline at end of file