How to use lld linker with ghcup ghc on linux to build haskell projects?

I read that ld.lld linker is significantly faster than ld.bfd and want to try it with my own project.

I tried it on a demo project first, but got errors:

sylecn@agem10:~/fromsource/link-with-lld-example$ cabal build
Build profile: -w ghc-9.4.8 -O1
In order, the following will be built (use -v for more details):
 - link-with-lld-example-1 (lib:link-with-lld-example, exe:link-with-lld-example) (first run)
Preprocessing executable 'link-with-lld-example' for link-with-lld-example-1..
Building executable 'link-with-lld-example' for link-with-lld-example-1..
[2 of 2] Linking /home/sylecn/fromsource/link-with-lld-example/dist-newstyle/build/x86_64-linux/ghc-9.4.8/link-with-lld-example-1/build/link-with-lld-example/link-with-lld-example
ld.lld: error: relocation R_X86_64_32S cannot be used against local symbol; recompile with -fPIC
>>> defined in /home/sylecn/.ghcup/ghc/9.4.8/lib/ghc-9.4.8/lib/../lib/x86_64-linux-ghc-9.4.8/base-4.17.2.1/libHSbase-4.17.2.1.a(Base.o)
>>> referenced by Base.o:(base_ControlziExceptionziBase_zdfShowNonTerminationzuzdcshowsPrec_info) in archive /home/sylecn/.ghcup/ghc/9.4.8/lib/ghc-9.4.8/lib/../lib/x86_64-linux-ghc-9.4.8/base-4.17.2.1/libHSbase-4.17.2.1.a

ld.lld: error: relocation R_X86_64_32S cannot be used against local symbol; recompile with -fPIC
>>> defined in /home/sylecn/.ghcup/ghc/9.4.8/lib/ghc-9.4.8/lib/../lib/x86_64-linux-ghc-9.4.8/base-4.17.2.1/libHSbase-4.17.2.1.a(Base.o)
>>> referenced by Base.o:(base_ControlziExceptionziBase_zdfShowNonTermination1_info) in archive /home/sylecn/.ghcup/ghc/9.4.8/lib/ghc-9.4.8/lib/../lib/x86_64-linux-ghc-9.4.8/base-4.17.2.1/libHSbase-4.17.2.1.a

Here is the versions used during the test:

sylecn@agem10:~$ ghcup list -c installed
   Tool  Version  Tags                      Notes      
✓  ghc   8.10.7   base-4.14.3.0                        
✔✔ ghc   9.4.8    recommended,base-4.17.2.1 hls-powered
✔✔ cabal 3.10.3.0 latest,recommended                   
✔✔ hls   2.7.0.0  recommended                          
✔✔ stack 2.15.5   recommended                          
✔✔ ghcup 0.1.22.0 latest,recommended

It seems base package is not compatible with lld linker? What is the correct way to link with lld linker? Is the ghc installed by ghcup compatible with lld?

1 Like

Have you tried installing your bindist with $LD and $CC set to your preferences? User Guide - GHCup

I have tried to uninstall and reinstall ghc using “ghcup tui” command, after installing lld, with

def-ghc-conf-options:
  - "--enable-ld-override"

in ~/.ghcup/config.yaml

I believe this has the same effect as setting $LD. But I don’t know how to check whether it made a difference. Is there a command I can run or a log file I can check?
The build error persist after reinstall ghc this way.

Does setting $CC make a difference? should I set $LD and $CC and reinstall ghc?

def-ghc-conf-options

I think that feature isn’t released yet. The docs are unfortunately a little bit of “bleeding edge”.

Try: LD=ld.lld ghcup install ghc 9.4.8

Check out ~/.ghcup/ghc/9.8.2/lib/ghc-9.4.8/lib/settings. The key "C compiler command" will tell you if it’s gcc or clang.

In my case,
LD=ld.lld ghcup install ghc --force 9.4.8

That worked. Thanks.

Unfortunately, there’s another GHC issue that prevents this from working properly: #21830: Wrong defaulting linker when LD env.var. is set · Issues · Glasgow Haskell Compiler / GHC · GitLab

So you’ll have to edit the GHC settings file manually to add -fuse-ld=lld to “C compiler link flags”. Otherwise it will likely not actually use lld.

OK. I was wrong. When I build the demo project, I forget to revert a local change I made that drop the lld settings. When I revert the change, build still fail.

On a second look on the ghc installer tarball (used by ghcup), it seems file ghc-9.4.8-x86_64-unknown-linux/lib/x86_64-linux-ghc-9.4.8/libHSbase-4.17.2.1-ghc9.4.8.so, ghc-9.4.8-x86_64-unknown-linux/lib/x86_64-linux-ghc-9.4.8/base-4.17.2.1/libHSbase-4.17.2.1.a
is included in the tarball. Would setting $LD and -fuse-ld=lld in settings file supposed to work at all? Since the original error is about that file not compiled with -fPIC.

Append something like this to your ghcup install command:

-- \
  CC=/usr/lib/llvm-18/bin/clang \
  CONF_CC_OPTS_STAGE2="-Wno-unused-command-line-argument" \
  CONF_CXX_OPTS_STAGE2="-Wno-unused-command-line-argument" \
  CONF_GCC_LINKER_OPTS_STAGE2="--ld-path=/usr/lib/llvm-18/bin/ld.lld" \
  CXX=/usr/lib/llvm-18/bin/clang++ \
  LD="/usr/lib/llvm-18/bin/ld.lld"

kruzifix!

This is why I’m starting to think ghcup should just provide an interface to change the GHC settings file.

But given that there’s other things in the works (ghc-toolchain), I’m not sure how future proof that would be.

1 Like

tbh I’m not a big fan of editing settings directly. Sure, you need to jump through more hops to provide the right configure options, but configure does it job and checks for consistency; you are more likely to end up with a subtly broken bindist if you edit settings directly.

Well, it actually doesn’t:

And even if those things get fixed, they won’t get backported (except by me).

A ghcup interface could check for consistency on its own and would work correctly across GHC versions, regardless of bindist bugs.

Side note: Since trying lld on linux is unsuccessful, I tried to build my own project on freebsd 14, which uses clang and lld by default. The build speed was not faster than on Linux despite using lld as linker. The VM used to run the build has similar hardware spec and runs on the same host.

In fact build with a clean cache took 22m29s in Linux VM, took 22m22s in FreeBSD VM.
The project that I built can be download from

if someone want to compare build speed between ld and lld linker.

build requires stack.
just build with
stack build

1 Like