Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Static cross-compilation: requires dynamic R_X86_64_32 reloc against '__TMC_END__' which may overflow at runtime; recompile with -fPIC #914

Closed
nomeata opened this issue Nov 8, 2020 · 22 comments
Labels
bug Something isn't working wontfix

Comments

@nomeata
Copy link
Contributor

nomeata commented Nov 8, 2020

For my ttttool project I have been building Static linux, windows and OSX binaries successfully with the haskell.nix toolchain in the past, with a pinned version from maybe two years ago (GHC 8.6, lot’s of manualy hackery).

I have gotten the windows build to work, but the static linux build is failing.

My current file (also available in entropia/tip-toi-reveng@71c2025) looks like this:

let
  # Fetch the latest haskell.nix and import its default.nix
  haskellNix = import (builtins.fetchTarball "https://github.com/input-output-hk/haskell.nix/archive/c00cc0cfedf03ee3f21de420882189adbb0801d8.tar.gz") {};

# windows crossbuilding needs at least 20.09.
# A peek at https://github.com/input-output-hk/haskell.nix/blob/master/ci.nix can help
  nixpkgsSrc = haskellNix.sources.nixpkgs-2009;
  nixpkgsArgs = haskellNix.nixpkgsArgs;
  pkgs = import nixpkgsSrc nixpkgsArgs;

  sourceByRegex = import ./source-by-regex.nix pkgs;

  src = sourceByRegex ../. [
    "cabal.project"
    "src/"
    "src/.*/"
    "src/.*.hs"
    ".*.cabal"
    "LICENSE"
    ];

  # Remove the with-comiler flag from cabal.project
  # We do that to help users that want to build with plain cabal
  # but it confuses `cabal new-configure` when run by nix
  patchedSrc = pkgs.runCommandNoCC "tttool-src" {} ''
    cp -r ${src} $out
    chmod -R u+w $out
    sed -i -e 's/with-compiler/-- with-compiler/' $out/cabal.project
  '';

  tttool = pkgs:
    (pkgs.haskell-nix.cabalProject {
      src = patchedSrc;
      compiler-nix-name = "ghc8102";
      index-state = "2020-11-08T00:00:00Z";
      modules =
      if pkgs.hostPlatform.isMusl
      then
        [{
          # terminfo is disabled on musl by haskell.nix, but still the flag
          # is set in the package plan, so override this
          packages.haskeline.flags.terminfo = false;
          packages.tttool.configureFlags = [
             "--disable-executable-dynamic"
             "--disable-shared"
             "--ghc-option=-optl=-pthread"
             "--ghc-option=-optl=-static"
             "--ghc-option=-optl=-L${pkgs.gmp6.override { withStatic = true; }}/lib"
             #"--ghc-option=-optl=-L${pkgs.zlib.static}/lib"
           ];
        }]
      else [];
    }).tttool.components.exes.tttool;
in
{ linux = tttool pkgs;
  static = tttool pkgs.pkgsCross.musl64;
  windows = tttool pkgs.pkgsCross.mingwW64;
}

The first hurdle was that haskeline would not build because it was configured with +terminfo, but terminfo is not available in musl.

Then I get to my program, but it fails with when linking with

/nix/store/9nh6bp6w99kyjsa1gi6ynd3vxp1x66xl-x86_64-unknown-linux-musl-binutils-2.31.1/bin/x86_64-unknown-linux-musl-ld.gold: error: /nix/store/4nf993577wbljvl8hbg79b9lj5qdxals-x86_64-unknown-linux-musl-stage-final-gcc-debug-9.3.0/lib/gcc/x86_64-unknown-linux-musl/9.3.0/crtbeginT.o: requires dynamic R_X86_64_32 reloc against '__TMC_END__' which may overflow at runtime; recompile with -fPIC
/nix/store/9nh6bp6w99kyjsa1gi6ynd3vxp1x66xl-x86_64-unknown-linux-musl-binutils-2.31.1/bin/x86_64-unknown-linux-musl-ld.gold: error: /nix/store/4nf993577wbljvl8hbg79b9lj5qdxals-x86_64-unknown-linux-musl-stage-final-gcc-debug-9.3.0/lib/gcc/x86_64-unknown-linux-musl/9.3.0/crtend.o: requires dynamic R_X86_64_32 reloc which may overflow at runtime; recompile with -fPIC
collect2: error: ld returned 1 exit status

