@@ -19,6 +19,9 @@ import Control.DeepSeq (NFData)
1919import Control.Exception
2020import Control.Monad.Extra
2121import Control.Monad.IO.Class
22+import qualified Crypto.Hash.SHA1 as H
23+import qualified Data.ByteString.Char8 as B
24+import Data.ByteString.Base16
2225import Data.Default
2326import System.Time.Extra
2427import Development.IDE.Core.Debouncer
@@ -57,15 +60,28 @@ import qualified Data.Map.Strict as Map
5760import GHC hiding (def)
5861import GHC.Generics (Generic)
5962import qualified GHC.Paths
63+import DynFlags
6064
65+import HIE.Bios.Environment
6166import HIE.Bios
6267import HIE.Bios.Cradle
6368import HIE.Bios.Types
6469
70+-- Prefix for the cache path
71+cacheDir :: String
72+cacheDir = "ghcide"
73+
6574-- Set the GHC libdir to the nix libdir if it's present.
6675getLibdir :: IO FilePath
6776getLibdir = fromMaybe GHC.Paths.libdir <$> lookupEnv "NIX_GHC_LIBDIR"
6877
78+getCacheDir :: [String] -> IO FilePath
79+getCacheDir opts = IO.getXdgDirectory IO.XdgCache (cacheDir </> opts_hash)
80+ where
81+ -- Create a unique folder per set of different GHC options, assuming that each different set of
82+ -- GHC options will create incompatible interface files.
83+ opts_hash = B.unpack $ encode $ H.finalize $ H.updates H.init (map B.pack opts)
84+
6985ghcideVersion :: IO String
7086ghcideVersion = do
7187 path <- getExecutablePath
@@ -224,14 +240,50 @@ getComponentOptions cradle = do
224240
225241
226242createSession :: ComponentOptions -> IO HscEnvEq
227−createSession opts = do
243+createSession (ComponentOptions theOpts _) = do
228244 libdir <- getLibdir
245+
246+ cacheDir <- Main.getCacheDir theOpts
247+
229248 env <- runGhc (Just libdir) $ do
230− _targets <- initSession opts
249+ dflags <- getSessionDynFlags
250+ (dflags', _targets) <- addCmdOpts theOpts dflags
251+ _ <- setSessionDynFlags $
252+ -- disabled, generated directly by ghcide instead
253+ flip gopt_unset Opt_WriteInterface $
254+ -- disabled, generated directly by ghcide instead
255+ -- also, it can confuse the interface stale check
256+ dontWriteHieFiles $
257+ setHiDir cacheDir $
258+ setDefaultHieDir cacheDir $
259+ setIgnoreInterfacePragmas $
260+ setLinkerOptions $
261+ disableOptimisation dflags'
231262 getSession
232263 initDynLinker env
233264 newHscEnvEq env
234265
266+-- we don't want to generate object code so we compile to bytecode
267+-- (HscInterpreted) which implies LinkInMemory
268+-- HscInterpreted
269+setLinkerOptions :: DynFlags -> DynFlags
270+setLinkerOptions df = df {
271+ ghcLink = LinkInMemory
272+ , hscTarget = HscNothing
273+ , ghcMode = CompManager
274+ }
275+
276+setIgnoreInterfacePragmas :: DynFlags -> DynFlags
277+setIgnoreInterfacePragmas df =
278+ gopt_set (gopt_set df Opt_IgnoreInterfacePragmas) Opt_IgnoreOptimChanges
279+
280+disableOptimisation :: DynFlags -> DynFlags
281+disableOptimisation df = updOptLevel 0 df
282+
283+setHiDir :: FilePath -> DynFlags -> DynFlags
284+setHiDir f d =
285+ -- override user settings to avoid conflicts leading to recompilation
286+ d { hiDir = Just f}
235287
236288cradleToSession :: Maybe FilePath -> Cradle a -> Action HscEnvEq
237289cradleToSession mbYaml cradle = do