on master help sign in
Local hidir and hiedir folders to avoid conflicts with Cabal (#441)

* Local hidir and hiedir folders to avoid conflicts with Cabal hi files created by ghcide would have different optimization settings, triggering Cabal recompilation if they were stored in Cabal folders hie files would end up in the src folder as -hiedir is not set by Cabal Telling GHC to write interface/hie files is pointless since we do it ourselves, and it also leads to the recompilation checker getting confused Using hie-bios initSession does things like setting up the cache directory for interface files and other things which ghcide would rather manage itself. * linker options Co-authored-by: Matthew Pickering <matthewtpickering@gmail.com>

commit48a7867a078b6eea55c868e2afa8cc3a9aec1159 authorPepe Iborra <pepeiborra@gmail.com> dateThu 20 Feb 2020, 11:32 (7 years ago) parent5bea92f
4 files changed+78−3
exe/Main.hs+54−2 ghcide.cabal+3 src/Development/IDE/GHC/Compat.hs+18 src/Development/IDE/GHC/Util.hs+3−1
exe/Main.hs+54−2
@@ -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
ghcide.cabal+3
@@ -171,7 +171,10 @@ executable ghcide
171171 hslogger,
172172 base == 4.*,
173173 binary,
174+ base16-bytestring >=0.1.1 && <0.2,
175+ bytestring,
174176 containers,
177+ cryptohash-sha1 >=0.11.100 && <0.12,
175178 data-default,
176179 deepseq,
177180 directory,
src/Development/IDE/GHC/Compat.hs+18
@@ -12,6 +12,8 @@ module Development.IDE.GHC.Compat(
1212 mkHieFile,
1313 writeHieFile,
1414 readHieFile,
15+ setDefaultHieDir,
16+ dontWriteHieFiles,
1517 hPutStringBuffer,
1618 includePathsGlobal,
1719 includePathsQuote,
@@ -156,3 +158,19 @@ pattern IEThingAll a <-
156158#else
157159 GHC.IEThingAll a
158160#endif
161+
162+setDefaultHieDir :: FilePath -> DynFlags -> DynFlags
163+setDefaultHieDir _f d =
164+#if MIN_GHC_API_VERSION(8,8,0)
165+ d { hieDir = hieDir d `mappend` Just _f}
166+#else
167+ d
168+#endif
169+
170+dontWriteHieFiles :: DynFlags -> DynFlags
171+dontWriteHieFiles d =
172+#if MIN_GHC_API_VERSION(8,8,0)
173+ gopt_unset d Opt_WriteHie
174+#else
175+ d
176+#endif
src/Development/IDE/GHC/Util.hs+3−1
@@ -19,6 +19,8 @@ module Development.IDE.GHC.Util(
1919 textToStringBuffer,
2020 readFileUtf8,
2121 hDuplicateTo',
22+ setDefaultHieDir,
23+ dontWriteHieFiles
2224 ) where
2325
2426import Control.Concurrent
@@ -27,7 +29,6 @@ import Data.Maybe
2729import Data.Typeable
2830import qualified Data.ByteString.Internal as BS
2931import Fingerprint
30−import GHC
3132import GhcMonad
3233import GhcPlugins hiding (Unique)
3334import Data.IORef
@@ -52,6 +53,7 @@ import Lexer
5253import StringBuffer
5354import System.FilePath
5455
56+import Development.IDE.GHC.Compat as GHC
5557import Development.IDE.Types.Location
5658
5759