Arch Linux recently changed their Haskell packages (no more static linking), which broke a bunch of stuff. Specifically, upgrading xmonad-0.13-8
→ xmonad-0.13-9
produces errors when recompiling xmonad, and only downgrading seems to fix the issue; and using cabal-install
(cabal install xmonad
) with Arch’s ghc
likewise produces errors, failing to install xmonad. For those of you coming from Google, the errors are of the format Could not find module ...
. See here and here, for example.
In addition, Arch’s xmobar (with xmonad-0.13-8
) has been crashing sporadically (segmentation faults), for some reason. See here, for instance.
In this post, I’ll explain how I got xmonad (and xmonad-contrib) and xmobar installed and working – and no xmobar crashes, so far – via stack. I’ll try to keep it as short and simple as possible. No in-depth explanations; just a straightforward, step-by-step rundown of what I did. The usual disclaimers (YMMV, etc.) apply.
I’ll assume you already have an ~/.xmonad
directory with an xmonad.hs
config file. If you don’t use xmobar, this post can still be useful; just ignore the lines/steps that refer to xmobar.
Step 1: Get stack
There are couple ways to get stack. I installed stack-static from the AUR, because it doesn’t come with any Haskell dependencies.
If you don’t care about tracking stack with your package manager, then, as the stack how-to-install explains, just run
curl -sSL https://get.haskellstack.org/ | sh
or
wget -qO- https://get.haskellstack.org/ | sh
Step 2: Install GHC with stack
To build and install Haskell packages, we need GHC. Simply run
stack setup
to install GHC into ~/.stack
. Useful for the kind of sandboxing projects that we’re doing with xmonad.
NB: You can run stack ghc
to do things with GHC, stack ghci
to fire up interactive GHC, and so on.
Step 3: Get xmonad, xmonad-contrib, and xmobar
We’ll be turning our ~/.xmonad
directory into a stack project, so first, head over there.
cd ~/.xmonad
For the remainder of this post, I’ll assume you’re inside ~/.xmonad
.
Next, download the xmonad, xmonad-contrib, and xmobar Git repositories, which contain the .cabal
and .yaml
files that stack will look for in the next step. I like to add -git
to their directory names, just as a reminder.
# From inside ~/.xmonad.
git clone "https://github.com/xmonad/xmonad" xmonad-git
git clone "https://github.com/xmonad/xmonad-contrib" xmonad-contrib-git
git clone "https://github.com/jaor/xmobar" xmobar-git
Your ~/.xmonad
directory should now contain xmonad-git
, xmonad-contrib-git
, and xmobar-git
, each of which contains a .cabal
file and a .yaml
file.
Step 4: Initialize stack
This step is easy: just run
# From inside ~/.xmonad.
stack init
Stack will find the .cabal
and .yaml
files and auto-create the file stack.yaml
for you. It’ll look like this:
# ~/.xmonad/stack.yaml
resolver: lts-9.6
packages:
- xmobar-git
- xmonad-git
- xmonad-contrib-git
extra-deps: []
flags: {}
extra-package-dbs: []
At this point, you can modify stack.yaml
to add flags, etc. The only change I made was to add the flag all_extensions
to xmobar, by changing
flags: {}
to
flags:
xmobar:
all_extensions: true
This flag provides all the xmobar bells & whistles, like support for xft, mpd, battery, wifi, etc.
NB: If you add the with_iwlib
flag (or all_extensions
), you’ll need to also install the iwlib C library and headers. In Arch Linux, just install wireless_tools
; in Debian-based systems, libiw-dev
. Or, in your stack.yaml
, change
extra_deps: []
to
extra_deps:
- iwlib-0.1.0
(The specific version you’ll need will change over time. If stack install
from step 5 produces an error, just see what stack recommends.)
Step 5: Build and install everything
Next, run
# From inside ~/.xmonad.
stack install
to build and install xmonad, xmonad-contrib, and xmobar (and all their dependencies). You’ll now have two new binaries, xmonad
and xmobar
, installed into ~/.local/bin
.
NB: You’ll want to add ~/.local/bin
to your PATH
, if it isn’t already. (If you use a login manager, see Step 9 below.)
Step 6: Write a build file
Since we’re doing everything via stack, rather than ghc directly, xmonad --recompile
won’t quite work yet. As of xmonad 0.13, we can write a custom build script, named build
and located inside ~/.xmonad
, which will use stack ghc to recompile xmonad. (Borrowed from pbrisbin.)
# ~/.xmonad/build
#!/bin/sh
exec stack ghc -- \
--make xmonad.hs \
-i \
-ilib \
-fforce-recomp \
-main-is main \
-v0 \
-o "$1"
Make sure it’s executable:
chmod a+x build
Step 7: Recompile and restart xmonad
You should now be able to recompile and restart xmonad (and xmobar) with
xmonad --recompile && xmonad --restart
NB: I had to restart my computer in order for xmobar to start up properly – probably because xmonad couldn’t find the xmobar binary.
Step 8: Updating
Whenever you update your xmonad, xmonad-contrib, or xmobar repositories, just cd ~/.xmonad
and run
stack install
to rebuild and reinstall everything.
NB: If you add a new flag or extra dependencies (in stack.yaml
), you may need to run stack clean
first.
(Step 9: Loose ends with login managers)
If you use a login manager, such as LightDM, then you may need to take some additional steps. I don’t use a login manager, nor do I know much about them, but I’ll use LightDM as the working example since I’ve read a little about it.
First off, LightDM uses *.desktop
files located /usr/share/xsessions
to know which desktop environments (or window managers) you have available to choose from. So, you’ll probably need to create xmonad.desktop
. The xmonad package from the official Arch repos installs the following file, so you can just copy it verbatim and place it into /usr/share/xsessions
:
[Desktop Entry]
Encoding=UTF-8
Type=Application
Name=Xmonad
Comment=Lightweight X11 tiled window manager written in Haskell
Exec=xmonad
Icon=xmonad
Terminal=false
StartupNotify=false
Categories=Application;
Second, running xmonad --recompile
may not work yet. If it doesn’t, make sure that you’ve added ~/.local/bin
to your PATH
by adding it to one of your shell profile files, such as ~/.profile
or (if you only use one shell, e.g. Bash) ~/.bash_profile
, and not to your shell’s configuration file (e.g. ~/.bashrc
). The reason is that LightDM (and by extension xmonad) is invoked from a login shell, which sources profile files like ~/.profile
, but not (necessarily) shell config files like ~/.bashrc
. See this SE thread and this Quora answer to learn more about the difference.
If that still doesn’t work, then it’s possible that your login manager doesn’t even source ~/.profile
(see the end of the SE thread linked above). In that case, a possible fix is to just manually symlink ~/.local/bin/xmonad
to /usr/bin
(since the latter is definitely in your PATH
; thanks to Ashesh in the comments below for this fix):
ln -s ~/.local/bin/xmonad /usr/bin