Can't build statically linked executable when Template Haskell is used
Summary
I want to build a statically linked executable using musl libc. As I know, the suggested way of doing it is to invoke ghc
with -optl=-pthread -optl=-static
flags, which make it pass -pthread -static
flags to the linker. But it fails when my code contains a TH splice, with the following error message:
$ x86_64-unknown-linux-musl-ghc -optl=-static -optl=-pthread Main.hs
<...>
x86_64-unknown-linux-musl-ld: crtbeginT.o: relocation R_X86_64_32 against hidden symbol `__TMC_END__' can not be used when making a shared object
x86_64-unknown-linux-musl-ld: crtend.o: relocation R_X86_64_32 against `.ctors' can not be used when making a shared object; recompile with -fPIC
collect2: error: ld returned 1 exit status
Invoking ghc with -v
flag shows the linker invocation it fails on:
x86_64-unknown-linux-musl-cc <...> -o /run/user/1000/ghc380334_0/libghc_6.so ./Foo.dyn_o -shared <...> -lgmp -lc -lm -static -pthread
What makes the linker fail are -shared
and -static
flags used at the same time. I found out that the linker is invoked not only for linking the final executable, but also for producing .so
libraries when TH code is processed. And -static
flag is passed in both cases, while we only want to pass it in the first one. Is there a way to achieve that?
Steps to reproduce
(Tarball with these files: ghc-static-issue.tar.gz, the example is originally due to Joachim Breitner: https://github.com/input-output-hk/haskell.nix/issues/914#issuecomment-724625620.)
Main.hs
:
{-# LANGUAGE TemplateHaskell #-}
module Main where
import Foo
main :: IO ()
main = print $(Foo.simpleVersion "foo")
Foo.hs
:
{-# LANGUAGE TemplateHaskell #-}
module Foo where
import Language.Haskell.TH (Q,Exp)
import qualified Language.Haskell.TH.Syntax as TH
simpleVersion :: String -> Q Exp
simpleVersion version = [|$(TH.lift version)|]
shell.nix
with GHC linked against musl:
let
nixpkgs-src = builtins.fetchTarball "https://github.com/NixOS/nixpkgs/archive/2030abed5863fc11eccac0735f27a0828376c84e.tar.gz";
pkgs = (import nixpkgs-src {}).pkgsCross.musl64;
in pkgs.stdenv.mkDerivation {
name = "env";
# ghc 8.10.4 executable, dynamically linked with musl:
nativeBuildInputs = [ pkgs.ghc ];
# provide both .a and .so libraries for gmp and libffi:
buildInputs = [
(pkgs.gmp.override { withStatic = true; })
(pkgs.libffi.overrideAttrs (_old: { dontDisableStatic = true; }))
];
}
To reproduce run:
$ nix-shell --pure shell.nix
$ x86_64-unknown-linux-musl-ghc -optl=-static -optl=-pthread -v Main.hs
Expected behavior
A statically linked executable compiled.
Environment
- GHC version used: 8.10.4, dynamically linked against musl
- Operating System: Linux
- System Architecture: x86_64