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>
This commit is contained in:
Pepe Iborra 2020-02-20 11:32:20 +00:00 committed by GitHub
parent 5bea92f9d3
commit 48a7867a07
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 78 additions and 3 deletions

View File

@ -19,6 +19,9 @@ import Control.DeepSeq (NFData)
import Control.Exception
import Control.Monad.Extra
import Control.Monad.IO.Class
import qualified Crypto.Hash.SHA1 as H
import qualified Data.ByteString.Char8 as B
import Data.ByteString.Base16
import Data.Default
import System.Time.Extra
import Development.IDE.Core.Debouncer
@ -57,15 +60,28 @@ import qualified Data.Map.Strict as Map
import GHC hiding (def)
import GHC.Generics (Generic)
import qualified GHC.Paths
import DynFlags
import HIE.Bios.Environment
import HIE.Bios
import HIE.Bios.Cradle
import HIE.Bios.Types
-- Prefix for the cache path
cacheDir :: String
cacheDir = "ghcide"
-- Set the GHC libdir to the nix libdir if it's present.
getLibdir :: IO FilePath
getLibdir = fromMaybe GHC.Paths.libdir <$> lookupEnv "NIX_GHC_LIBDIR"
getCacheDir :: [String] -> IO FilePath
getCacheDir opts = IO.getXdgDirectory IO.XdgCache (cacheDir </> opts_hash)
where
-- Create a unique folder per set of different GHC options, assuming that each different set of
-- GHC options will create incompatible interface files.
opts_hash = B.unpack $ encode $ H.finalize $ H.updates H.init (map B.pack opts)
ghcideVersion :: IO String
ghcideVersion = do
path <- getExecutablePath
@ -224,14 +240,50 @@ getComponentOptions cradle = do
createSession :: ComponentOptions -> IO HscEnvEq
createSession opts = do
createSession (ComponentOptions theOpts _) = do
libdir <- getLibdir
cacheDir <- Main.getCacheDir theOpts
env <- runGhc (Just libdir) $ do
_targets <- initSession opts
dflags <- getSessionDynFlags
(dflags', _targets) <- addCmdOpts theOpts dflags
_ <- setSessionDynFlags $
-- disabled, generated directly by ghcide instead
flip gopt_unset Opt_WriteInterface $
-- disabled, generated directly by ghcide instead
-- also, it can confuse the interface stale check
dontWriteHieFiles $
setHiDir cacheDir $
setDefaultHieDir cacheDir $
setIgnoreInterfacePragmas $
setLinkerOptions $
disableOptimisation dflags'
getSession
initDynLinker env
newHscEnvEq env
-- we don't want to generate object code so we compile to bytecode
-- (HscInterpreted) which implies LinkInMemory
-- HscInterpreted
setLinkerOptions :: DynFlags -> DynFlags
setLinkerOptions df = df {
ghcLink = LinkInMemory
, hscTarget = HscNothing
, ghcMode = CompManager
}
setIgnoreInterfacePragmas :: DynFlags -> DynFlags
setIgnoreInterfacePragmas df =
gopt_set (gopt_set df Opt_IgnoreInterfacePragmas) Opt_IgnoreOptimChanges
disableOptimisation :: DynFlags -> DynFlags
disableOptimisation df = updOptLevel 0 df
setHiDir :: FilePath -> DynFlags -> DynFlags
setHiDir f d =
-- override user settings to avoid conflicts leading to recompilation
d { hiDir = Just f}
cradleToSession :: Maybe FilePath -> Cradle a -> Action HscEnvEq
cradleToSession mbYaml cradle = do

View File

@ -171,7 +171,10 @@ executable ghcide
hslogger,
base == 4.*,
binary,
base16-bytestring >=0.1.1 && <0.2,
bytestring,
containers,
cryptohash-sha1 >=0.11.100 && <0.12,
data-default,
deepseq,
directory,

View File

@ -12,6 +12,8 @@ module Development.IDE.GHC.Compat(
mkHieFile,
writeHieFile,
readHieFile,
setDefaultHieDir,
dontWriteHieFiles,
hPutStringBuffer,
includePathsGlobal,
includePathsQuote,
@ -156,3 +158,19 @@ pattern IEThingAll a <-
#else
GHC.IEThingAll a
#endif
setDefaultHieDir :: FilePath -> DynFlags -> DynFlags
setDefaultHieDir _f d =
#if MIN_GHC_API_VERSION(8,8,0)
d { hieDir = hieDir d `mappend` Just _f}
#else
d
#endif
dontWriteHieFiles :: DynFlags -> DynFlags
dontWriteHieFiles d =
#if MIN_GHC_API_VERSION(8,8,0)
gopt_unset d Opt_WriteHie
#else
d
#endif

View File

@ -19,6 +19,8 @@ module Development.IDE.GHC.Util(
textToStringBuffer,
readFileUtf8,
hDuplicateTo',
setDefaultHieDir,
dontWriteHieFiles
) where
import Control.Concurrent
@ -27,7 +29,6 @@ import Data.Maybe
import Data.Typeable
import qualified Data.ByteString.Internal as BS
import Fingerprint
import GHC
import GhcMonad
import GhcPlugins hiding (Unique)
import Data.IORef
@ -52,6 +53,7 @@ import Lexer
import StringBuffer
import System.FilePath
import Development.IDE.GHC.Compat as GHC
import Development.IDE.Types.Location