Cargo project fails to link if musl exists as a nix depenency

I have a rust project targeting x86_64-unknown-linux-gnu. However, at runtime I have a dependency on musl. When I add pkgs.musl to buildInputs Cargo stops being able to link the rust project. It’s still targetting gnu, the only change is that musl-gcc and so on are also on path now. cc is still the same program as before.

The actual error:

error: could not compile `libc` due to previous error
error: linking with `cc` failed: exit status: 1
  |
  = note: "cc" "-m64" /*A bunch of rust crates*/ "-nodefaultlibs"
  = note: /nix/store/9izhv7bayzj8sr7m5n7c4qw1qk2fhq9s-binutils-2.38/bin/ld: /home/u3836/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-69edc9ac8de4d39c.rlib(std-69edc9ac8de4d39c.std.2a45fe64-cgu.0.rcgu.o): undefined reference to symbol 'gnu_get_libc_version@@GLIBC_2.2.5'
	  /nix/store/9izhv7bayzj8sr7m5n7c4qw1qk2fhq9s-binutils-2.38/bin/ld: /nix/store/d2bpliayddadf6lx6l1i04w265gqw8n6-glibc-2.34-210/lib/libc.so.6: error adding symbols: DSO missing from command line
	  collect2: error: ld returned 1 exit status

  = help: some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified
  = note: use the `-l` flag to specify native libraries to link
  = note: use the `cargo:rustc-link-lib` directive to specify the native libraries to link with Cargo (see https://doc.rust-lang.org/cargo/reference/build-scripts.html#cargorustc-link-libkindname)

error: could not compile `proc-macro2` due to previous error

The version of glibc it tries to link, /nix/store/d2bpliayddadf6lx6l1i04w265gqw8n6-glibc-2.34-210/lib/libc.so.6, is the same regardless of whether musl is there or not according to ldd and that symbol is not there even when it works.

On top of that, it’s still trying to find the glibc symbol when targetting x86_64-unknown-linux-musl.

And if that can’t be solved easily, is there a nix way to have package in buildInputs that isn’t available at build time, just at runtime, while still giving me the path of that package.

Minimal reproduction

If you want to replace glibc dynamic by musl static it’s a toolchain change, so you need cross compilation (native compilation is not possible for static targets because of proc macros). So take all your packages from pkgs.pkgsStatic instead of pkgs.
This patch makes nix build output a musl-static mcve executable. The shell does not work as I expected, though.

diff --git a/flake.nix b/flake.nix
index a01bb38..55908a8 100644
--- a/flake.nix
+++ b/flake.nix
@@ -11,20 +11,21 @@
 			let
 				pkgs = nixpkgs.legacyPackages.${system};
 			in rec {
-				mcve = pkgs.rustPlatform.buildRustPackage {
+				mcve = pkgs.pkgsStatic.rustPlatform.buildRustPackage {
 					pname              = "mcve";
 					version            = "0.0.1";
 					src                = self;
 					cargoSha256        = "sha256-ah8IjShmivS6IWL3ku/4/j+WNr/LdUnh1YJnPdaFdcM=";
 					cargoLock.lockFile = "${self}/Cargo.lock";
-					buildInputs        = with pkgs; [ musl ];
+					# buildInputs        = with pkgs; [ musl ];
 				};
 				defaultPackage = mcve;
 				devShell = pkgs.mkShell {
-					buildInputs       = mcve.buildInputs;
-					nativeBuildInputs = with pkgs; [
-						rustup
-					] ++ mcve.nativeBuildInputs;
+				inputsFrom = [ mcve ];
+					# buildInputs       = mcve.buildInputs;
+					# nativeBuildInputs = with pkgs; [
+					# 	rustup
+					# ] ++ mcve.nativeBuildInputs;
 				};
 			}
 		);

In any case, adding musl to a glibc stdenv will not make what you want, you need to change the stdenv. (just like when you want to swap gcc for gcc6 or for clang).

I wasn’t trying to compile rust with musl, I am writing a compiler and wanted musl available at runtime to link against then.

But I solved it with some help from reddit.
Thanks anyway

What was your solution in the end (if you have time to write it up)?

The solution was to use a wrapper script.

Here’s the flake as it looks now

1 Like