Hadrian: Add ./hadrian/ghci.sh script for fast development feedback
authorMatthew Pickering <matthewtpickering@gmail.com>
Sun, 10 Mar 2019 17:43:10 +0000 (17:43 +0000)
committerMarge Bot <ben+marge-bot@smart-cactus.org>
Tue, 12 Mar 2019 13:04:52 +0000 (09:04 -0400)
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.

hadrian/README.md
hadrian/ghci.sh [new file with mode: 0755]
hadrian/hadrian.cabal
hadrian/src/Builder.hs
hadrian/src/Main.hs
hadrian/src/Oracles/Setting.hs
hadrian/src/Rules.hs
hadrian/src/Settings.hs
hadrian/src/Settings/Builders/Ghc.hs
hadrian/src/Settings/Flavours/GhcInGhci.hs [new file with mode: 0644]

index 179d9d0..77c3cd0 100644 (file)
@@ -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
 ---------------
 
diff --git a/hadrian/ghci.sh b/hadrian/ghci.sh
new file mode 100755 (executable)
index 0000000..4a70946
--- /dev/null
@@ -0,0 +1,3 @@
+#!/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
index a5a1ead..a0b3648 100644 (file)
@@ -97,6 +97,7 @@ executable hadrian
                        , Settings.Flavours.Quick
                        , Settings.Flavours.QuickCross
                        , Settings.Flavours.Quickest
+                       , Settings.Flavours.GhcInGhci
                        , Settings.Packages
                        , Settings.Warnings
                        , Stage
index 6d334d8..d855aa5 100644 (file)
@@ -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
index 083e683..fe5dbbb 100644 (file)
@@ -50,6 +50,7 @@ main = do
             Rules.SourceDist.sourceDistRules
             Rules.Test.testRules
             Rules.topLevelTargets
+            Rules.toolArgsTarget
 
     shakeArgsWith options CommandLine.optDescrs $ \_ targets -> do
         Environment.setupEnvironment
index 4666539..a869a31 100644 (file)
@@ -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
index c5be5a7..e4de23f 100644 (file)
@@ -1,4 +1,5 @@
-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]
 
index bc0f8ce..3089c0a 100755 (executable)
@@ -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
index 0d0d58a..940eab5 100644 (file)
@@ -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
diff --git a/hadrian/src/Settings/Flavours/GhcInGhci.hs b/hadrian/src/Settings/Flavours/GhcInGhci.hs
new file mode 100644 (file)
index 0000000..82fd0f2
--- /dev/null
@@ -0,0 +1,25 @@
+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 }