-
Notifications
You must be signed in to change notification settings - Fork 63
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add getRuntimeGhcLibDir and getRuntimeGhcVersion, via runGhc #207
Conversation
Closes #151 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the design!
Since this is a big breaking change that is very important to get right, we will wait for some feedback before merging it.
, getGhcPath = | ||
-- We're being lazy here and just returning the ghc path for the | ||
-- first non-none cradle. This shouldn't matter in practice: all | ||
-- sub cradles should be using the same ghc version! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably be "must"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure about that, the multi combinations could give us as first ghc a wrong one. F.e. if you use a direct cradle it can give us the ghc on path but stack or cabal the ghc configured for the project.
However it is probable that the direct cradle could work with the build tool one but not the other way around.
Would be not feasible return a list of unique ghc's and let the client code pick the first one or handle the list in other way? i can imagine you could choose the newer ghc, f.e.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ghc libdir should be the same ghc version for each sub-cradle though. This would mean it doesn't matter which one is used to load the ghc session
The only case where it would make a difference would be if two sub-cradles actually had different ghc versions, and then returned two different ghc libdirs of different ghc versions.
But then in that case ghcide/hls wouldn't be able to load them both anyway!
I guess we could return a list anyway for ghcide/hls and they could just called head
. But I think it would be nice to handle as much of this stuff in hie-bios as possible
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Uh i completly missed that comment, sorry
Actually i am not sure if return a list without knowing which cradle is the source of each ghc version is a good idea.
I dont have an alternative that it is simple, maybe return an error or warning if not all ghcs are the same version? 🤔
If you think that this could be merged as is, it will be fine for me too
src/HIE/Bios/Environment.hs
Outdated
-- hie-bios compiled on, so we avoid using it unless we have to! | ||
getGhcLibDir :: Cradle a -> IO FilePath | ||
getGhcLibDir cradle = | ||
fmap (fromMaybe Paths.libdir) $ runMaybeT $ fromNix <|> fromCradle |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we know what should take precedence?
In my experience with nix, ghc is wrapped to give the correct libdir.
The order should be in my opinion: Cradle Ghc -> Nix env var -> Paths.libdir
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As ghc-paths will be wrong in the general case maybe we should remove it and returns IO (Maybe Filepath)
to make clear we cant return it for all cases in a reliable way and force the client code handle that possibility (maybe using ghc-paths at the end!)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My aim here was to mirror what currently happens inside ghcide/hls, and I presume this nix env var might be used for the direct cradles where it's calling ghc
without cabal or stack: https://github.com/digital-asset/ghcide/blob/9e984b56cfb62a83829975210ce3f14c668912f6/docs/Setup.md#issues-with-nix
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the client code is just going to end up calling ghc-paths then shouldn't we just do it here as well? We might want to rename getGhcLibDir
to something more honest though like mostlyAccurateGuessGhcLibDir
, since the only scenario where ghc-paths doesn't work will be when moving binaries across machines. On the other hand, if we are using static binaries then we would really want to error here instead of silently giving the wrong path. But then we would end up splitting the libdir logic even further back into the clients
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well i suppose client code could do a final sanity check executing the ghc returned by the cradle (--numeric-version
?) and catch the error. Not elegant but doable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jneira getGhcOnPathLibDir
should now do a check of the ghc version beforehand now
src/HIE/Bios/Ghc/Api.hs
Outdated
@@ -32,29 +31,25 @@ import HIE.Bios.Flags | |||
---------------------------------------------------------------- | |||
|
|||
-- | Converting the 'Ghc' monad to the 'IO' monad. All exceptions are ignored and logged. | |||
withGHC :: FilePath -- ^ A target file displayed in an error message. | |||
withGHC :: Cradle c -- ^ The cradle to use for resolving the lib dir |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not entirely sure I like this API. The ghc session is not dependent on the cradle, only on the libdir.
To me, this usage sends a signal that the cradle is somehow used in the session and needs to be known before launching the session. (my opinion is debatable here)
(btw, neither ghcide/hls nor haskell-ide-engine uses it)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I'm happy enough to change this to the libdir, and then the users of this API can just run the cradle themselves to extract it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Come to think of it, if we make the user pass in the libdir then there's no point really in having withGhcT
, since all it did was handle the libdir part
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd also advocate for just removing withGHC as well, since it's not used by ghcide/hls and is a carryover from ghc-mod
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I agree, let's remove it.
, getGhcPath = | ||
-- We're being lazy here and just returning the ghc path for the | ||
-- first non-none cradle. This shouldn't matter in practice: all | ||
-- sub cradles should be using the same ghc version! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure about that, the multi combinations could give us as first ghc a wrong one. F.e. if you use a direct cradle it can give us the ghc on path but stack or cabal the ghc configured for the project.
However it is probable that the direct cradle could work with the build tool one but not the other way around.
Would be not feasible return a list of unique ghc's and let the client code pick the first one or handle the list in other way? i can imagine you could choose the newer ghc, f.e.
src/HIE/Bios/Cradle.hs
Outdated
@@ -326,6 +340,7 @@ biosCradle wdir biosCall biosDepsCall = | |||
, cradleOptsProg = CradleAction | |||
{ actionName = Types.Bios | |||
, runCradle = biosAction wdir biosCall biosDepsCall | |||
, getGhcPath = findExecutable "ghc" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Afaik the dependencies of the bios cradle is a responsability of the bios program (see biosDeps): should not be the ghc used by that bios program returned by itself? Or at least being able to take in account it and fallback to the ghc on path.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a way for a bios program to return the path to the GHC it intends to use? From my understanding it just returns newline separated arguments in stdout
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may still want define the libdir, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if there will be a good way to have the bios program pass the library directory back, seeing as programs are only really aware of filepaths being passed to them, either through the shell arguments or by the HIE_BIOS_ARG
environment variable. Also I can't really imagine how the bios programs are going to return the library directory in the first place.
With that said, the current way haskell-language-server works out the project version is by calling ghc
on the path anyway, and this should fall back to the hardcoded ghc-paths should that fail. So I don't think there would be much of a difference.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, an option could be add another optional config option like the existing one for dependencies:
cradle:
bios:
program: ./flags.sh
dependency-program: ./dependency.sh
ghc-path-program: ./ghc-path.sh
But i am not aware of a bios program that needs it so i would merge this without it and add it on concrete user request afterwards
6df34cb
to
12f4f2f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've tested in windows with some cabal and stack projects and it has worked in all cases.
Really a great job.
EDIT: Well, that was difficult but the result for ghc and its bios cradle is strange:
GHC library directory: Just "D:\\bin\\stack\\x86_64-windows\\ghc-8.6.5\\lib"
(ghc on path is 8.8.3 and hie-bios was installed with 8.10.1)
EDIT2: I've jut run it again in ghc and i've ot another result so surely i did something wrong
PS D:\dev\ws\haskell\ghc> hie-bios debug .\ghc\Main.hs
Root directory: D:\dev\ws\haskell\ghc
Component directory: D:\dev\ws\haskell\ghc
GHC options: "-v "
GHC library directory: Nothing
Config Location: D:\dev\ws\haskell\ghc\hie.yaml
Cradle: Cradle {cradleRootDir = "D:\\dev\\ws\\haskell\\ghc", cradleOptsProg = CradleAction: Bios}
Dependencies:
For posterity, the issue with hie-bios failing on the ghc source tree itself was due to the sanity check that the ghc versions matched when fetching the library directory for GHC on the path. We just removed this in the end, since we now have a separate function for checking the project version. And upon further reflection, I think hie-bios shouldn't try to act smart here – the runtime ghc version for a bios or plain/default cradle should always just consult |
Yeah, moreover now it is named |
29d2d3a
to
126bfd8
Compare
This is part of the work towards getting static binaries properly working in ghcide and haskell-language-server. To do this we need to be able to fetch the ghc library directory on the fly, as it will change with each ghc installation. getRuntimeGhcLibDir is what client code should use to obtain the libdir, and searches three places, falling back in this order: 1. the NIX_GHC_LIBDIR environment variable 2. ghc --print-libdir for whatever ghc the cradle is using 3. the libdir baked into ghc-paths We want to avoid using ghc-paths if possible since it bakes the path into the binary, which means it isn't portable in the static binary sense. So if True is passed for the second argument, it will avoid falling back on ghc-paths, which can be useful when distributing static binaries etc. From the library directory we can also get the path to the ghc binary used, which we can then use to get the cradle ghc version via getRuntimeGhcVersion
45577a8
to
482d8af
Compare
Was trying to figure out why appveyor was failing with stack and ghc 8.10.1 so I set up GitHub CI to see if would make a difference but it didn't. I think there's something funny going on with that combination anyway so I've just commented out those tests again. I've left in the GitHub CI anyway, should be handy |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good!
Needs a follow-up PR so that bios cradle can also specify its libdir somehow.
Now we can just call `cabal exec ghc -- --numeric-version` directly without the need for guessing where the ghc binary lies.
Since the functions are now "getRuntimeGhc*", it doesn't make sense to try and use anything compiletime related
This avoids clashes with runGhc exported from GHC
This PR moves the logic in ghcide/hls of getting the runtime ghc library directory and version into hie-bios, and in doing so moves the responsibility to the cradle