pkgsStatic.musl fails to build

Hi.

I am trying to build a static binary. I am using

{ project ? import ./nix { }
}:
let
  pkgs = project.pkgs.pkgsStatic;
  stdenv = pkgs.clang10Stdenv;
  mkShell = pkgs.mkShell.override { inherit stdenv; };
in
mkShell {
  nativeBuildInputs = [pkgs.musl] ++ builtins.attrValues project.devTools;

  shellHook = ''
    ${project.ci.pre-commit-check.shellHook}
  '';

}

Running nix-shell tries to build musl-static-x86_64-unknown-linux-musl-1.2.2 but it fails with:

Moving /nix/store/6kpc2425qs3yjdqrz8x7rcqjhz8722nh-musl-static-x86_64-unknown-linux-musl-1.2.2/bin/musl-gcc to /nix/store/8l99day2gwzvibfvwhvf36sv7skqvv8p-musl-static-x86_64-unknown-linux-musl-1.2.2-dev/bin/musl-gcc
rmdir: failed to remove '/nix/store/6kpc2425qs3yjdqrz8x7rcqjhz8722nh-musl-static-x86_64-unknown-linux-musl-1.2.2/bin': Directory not empty
Moving /nix/store/6kpc2425qs3yjdqrz8x7rcqjhz8722nh-musl-static-x86_64-unknown-linux-musl-1.2.2/bin/musl-clang to /nix/store/8l99day2gwzvibfvwhvf36sv7skqvv8p-musl-static-x86_64-unknown-linux-musl-1.2.2-dev/bin/musl-clang
rmdir: failed to remove '/nix/store/6kpc2425qs3yjdqrz8x7rcqjhz8722nh-musl-static-x86_64-unknown-linux-musl-1.2.2/bin': Directory not empty
Moving /nix/store/6kpc2425qs3yjdqrz8x7rcqjhz8722nh-musl-static-x86_64-unknown-linux-musl-1.2.2/bin/ld.musl-clang to /nix/store/8l99day2gwzvibfvwhvf36sv7skqvv8p-musl-static-x86_64-unknown-linux-musl-1.2.2-dev/bin/ld.musl-clang
rmdir: failed to remove '/nix/store/6kpc2425qs3yjdqrz8x7rcqjhz8722nh-musl-static-x86_64-unknown-linux-musl-1.2.2/bin': Directory not empty
Moving /nix/store/6kpc2425qs3yjdqrz8x7rcqjhz8722nh-musl-static-x86_64-unknown-linux-musl-1.2.2/lib/musl-gcc.specs to /nix/store/8l99day2gwzvibfvwhvf36sv7skqvv8p-musl-static-x86_64-unknown-linux-musl-1.2.2-dev/lib/musl-gcc.specs
rmdir: failed to remove '/nix/store/6kpc2425qs3yjdqrz8x7rcqjhz8722nh-musl-static-x86_64-unknown-linux-musl-1.2.2/lib': Directory not empty
clang-10: warning: argument unused during compilation: '-pie' [-Wunused-command-line-argument]
/nix/store/635hpnadj6rhz2wbi3yfaxpqb5556qsw-x86_64-unknown-linux-musl-binutils-2.35.1/bin/x86_64-unknown-linux-musl-ld:INSTALL: file format not recognized; treating as linker script
/nix/store/635hpnadj6rhz2wbi3yfaxpqb5556qsw-x86_64-unknown-linux-musl-binutils-2.35.1/bin/x86_64-unknown-linux-musl-ld:INSTALL:2: syntax error
clang-10: error: linker command failed with exit code 1 (use -v to see invocation)
builder for '/nix/store/k92sv6w9w5564clwzsj58cj0007kqm8a-musl-static-x86_64-unknown-linux-musl-1.2.2.drv' failed with exit code 1
error: build of '/nix/store/k92sv6w9w5564clwzsj58cj0007kqm8a-musl-static-x86_64-unknown-linux-musl-1.2.2.drv' failed

This seems to be caused by some automatic tooling running after the postInstallPhase I suppose. But why is it trying to run the linker on the INSTALL file? Any ideas?!

BTW, I also tried to build this from nixpkgs (nix-build -A pkgsStatic.musl) but this gives the same error. I tried to debug this and added