<no location info>: error:
    `x86_64-unknown-linux-musl-cc' failed in phase `Linker'. (Exit code: 1)
builder for '/nix/store/glkb3dgcrzpfxjlqiqh40wvwly1vaia4-tttool-exe-tttool-1.9-x86_64-unknown-linux-musl.drv' failed with exit code 1

This is with and without the additional configureFlags, which were roughly what I had two years ago (where that worked), but which are also documented at https://input-output-hk.github.io/haskell.nix/tutorials/cross-compilation/#static-executables-with-musl-libc.

What should I try next?

@nomeata
Copy link
Contributor Author

nomeata commented Nov 8, 2020

JFTR: same with ghc-8.8.4/nixpkgs-20.09 and ghc-8.8.4/nixpkgs-20.03.

@nomeata
Copy link
Contributor Author

nomeata commented Nov 8, 2020

It must be related to some of the dependencies of this package, simpler packages work (as shown by this one-liner in the haskell.nix repo):

nix-build -E 'let haskellNix = (import ./. {}); pkgs = import haskellNix.sources.nixpkgs-2009 haskellNix.nixpkgsArgs; in (pkgs.pkgsCross.musl64.haskell-nix.hackage-package { name = "hello"; compiler-nix-name = "ghc8102"; version = "1.0.0.2"; modules = [ { packages.hello.configureFlags = [ "--ghc-option=-static" ]; } ]; }).components.exes.hello'

@nomeata
Copy link
Contributor Author

nomeata commented Nov 8, 2020

I could narrow it down to a use of code based on https://gist.github.com/chpatrick/863a02927dc79b0b316d, which uses TH to create a “static vector” (which kinda makes sense, given that crtstartT.o is somehow related to static constructors).

If I just write V.fromList [ … ] it works.

Maybe too much of a special case to bother you with?

@nomeata nomeata closed this as completed Nov 8, 2020
@michaelpj
Copy link
Collaborator

Well, it would be nice to understand what's going on, so we could document it. Maybe that bit of code would never work with static cross-compilation at all, or maybe it's some haskell.nix thing. Hard to say.

@nomeata
Copy link
Contributor Author

nomeata commented Nov 9, 2020

I’ll try to get a minmal example going then.

@nomeata nomeata reopened this Nov 9, 2020
@TheKK
Copy link

TheKK commented Nov 10, 2020

I got the same issue with code below:

import Options.Applicative.Simple
import qualified Paths_myLibName

main :: IO ()
main = do
  (options, runSubCommand) <-
    simpleOptions
      $(simpleVersion Paths_myLibName.version)
      "Header for command line arguments"
      "Program description, also for command line arguments"
      ( Options
          <$> switch
            ( long "verbose"
                <> short 'v'
                <> help "Verbose output?"
            )
      )
      pure ()
    -- Ignore others

Replacing the $(simpleVersion Paths_myLibName.version) part with string literal makes it works as well. So it should not be vector specific issue.

@nomeata
Copy link
Contributor Author

nomeata commented Nov 10, 2020

Thanks! It really points to the use of static strings (LitE (StringPrimL "foo")) in TH output…

@angerman
Copy link
Collaborator

I wonder if this is due to GHC not defaulting to -fPIC. I believe we end up compiling a Template Haskell splice to native code (without -fPIC) and then end up being forced to load/link symbols in the runtime linker, but simply fail to do so.
There is a somewhat similar issue on aarch64. We can somewhat work around by forcing to load objects in the lower 2GB of memory, however that won't work on all aarch64 platforms, hence we'll be setting always PIC on aarch64 as well (as we do on x86_64/darwin already). Maybe it's just time to pull the plug and make GHC default to PIC always?

