xmonad/xmonad-extras

Can't get eval / hint working on Arch Linux.

LeifW opened this issue · 7 comments

LeifW commented

Not sure where to ask this, but apparently I can't get hint to work from xmonad, period, and thus the eval parts of this library don't work.

I can't get get the hint-based parts XMonad.Prompt.Eval / XMonad.Actions.Eval to work.
If I run the prompt part to a key, and then input putStrLn "Hello" in its prompt, it pops up an xmessage saying `
If I run it again, I get "GhcException the impossible happened Dynamic linker not initialized"; which happens every subsequent time until I restart xmonad, then it's back to the "could not execute: gcc" the first time.

If instead of XMonad.Prompt.Eval I use the underlying XMonad.Actions.Eval, and bind evalExpression defaultEvalConfig "putStrLn \"hello\"" to a key, it exhibits the same (failing) behavior.

Here's a minimal reproduction: I bound "mod-i" to something that's supposed to write "hello" to /tmp/xmonad.out, however, it fails and writes the above GhcException "could not execute: gcc" to /tmp/xmonad.error.

import XMonad
import XMonad.Util.EZConfig (additionalKeys)

import Language.Haskell.Interpreter

a :: IO (Either InterpreterError (IO ()))
a = runInterpreter $ setImports ["Prelude"] >> interpret  "writeFile \"/tmp/xmonad.out\" \"hello\"" (pure ())

runAOrWriteError :: IO ()
runAOrWriteError = a >>= either (writeFile "/tmp/xmonad.error" . show) id

main :: IO ()
main = xmonad $ def `additionalKeys` [((modMask def, xK_i), io runAOrWriteError)] 

The call to hint works fine if main is replaced with main = runAOrWriteError. Also, the same works through XMonad.Actions.EvalExpression if I replace the X references with IO and run the above from main.
https://github.com/xmonad/xmonad-extras/blob/master/XMonad/Actions/Eval.hs

Also, the example.hs included in the hint repo works fine for me (not if I ran it from xmonad, I'll bet).

The hint source says that exception is caught and re-thrown from the underlying GHC API.
https://github.com/mvdan/hint/blob/c6fdd3c272af1df6d5293c03c59e79b8877bec21/src/Hint/Base.hs#L57

Not sure if it's relevant, but I'm running on Arch Linux, where Haskell libraries are dynamically linked. See https://wiki.archlinux.org/index.php/haskell#Problems_with_linking for more info on that.

I created a docker image based on Arch Linux just to have a "clean" reproduction of this, and the behavior is the same there. I could share the image if desired, or try it on other distros (just need to be able to e.g. apt-get install a recent version of xmonad-contrib, else install that stuff from scratch).

GHC 8.2.2, xmonad and xmonad-contrib 0.13, xmonad-extras installed from git master, hint 0.7.0.

psibi commented

Sorry for my late reply. Did you get this to work ? I would be open to a PR if you think it's a bug with the package. Personally, I don't use the Eval module - So I can't help you much.

psibi commented

I'm closing the issue as I haven't recived any response. Please free feel to re-open if the issue still exists. Thanks!

I'm having this issue as well

Arch packages ghc in a strange way that makes a lot of haskell packages break. I'd recommend getting ghcup (from the AUR or the official site and install ghc and cabal that way. It's the only way I could get xmonad-contrib or this to even compile.

However you might be able to follow these instructions to get it to work if you're using cabal-install from the arch repositories. It looks relevant to the errors you're getting: https://wiki.archlinux.org/index.php/Haskell#Problems_with_linking

Tried ghcup and that didn't fix the issue. tried stack as well and that didn't make it work either. I'm still getting "Dynamic linker not initialized"

In case it's useful for anyone who finds this thread: the way xmonad installs signal handlers breaks process library, which is used by ghc package (and therefore, hint) to invoke gcc command. To get hint working, you need to uninstall those signal handlers. My take on minimal GHCi-like prompt looks like this:

import           XMonad
import           XMonad.Prompt                 as XP
import qualified Language.Haskell.Interpreter  as I


data EvalPrompt = EvalPrompt

instance XP.XPrompt EvalPrompt where
  showXPrompt = const "haskell> "
  commandToComplete _ = id
  completionFunction _ s = io $ do
    res <- I.runInterpreter $ do
            I.setImports ["Prelude", "Data.Ratio"]
            I.eval s
    case res of
      Left err -> return [show err]
      Right s -> return [s]

myXPConfig = def :: XP.XPConfig

evalPrompt = do
  uninstallSignalHandlers
  mkXPromptWithModes [XPT EvalPrompt] myXPConfig
  installSignalHandlers

This prompt outputs expression result where completions usually are as you type. You can, of course, bind evalPrompt action to any keys you like.
I'm not sure if it's dangerous to do something like that, but it works for me, at least.

Extremely useful, thanks!