st: libxft with bgra patch in Ubuntu

2021-07-26

Why to patch libxft?

st, the simple terminal by suckless.org, has a lot of advantages:

But its biggest problem is that it crashes when you type a color emoji (or it occurs in an e-mail or text file, p.e.). This is not a bug in st but in libxft (which is a dependency of st). Obviously, a crashing terminal emulator is not an option. So you can either choose a font that has no color emojis, or you apply the "bgra patch" (by Maxime Coste) to libxft.

When you use Arch Linux, you are lucky: You can simply install libxft-bgra (AUR). But for others (for example Ubuntu users) it's a little bit more difficult. Here is how to make st work with color emojis in Ubuntu:

Apply the bgra patch to libxft

First, get the libxft source code and fetch the branch with the bgra patch:

cd ~
git clone https://gitlab.freedesktop.org/xorg/lib/libxft.git
cd libxft
git fetch https://gitlab.freedesktop.org/mawww/libxft.git bgra-glyphs
git checkout -b mawww/libxft-bgra-glyphs FETCH_HEAD

Then install the packages needed for building and build the patched libxft:

sudo apt install build-essential libtool pkg-config libxrender-dev libfreetype6-dev libfontconfig1-dev xutils-dev
sh autogen.sh --sysconfdir=/etc --prefix=/usr --mandir=/usr/share/man
make

Now, you could install the patched version with sudo make install. But st wouldn't use the newly installed version anyway (because it doesn't find it). This can be fixed but I prefer making st using the patched version and keep the default libxft for other programs as it is.

Build st with the patched libxft linked

If you haven't already cloned the st repository, do it now:

cd ~
git clone git://git.suckless.org/st
cd st

Now tell it where to find the patched libxft version:

diff --git a/config.mk b/config.mk
index c070a4a..4920ec9 100644
--- a/config.mk
+++ b/config.mk
@@ -7,8 +7,8 @@ VERSION = 0.8.4
 PREFIX = /usr/local
 MANPREFIX = $(PREFIX)/share/man

-X11INC = /usr/X11R6/include
-X11LIB = /usr/X11R6/lib
+X11INC = /home/max/libxft/include
+X11LIB = /home/max/libxft/src/.libs

 PKG_CONFIG = pkg-config

@@ -23,7 +23,7 @@ LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft \
 # flags
 STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
 STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS)
-STLDFLAGS = $(LIBS) $(LDFLAGS)
+STLDFLAGS = -Xlinker -rpath=$(X11LIB) $(LIBS) $(LDFLAGS)

 # OpenBSD:
 #CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 -D_BSD_SOURCE

Of course, you'll have to replace /home/max/libxft with the actual path to your patched libxft.

Then do make. You can check if st uses the patched version of libxft:

▶ ldd ./st
        linux-vdso.so.1 (0x00007fffc413f000)
        libX11.so.6 => /lib/x86_64-linux-gnu/libX11.so.6 (0x00007f98204b1000)
        libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007f98204ac000)
        libXft.so.2 => /home/max/repos/libxft/src/.libs/libXft.so.2 (0x00007f9820492000)
        ...

Now run sudo make install and you can start your patched st with your usual key binding or by executing st whereever you start programs.