@angerman
Copy link
Collaborator

Ref.: ghc/ghc@2cb8790

@nomeata
Copy link
Contributor Author

nomeata commented Nov 10, 2020

Hmm, simple attempts at reproducing this have failed. This is what I tried (and where I stopped); ready to check out and run nix-build if someone wants to try things: https://gist.github.com/nomeata/30450fc3fafa8265a513834b9a72e5e7

@TheKK
Copy link

TheKK commented Nov 10, 2020

Here's my minimal code to reproduce issue: https://gist.github.com/TheKK/16bc3829fa263e2719f7b3a93845b80d
Not even static build!

@nomeata
Copy link
Contributor Author

nomeata commented Nov 10, 2020

Thanks! I minimized it a bit further, removing the package dependency. See https://gist.github.com/nomeata/30450fc3fafa8265a513834b9a72e5e7 at revision d0a35d1f012b3da9a7f4c86e91824fe0285d3e59.

Note

-- main = print $( [|$(TH.lift "foo")|] )
main = print $(Foo.simpleVersion "foo")

Inlining Foo.simpleVersion in main makes the problem go away. Maybe that helps.

@TheKK
Copy link

TheKK commented Nov 11, 2020

Thanks! I minimized it a bit further, removing the package dependency. See https://gist.github.com/nomeata/30450fc3fafa8265a513834b9a72e5e7 at revision d0a35d1f012b3da9a7f4c86e91824fe0285d3e59.

Some new observations. Base on your gist, creating shell.nix using shellFor and running cabal build does not encounter the linking issue.

let
  haskellNix = import (builtins.fetchTarball "https://github.com/input-output-hk/haskell.nix/archive/master.tar.gz") {};
  pkgs = haskellNix.pkgs;
  hsPkgs = pkgs.pkgsCross.musl64.haskell-nix.cabalProject({
    src = ./.;
    compiler-nix-name = "ghc8102";
  });
in
  hsPkgs.shellFor {
    packages = ps: with ps; [
        issue914
    ];
    withHoogle = false;
    tools = { cabal = "3.2.0.0"; };
    buildInputs = [ ];
    exactDeps = true;
  }

# run with `nix-shell --run "cabal build"`

I also found that there's some configuration stage while running nix-build. But I'm not familiar with the default (?) Haskell builder used by Nix. I guess the term configure means runhaskell Setup.hs configure ? Anyway, I can't reproduce the linking error inside shellFor currently.

Is there any trick I could use to debug?

Configure flags:
--prefix=/nix/store/20m9pwl3w0lnynf9b95vh8i5civ41ywk-issue914-exe-issue914-0.1.0.0-x86_64-unknown-linux-musl exe:issue914 --package-db=clear --package-db=/nix/store/w2n0vxbyimrm2chn6fmzihb2dnvqa3pg-x86_64-unknown-linux-musl-issue914-exe-issue914-0.1.0.0-config/lib/x86_64-unknown-linux-musl-ghc-8.10.2/package.conf.d --exact-configuration --dependency=rts=rts --dependency=ghc-heap=ghc-heap-8.10.2 --dependency=ghc-prim=ghc-prim-0.6.1 --dependency=integer-gmp=integer-gmp-1.0.3.0 --dependency=base=base-4.14.1.0 --dependency=deepseq=deepseq-1.4.4.0 --dependency=array=array-0.5.4.0 --dependency=ghc-boot-th=ghc-boot-th-8.10.2 --dependency=pretty=pretty-1.1.3.6 --dependency=template-haskell=template-haskell-2.16.0.0 --dependency=ghc-boot=ghc-boot-8.10.2 --dependency=ghc=ghc-8.10.2 --dependency=Cabal=Cabal-3.2.0.0 --dependency=array=array-0.5.4.0 --dependency=binary=binary-0.8.8.0 --dependency=bytestring=bytestring-0.10.10.0 --dependency=containers=containers-0.6.2.1 --dependency=directory=directory-1.3.6.0 --dependency=filepath=filepath-1.4.2.1 --dependency=ghc-boot=ghc-boot-8.10.2 --dependency=ghc-compact=ghc-compact-0.1.0.0 --dependency=ghc-prim=ghc-prim-0.6.1 --dependency=hpc=hpc-0.6.1.0 --dependency=mtl=mtl-2.2.2 --dependency=parsec=parsec-3.1.14.0 --dependency=process=process-1.6.9.0 --dependency=text=text-1.2.3.2 --dependency=time=time-1.9.3 --dependency=transformers=transformers-0.5.6.2 --dependency=unix=unix-2.7.2.2 --dependency=xhtml=xhtml-3000.2.2.1 --with-ghc=x86_64-unknown-linux-musl-ghc --with-ghc-pkg=x86_64-unknown-linux-musl-ghc-pkg --with-hsc2hs=x86_64-unknown-linux-musl-hsc2hs --with-gcc=x86_64-unknown-linux-musl-cc --with-ld=x86_64-unknown-linux-musl-ld.gold --ghc-option=-optl-fuse-ld=gold --ld-option=-fuse-ld=gold --with-ar=x86_64-unknown-linux-musl-ar --with-strip=x86_64-unknown-linux-musl-strip --disable-executable-stripping --disable-library-stripping --disable-library-profiling --disable-executable-profiling --enable-static --enable-shared --disable-coverage --enable-library-for-ghci --disable-executable-dynamic --ghc-option=-optl=-pthread --ghc-option=-optl=-static --enable-split-sections

@nomeata
Copy link
Contributor Author

nomeata commented Nov 11, 2020

According to nh2/static-haskell-nix#99 (comment), this patch has helped with an issue that at least has similar symptoms: NixOS/nixpkgs#85924 (comment)

timjb added a commit to timjb/halma that referenced this issue Dec 13, 2020
Unfortunately, the build fails with

/nix/store/cdbsfljc8m900axs37fab7gnp2y1dksn-binutils-2.31.1/bin/ld: /nix/store/x0ybqvkk6h6x8mhsy5gghplsfvammq6q-gcc-9.3.0/lib/gcc/x86_64-unknown-linux-musl/9.3.0/crtbeginT.o: relocation R_X86_64_32 against hidden symbol `__TMC_END__' can not be used when making a shared object
/nix/store/cdbsfljc8m900axs37fab7gnp2y1dksn-binutils-2.31.1/bin/ld: /nix/store/x0ybqvkk6h6x8mhsy5gghplsfvammq6q-gcc-9.3.0/lib/gcc/x86_64-unknown-linux-musl/9.3.0/crtend.o: relocation R_X86_64_32 against `.ctors' can not be used when making a shared object; recompile with -fPIC

This may be related to

- nh2/static-haskell-nix#99
- input-output-hk/haskell.nix#914
@zhenyavinogradov
Copy link
Contributor

zhenyavinogradov commented Aug 12, 2021

I tried investigating this issue using @nomeata's examples, the problem is that GHC invokes system linker to produce shared libraries for Template Haskell splices, but haskell.nix uses -optl=-static flag, which makes the linker unable to produce shared libraries:

"--ghc-option=-optl=-static"

I asked about this in GHC issue tracker, and Ben Gamari helped me and said that for producing statically linked executables you should set DYNAMIC_GHC_PROGRAMS=NO when you build GHC, to make GHC itself statically linked https://gitlab.haskell.org/ghc/ghc/-/issues/20168. For haskell.nix it can be achieved by overriding ghc.package in modules.

modules = [ ({ options, ... }: {
  ghc.package = options.ghc.package.default.override { enableShared = false; };
})];

Another workaround I found to keep dynamically linked GHC is to make a wrapper for the system linker, which would check if -shared and -static flags are used simultaneously, and delete -static flag in this case. It fixes the build for me as well, but maybe there are some problems with it I don't know about.

modules =
  let
    linker-workaround = pkgs.writeShellScript "linker-workaround" ''
      # put all flags into 'params' array
      source ${pkgs.pkgsCross.musl64.stdenv.cc}/nix-support/utils.bash
      expandResponseParams "$@"

      # check if '-shared' flag is present
      hasShared=0
      for param in "''${params[@]}"; do
        if [[ "$param" == "-shared" ]]; then
          hasShared=1
        fi
      done

      if [[ "$hasShared" -eq 0 ]]; then
        # if '-shared' is not set, don't modify the params
        newParams=( "''${params[@]}" )
      else
        # if '-shared' is present, remove '-static' flag
        newParams=()
        for param in "''${params[@]}"; do
          if [[ ("$param" != "-static") ]]; then
            newParams+=( "$param" )
          fi
        done
      fi

      # invoke the actual linker with the new params
      exec x86_64-unknown-linux-musl-cc @<(printf "%q\n" "''${newParams[@]}")
    '';
  in [{
    packages.issue914.ghcOptions = [ "-pgml=${linker-workaround}" ];
  }];

@angerman
Copy link
Collaborator

@zhenyavinogradov that is an interesting workaround!

@yvan-sraka yvan-sraka added the bug Something isn't working label Sep 20, 2022
@stale
Copy link

stale bot commented Jan 18, 2023

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the wontfix label Jan 18, 2023
@stale stale bot closed this as completed Mar 20, 2023
@ju1m
Copy link
Contributor

ju1m commented Mar 14, 2024

Alas, the proposed overriding of ghc.package in modules no longer works:

error:                                                                                                                                              
       … while calling the 'derivationStrict' builtin                                                                                               
                                                                                                                                                    
         at /builtin/derivation.nix:9:12: (source not available)                                                                                    
                                                                                                                                                    
       … while evaluating derivation 'gargantext-graph-lib-gargantext-graph-x86_64-unknown-linux-musl-0.1.0.0'                                      
         whose name attribute is located at /nix/store/apn339kmg5xllk224ghr7cw6468pgkc7-source/pkgs/stdenv/generic/make-derivation.nix:300:7        
                                                                                                                                                    
       … while evaluating attribute 'SETUP_HS' of derivation 'gargantext-graph-lib-gargantext-graph-x86_64-unknown-linux-musl-0.1.0.0'              
                                                                                                                                                    
         at /nix/store/7j7h13h8m68hw4g7x1ijlmkki02wjn39-source/builder/comp-builder.nix:288:7:                                                      
                                                                                                                                                    
          287|                                                                                                                                      
          288|       SETUP_HS = setup + /bin/Setup;                                                                                                 
             |       ^                                                                                                                              
          289|                                                                                                                                      
                                                                                                                                                    
       error: attribute 'defaultSetupFor' missing                                                                                                   
                                                                                                                                                    
       at /nix/store/7j7h13h8m68hw4g7x1ijlmkki02wjn39-source/builder/hspkg-builder.nix:39:26:                                                       
                                                                                                                                                    
           38|       # Don't try to build default setup with DWARF enabled                                                                          
           39|       let defaultSetup = ghc.defaultSetupFor package.identifier.name // {                                                            
             |                          ^                                                                                                           
           40|         dwarf = defaultSetup

@angerman
Copy link
Collaborator

@ju1m do you happen to have an easy reproducer on hand?

@angerman angerman reopened this Mar 16, 2024
@stale stale bot removed wontfix labels Mar 16, 2024
@ju1m
Copy link
Contributor

ju1m commented Mar 26, 2024

@angerman, using this flake.nix:

