Commit 2d7dd028 authored by Matthew Pickering's avatar Matthew Pickering Committed by Marge Bot

Hadrian: Add ./hadrian/ghci.sh script for fast development feedback

Running the `./hadrian/ghci` target will load the main compiler into
a ghci session. This is intended for fast development feedback, modules are only
typechecked so it isn't possible to run any functions in the repl.

You can also use this target with `ghcid`.

The first time this command is run hadrian will need to compile a few dependencies
which will take 1-2 minutes. Loading GHC into GHCi itself takes about 30 seconds.

Internally this works by calling a new hadrian target called `tool-args`.
This target prints out the package and include flags which are necessary
to load files into ghci. The same target is intended to be used by other
tooling which uses the GHC API in order to set up the correct GHC API
session. For example, using this target it is also possible to use HIE
when developing on GHC.
parent 4cf2160a
......@@ -158,6 +158,27 @@ build stage2:lib:text
build stage1:exe:haddock
```
#### Fast feedback using ghci
Running the `./hadrian/ghci.sh` script will load the main compiler into
a ghci session. This is intended for fast development feedback, modules are only
typechecked so it isn't possible to run any functions in the repl.
```
./hadrian/ghci.sh
```
You can also use this target with `ghcid`.
```
ghcid --command="./hadrian/ghci.sh"
```
The first time this command is run hadrian will need to compile a few dependencies
which will take 1-2 minutes. Loading GHC into GHCi itself takes about 30 seconds and
reloads after that take in the region of 1-5 seconds depending on which modules
need to be recompiled.
#### Testing
To run GHC testsuite, use `build test`. See
......@@ -203,6 +224,23 @@ a compiler built using Stage2. This is useful for cross-compilation. Detailed
instructions can be found in the corresponding
[part of the user settings manual](doc/user-settings.md#specifying-the-final-stage-to-build).
#### Integrating Hadrian into other tooling
The `tool-args` target is designed to allow hadrian to be integrated into other
tooling which uses the GHC API.
`tool-args` prints out a list of flags which hadrian will use to compile
a module in the `compiler` directory. Using these flags you can then set up
a GHC API session with the correct environment to load a module into your own
GHC session. This is how `haskell-ide-engine` is able to support hadrian.
```
> ./hadrian/build.sh tool-args
-hide-all-packages -no-user-package-db -package-db _build/stage0/lib/packag...
```
The `./hadrian/ghci.sh` script is implemented using this target.
Troubleshooting
---------------
......
#!/usr/bin/env bash
ghci $(TERM=dumb CABFLAGS=-v0 . "hadrian/build.cabal.sh" tool-args -q --build-root=.hadrian_ghci --flavour=ghc-in-ghci "$@") -fno-code -fwrite-interface -hidir=.hadrian_ghci/interface -O0 ghc/Main.hs
......@@ -97,6 +97,7 @@ executable hadrian
, Settings.Flavours.Quick
, Settings.Flavours.QuickCross
, Settings.Flavours.Quickest
, Settings.Flavours.GhcInGhci
, Settings.Packages
, Settings.Warnings
, Stage
......
......@@ -45,7 +45,11 @@ instance NFData CcMode
-- * Compile a C source file.
-- * Extract source dependencies by passing @-M@ command line argument.
-- * Link object files & static libraries into an executable.
data GhcMode = CompileHs | CompileCWithGhc | FindHsDependencies | LinkHs
data GhcMode = CompileHs
| CompileCWithGhc
| FindHsDependencies
| LinkHs
| ToolArgs
deriving (Eq, Generic, Show)
instance Binary GhcMode
......
......@@ -50,6 +50,7 @@ main = do
Rules.SourceDist.sourceDistRules
Rules.Test.testRules
Rules.topLevelTargets
Rules.toolArgsTarget
shakeArgsWith options CommandLine.optDescrs $ \_ targets -> do
Environment.setupEnvironment
......
......@@ -3,7 +3,7 @@ module Oracles.Setting (
getSettingList, anyTargetPlatform, anyTargetOs, anyTargetArch, anyHostOs,
ghcWithInterpreter, ghcEnableTablesNextToCode, useLibFFIForAdjustors,
ghcCanonVersion, cmdLineLengthLimit, iosHost, osxHost, windowsHost,
hostSupportsRPaths, topDirectory, libsuf
hostSupportsRPaths, topDirectory, libsuf, ghcVersionStage
) where
import Hadrian.Expression
......
module Rules (buildRules, oracleRules, packageTargets, topLevelTargets) where
module Rules (buildRules, oracleRules, packageTargets, topLevelTargets
, toolArgsTarget ) where
import qualified Hadrian.Oracles.ArgsHash
import qualified Hadrian.Oracles.Cabal.Rules
......@@ -26,6 +27,38 @@ import Target
import UserSettings
import Utilities
-- | @tool-args@ is used by tooling in order to get the arguments necessary
-- to set up a GHC API session which can compile modules from GHC. When
-- run, the target prints out the arguments that would be passed to @ghc@
-- during normal compilation to @stdout@.
--
-- This target is called by the `ghci.sh` script in order to load all of GHC's
-- modules into GHCi.
toolArgsTarget :: Rules ()
toolArgsTarget = do
"tool-args" ~> do
let fake_target = target (Context Stage0 compiler dynamic)
(Ghc ToolArgs Stage0) [] ["ignored"]
-- need the autogenerated files so that they are precompiled
generatedGhcDependencies Stage0 >>= need
interpret fake_target Rules.Generate.compilerDependencies >>= need
root <- buildRoot
let dir = buildDir (vanillaContext Stage0 compiler)
need [ root <//> dir -/- "Config.hs" ]
need [ root <//> dir -/- "Fingerprint.hs" ]
need [ root <//> dir -/- "Parser.hs" ]
need [ root <//> dir -/- "Lexer.hs" ]
need [ root <//> dir -/- "CmmParse.hs" ]
need [ root <//> dir -/- "CmmLex.hs" ]
-- Find out the arguments that are needed to load a module into the
-- session
arg_list <- interpret fake_target getArgs
liftIO $ putStrLn (intercalate " " arg_list)
allStages :: [Stage]
allStages = [minBound .. maxBound]
......
......@@ -18,6 +18,7 @@ import Settings.Flavours.Profiled
import Settings.Flavours.Quick
import Settings.Flavours.Quickest
import Settings.Flavours.QuickCross
import Settings.Flavours.GhcInGhci
getArgs :: Args
getArgs = expr flavour >>= args
......@@ -38,7 +39,8 @@ hadrianFlavours =
[ defaultFlavour, developmentFlavour Stage1, developmentFlavour Stage2
, performanceFlavour, profiledFlavour, quickFlavour, quickestFlavour
, quickCrossFlavour
, performanceLlvmFlavour, profiledLlvmFlavour, quickLlvmFlavour ]
, performanceLlvmFlavour, profiledLlvmFlavour, quickLlvmFlavour
, ghcInGhciFlavour ]
flavour :: Action Flavour
flavour = do
......
......@@ -11,7 +11,18 @@ import qualified Context as Context
import Rules.Libffi (libffiName)
ghcBuilderArgs :: Args
ghcBuilderArgs = mconcat [compileAndLinkHs, compileC, findHsDependencies]
ghcBuilderArgs = mconcat [ compileAndLinkHs, compileC, findHsDependencies
, toolArgs]
toolArgs :: Args
toolArgs = do
builder (Ghc ToolArgs) ? mconcat
[ packageGhcArgs
, includeGhcArgs
, map ("-optc" ++) <$> getStagedSettingList ConfCcArgs
, map ("-optP" ++) <$> getStagedSettingList ConfCppArgs
, map ("-optP" ++) <$> getContextData cppOpts
]
compileAndLinkHs :: Args
compileAndLinkHs = (builder (Ghc CompileHs) ||^ builder (Ghc LinkHs)) ? do
......
module Settings.Flavours.GhcInGhci (ghcInGhciFlavour) where
import Expression
import Flavour
import {-# SOURCE #-} Settings.Default
import Settings.Flavours.Common
-- Please update doc/flavours.md when changing this file.
ghcInGhciFlavour :: Flavour
ghcInGhciFlavour = defaultFlavour
{ name = "ghc-in-ghci"
, args = defaultBuilderArgs <> ghciArgs <> defaultPackageArgs
, libraryWays = pure [vanilla, dynamic]
, rtsWays = pure [vanilla, threaded, dynamic]
, dynamicGhcPrograms = return False }
ghciArgs :: Args
ghciArgs = sourceArgs SourceArgs
{ hsDefault = mconcat $
[ pure ["-O0", "-H64m"]
, naturalInBaseFixArgs
]
, hsLibrary = mempty
, hsCompiler = mempty
, hsGhc = mempty }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment