@@ -19,6 +19,9 @@ import Control.DeepSeq (NFData)
19import Control.Exception
19import Control.Exception
20import Control.Monad.Extra
20import Control.Monad.Extra
21import Control.Monad.IO.Class
21import 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
22import Data.Default
25import Data.Default
23import System.Time.Extra
26import System.Time.Extra
24import Development.IDE.Core.Debouncer
27import Development.IDE.Core.Debouncer
@@ -57,15 +60,28 @@ import qualified Data.Map.Strict as Map
57import GHC hiding (def)
60import GHC hiding (def)
58import GHC.Generics (Generic)
61import GHC.Generics (Generic)
59import qualified GHC.Paths
62import qualified GHC.Paths
65+import HIE.Bios.Environment
61import HIE.Bios
66import HIE.Bios
62import HIE.Bios.Cradle
67import HIE.Bios.Cradle
63import HIE.Bios.Types
68import HIE.Bios.Types
70+-- Prefix for the cache path
65-- Set the GHC libdir to the nix libdir if it's present.
74-- Set the GHC libdir to the nix libdir if it's present.
66getLibdir :: IO FilePath
75getLibdir :: IO FilePath
67getLibdir = fromMaybe GHC.Paths.libdir <$> lookupEnv "NIX_GHC_LIBDIR"
76getLibdir = fromMaybe GHC.Paths.libdir <$> lookupEnv "NIX_GHC_LIBDIR"
78+getCacheDir :: [String] -> IO FilePath
79+getCacheDir opts = IO.getXdgDirectory IO.XdgCache (cacheDir </> opts_hash)
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)
69ghcideVersion :: IO String
85ghcideVersion :: IO String
70ghcideVersion = do
86ghcideVersion = do
71 path <- getExecutablePath
87 path <- getExecutablePath
@@ -224,14 +240,50 @@ getComponentOptions cradle = do
226createSession :: ComponentOptions -> IO HscEnvEq
242createSession :: ComponentOptions -> IO HscEnvEq
227−createSession opts = do
243+createSession (ComponentOptions theOpts _) = do
228 libdir <- getLibdir
244 libdir <- getLibdir
246+ cacheDir <- Main.getCacheDir theOpts
229 env <- runGhc (Just libdir) $ do
248 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
258+ setDefaultHieDir cacheDir $
259+ setIgnoreInterfacePragmas $
261+ disableOptimisation dflags'
231 getSession
262 getSession
232 initDynLinker env
263 initDynLinker env
233 newHscEnvEq env
264 newHscEnvEq env
266+-- we don't want to generate object code so we compile to bytecode
267+-- (HscInterpreted) which implies LinkInMemory
269+setLinkerOptions :: DynFlags -> DynFlags
270+setLinkerOptions df = df {
271+ ghcLink = LinkInMemory
272+ , hscTarget = HscNothing
273+ , ghcMode = CompManager
276+setIgnoreInterfacePragmas :: DynFlags -> DynFlags
277+setIgnoreInterfacePragmas df =
278+ gopt_set (gopt_set df Opt_IgnoreInterfacePragmas) Opt_IgnoreOptimChanges
280+disableOptimisation :: DynFlags -> DynFlags
281+disableOptimisation df = updOptLevel 0 df
283+setHiDir :: FilePath -> DynFlags -> DynFlags
285+ -- override user settings to avoid conflicts leading to recompilation
236cradleToSession :: Maybe FilePath -> Cradle a -> Action HscEnvEq
288cradleToSession :: Maybe FilePath -> Cradle a -> Action HscEnvEq
237cradleToSession mbYaml cradle = do
289cradleToSession mbYaml cradle = do