{
  inputs = {
    haskell-nix.url = "github:input-output-hk/haskell.nix/11337f2fb85cd606630929f8fce485160d343cdc";
    nixpkgs.follows = "haskell-nix/nixpkgs-unstable";
    flake-utils.url = "github:numtide/flake-utils";
    hello = { url = "github:rudymatela/hello-haskell"; flake = false; };
  };
  outputs = { self, ... }@inputs:
    let
      supportedSystems = with inputs.flake-utils.lib.system; [
        x86_64-linux
      ];
    in
    inputs.flake-utils.lib.eachSystem supportedSystems (system:
      let
        pkgs = import inputs.nixpkgs {
          inherit system;
          config = inputs.haskell-nix.config;
          overlays = [ inputs.haskell-nix.overlay ];
        };
        inherit (inputs.nixpkgs) lib;
        inherit (pkgs.haskell-nix) haskellLib;

        project = pkgs.haskell-nix.cabalProject' {
          name = "hello";
          src = inputs.hello;

          compiler-nix-name = "ghc948";
          #index-state = haskellLib.parseIndexState (lib.readFile ./cabal.project);

          flake.variants = {
            static = {
              modules = [
                ({ config, options, ... }: {
                  enableStatic = true;
                  #enableShared = false;

                  ghc.package = options.ghc.package.default.override { enableShared = false; };
                })
              ];
            };
          };

          flake.crossPlatforms = platforms:
            pkgs.lib.optionals pkgs.stdenv.hostPlatform.isx86_64 (
              pkgs.lib.optionals pkgs.stdenv.hostPlatform.isLinux [
                platforms.musl64
              ]
            );
        };
      in project.flake'
    );

  nixConfig = {
    extra-substituters = [ "https://cache.iog.io" ];
    extra-trusted-public-keys = [ "hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ=" ];
    allow-import-from-derivation = "true";
  };
}

Yields:

$ nix -L build .#static-x86_64-unknown-linux-musl:hello:test:test
error:
       … while calling the 'derivationStrict' builtin

         at /builtin/derivation.nix:9:12: (source not available)

       … while evaluating derivation 'hello-test-test-x86_64-unknown-linux-musl-0.0.0'
         whose name attribute is located at /nix/store/apn339kmg5xllk224ghr7cw6468pgkc7-source/pkgs/stdenv/generic/make-derivation.nix:300:7

       … while evaluating attribute 'SETUP_HS' of derivation 'hello-test-test-x86_64-unknown-linux-musl-0.0.0'

         at /nix/store/p8ih2yls5axj43fyn5a1zi42d77blmbl-source/builder/comp-builder.nix:288:7:

          287|
          288|       SETUP_HS = setup + /bin/Setup;
             |       ^
          289|

       error: attribute 'defaultSetupFor' missing

       at /nix/store/p8ih2yls5axj43fyn5a1zi42d77blmbl-source/builder/hspkg-builder.nix:39:26:

           38|       # Don't try to build default setup with DWARF enabled
           39|       let defaultSetup = ghc.defaultSetupFor package.identifier.name // {
             |                          ^
           40|         dwarf = defaultSetup;

At some point I tried to copy what's done in overlays/compiler-llvm.nix, copying the list of overlays in my flake.nix to add a new overlay just after overlays/compiler-llvm.nix to avoid the same kind of errors (error: attribute 'defaultSetupFor' missing), but I gave up when it looked for the materialization of that compiler because I didn't want to patch haskell.nix.
I've not tried to use compilerSelection.

In the meantime I found that using -fexternal-interpreter (eg. packages.accelerate-llvm.ghcOptions = [ "-fexternal-interpreter" ];) is much slower but overcomes GHC's RTS segfaulting on internal_dlopen() when Musl and TemplateHaskell are used, alas it's no magic flag, ghc-iserv keeps failing when using foreign static libs:

$ nix -L build 'git+https://gitlab.iscpif.fr/julm/gargantext-graph/?ref=static#static-x86_64-unknown-linux-musl:gargantext-graph:test:gargantext-graph-test'
[…]
ghc-iserv: /nix/store/a5s111d9jh9jljffszc0gfncjibp2nr4-igraph-0.10.7/lib/libigraph.a: unsupported internal ELF TLSGD relocation for symbol `igraph_i_finally_stack_size'
ghc-iserv: /nix/store/fsgb6a84a9k62mpfc7ccacgdzcqpp8ql-haskell-igraph-lib-haskell-igraph-x86_64-unknown-linux-musl-0.10.4/lib/x86_64-linux-ghc-9.4.8/haskell-igraph-0.10.4-EBe5Nu77ckCJAIVDVPknAF/HShaskell-igraph-0.10.4-EBe5Nu77ckCJAIVDVPknAF.o: unknown symbol `igraph_error'                      
ghc-iserv: Could not load Object Code /nix/store/fsgb6a84a9k62mpfc7ccacgdzcqpp8ql-haskell-igraph-lib-haskell-igraph-x86_64-unknown-linux-musl-0.10.4/lib/x86_64-linux-ghc-9.4.8/haskell-igraph-0.10.4-EBe5Nu77ckCJAIVDVPknAF/HShaskell-igraph-0.10.4-EBe5Nu77ckCJAIVDVPknAF.o.
[…]
<no location info>: error:
    unable to load unit `haskell-igraph-0.10.4'

Just to clarify, I never encountered the requires dynamic R_X86_64_32 reloc against '__TMC_END_' error mentionned in the intro of this issue, out of despair I just wanted to try a GHC built with DYNAMIC_GHC_PROGRAMS=NO (ie. enableShared = false) to see if it can overcome those unsupported internal ELF TLSGD relocation, unknown symbol and unable to load unit errors. Though the problem may well be in pkgsCross.musl64 or my flake.nix and not the GHC side.

@ju1m
Copy link
Contributor

ju1m commented Mar 26, 2024

Turns out pkgs.igraph was not the only package needing attention to support a static build:

  1. Nixpkgs provides pkgs.lapack and pkgs.blas which are packages to select between alternative LAPACK and BLAS implementations, which both default to pkgs.openblas.
  2. hmatrix has an openblas flag defaulting to false, in which case it uses pkgs.lapack and pkgs.blas otherwise it uses pkgs.openblas.
  3. lib/system-nixpkgs-map.nix surprisingly maps lapack to liblapack, which is not the alternative selector package that pkgs.lapack is, but an alias to pkgs.lapack-reference.
  4. Both pkgsCross.musl64.lapack-reference and pkgsCross.musl64.blas-reference are not built with -DBUILD_SHARED_LIBS=OFF to enable static builds.
  5. When linking an executable depending on hmatrix, it fails to find -llapack and -lblas static libraries.

With the current haskell.nix, I can see two workarounds:

  1. To force hmatrix to use openblas (packages.hmatrix.flags.openblas = true) because it supports static build when stdenv.hostPlatform.isStatic is true. Alas pkgsCross.musl64.stdenv.hostPlatform.isStatic is false, so it has to be forced:
(finalPkgs: previousPkgs: {
  pkgsCross = previousPkgs.pkgsCross // {
    musl64 = previousPkgs.pkgsCross.musl64.extend (finalMusl64: previousMusl64: {
      openblas = previousMusl64.openblas.override {
        enableStatic = true;
        /*enableShared = false; May not be supported by lapack/blas alternative packages. In any case, enabling it make ghc-iserv segfault, likely because it fails to find the shared libraries. */
        singleThreaded=true;
      };
    });
  };
})

Note: I think singleThreaded=true has to be forced to let GHC handle the threads.
2. Or to force liblapack to be a static build:

(finalPkgs: previousPkgs: {
  pkgsCross = previousPkgs.pkgsCross // {
    musl64 = previousPkgs.pkgsCross.musl64.extend (finalMusl64: previousMusl64: {
      liblapack = previousMusl64.liblapack.override { shared = false; };
    });
  };
})

Copy link

stale bot commented Jul 25, 2024

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the wontfix label Jul 25, 2024
@stale stale bot closed this as completed Sep 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working wontfix
Projects
None yet
Development

No branches or pull requests

7 participants