diff --git a/pkgs/os-specific/linux/musl/default.nix b/pkgs/os-specific/linux/musl/default.nix
index ae175a36324..307e237e657 100644
--- a/pkgs/os-specific/linux/musl/default.nix
+++ b/pkgs/os-specific/linux/musl/default.nix
@@ -137,6 +139,7 @@ stdenv.mkDerivation rec {
     install -D ${queue_h} $dev/include/sys/queue.h
     install -D ${cdefs_h} $dev/include/sys/cdefs.h
     install -D ${tree_h} $dev/include/sys/tree.h
+    echo 'postinstall done'
   '';
 
   passthru.linuxHeaders = linuxHeaders;

Into the postInstall script. And it builds:

...
Moving /nix/store/n2c8dzgv0ayzq9fjjxn1lc7rdaz26pac-musl-static-x86_64-unknown-linux-musl-1.2.2/lib/musl-gcc.specs to /nix/store/qqsl2z7dc984j3552nk22777vpwdh5gq-musl-static-x86_64-unknown-linux-musl-1.2.2-dev/lib/musl-gcc.specs
rmdir: failed to remove '/nix/store/n2c8dzgv0ayzq9fjjxn1lc7rdaz26pac-musl-static-x86_64-unknown-linux-musl-1.2.2/lib': Directory not empty
done
postinstall done
post-installation fixup
...

TIA

I think I have a better understanding what happens.

The postInstall has this entry:

$CC ${iconv_c} -o $out/bin/iconv \
      -I$dev/include \
      -L$out/lib -Wl,-rpath=$out/lib \
      -lc \
      -B $out/lib \
      -Wl,-dynamic-linker=$(ls $out/lib/ld-*)

This calls out to ls trying to determine the path to the dynamic linker. Alas, for pkgsStatic the dynamic linker is not build at all:

ls /nix/store/cchwl3lfkv630g4csscxq3dbbi8d0lsr-musl-static-x86_64-unknown-linux-musl-1.2.2/lib/ld-*
zsh: no matches found: /nix/store/cchwl3lfkv630g4csscxq3dbbi8d0lsr-musl-static-x86_64-unknown-linux-musl-1.2.2/lib/ld-*

The Makefile has

LDSO_PATHNAME = $(syslibdir)/ld-musl-$(ARCH)$(SUBARCH).so.1

$(DESTDIR)$(LDSO_PATHNAME): $(DESTDIR)$(libdir)/libc.so
    $(INSTALL) -D -l libc.so $@ || true

ie. it just ignores errors when installing libc.so to lib/ld-musl-$arch$subarch.so.1 fails for some reason.

But how can I fix this? Using an overlay? Or simply use pkgs.musl ?

edit: Yes, actually using pkgs.musl (non pkgsStatic.musl) which also includes the static library makes this work:

{ project ? import ./nix { }
}:
let
  pkgs = project.pkgs.pkgsStatic;
  stdenv = pkgs.clang10Stdenv;
  mkShell = pkgs.mkShell.override { inherit stdenv; };
in
mkShell {
  nativeBuildInputs = [project.pkgs.musl] ++ builtins.attrValues project.devTools;

  ...
}

Question is: How can the musl build be fixed for the static build? I guess one would need to check if it is a static build and not try to link the libc dynamically?

I suspect you should not list musl at all. pkgsStatic.stdenv comes with musl already and in my experience listing the libc a second time does nothing good.

1 Like

Oh yes, you’re right. And that’s kind of what I tried first, but I could not compile a simple C program (since I assumed inside the nix-shell clang would automatically resolve to the static-musl-clang) … this led me to think that I needed to specify a C library explicitly.

Currently, I get the path to the compiler like this:

  shellHook = ''
    export CLANG_PATH="$NIX_CC/bin/$CC"
  ''

Is there a better way?

you should not use clang to compile but $CC, which should be clang but under another name: x86_64-unknown-linux-musl-clang when I tried.

1 Like

Most likely using pkgsStatic.clangStdenv or pkgsStatic.llvmPackages_xx.stdenv.

Yeah, I figured this out by myself. But can I get the absolute path to the compiler in nix? As you can see, I use $CC and $NIX_CC to construct the path inside the shell hook, but is this even the right thing to do? Or how can I determine the path in a nix expression?

I am using pkgsStatic.clang10Stdenv as you can see from my code above. I do not understand what you wanted to tell me?

let
  ccPath = "${stdenv.cc}/bin/${stdenv.cc.targetPrefix}cc";
in
# …

Concatenating seems also fine or using type -p "$CC" if you need to do it in the shell.

Sorry, missed that.

1 Like