third_party/nix: introduce toolchain bundle

This introduces a nix derivation that builds a musl amd64/aarch64
toolchain sysroot.

Change-Id: Iba082edb8fd1f2ab580020bb1c7339a76487f3c8
Reviewed-on: https://review.monogon.dev/c/monogon/+/4006
Reviewed-by: Lorenz Brun <lorenz@monogon.tech>
Tested-by: Jenkins CI
diff --git a/third_party/nix/BUILD.bazel b/third_party/nix/BUILD.bazel
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/nix/BUILD.bazel
diff --git a/third_party/nix/default.nix b/third_party/nix/default.nix
new file mode 100644
index 0000000..7688b7f
--- /dev/null
+++ b/third_party/nix/default.nix
@@ -0,0 +1,26 @@
+{ sources ? import ./sources.nix }:
+let
+  pkgs = import sources.nixpkgs
+    {
+      overlays = [
+        (self: super: {
+          qemu-minimal = import ./pkgs/qemu { pkgs = super; };
+          diffutils = import ./pkgs/diffutils { pkgs = super; };
+          util-linux-minimal = (import ./pkgs/util-linux { pkgs = super; });
+          bazel-unwrapped = import ./pkgs/bazel { pkgs = super; };
+          perl = import ./pkgs/perl { pkgs = super; };
+        })
+        (self: super: {
+          vde2 = super.vde2.overrideAttrs (oldAttrs: {
+            env.NIX_CFLAGS_COMPILE = (oldAttrs.NIX_CFLAGS_COMPILE or "") + " -Wno-error=int-conversion -Wno-error=implicit-function-declaration";
+          });
+        })
+      ];
+
+      config.replaceCrossStdenv = { buildPackages, baseStdenv }:
+        (buildPackages.withCFlags [ "-fPIC" ]) baseStdenv;
+    };
+in
+pkgs // {
+  lib.version = "${sources.nixpkgs.branch}.${sources.nixpkgs.rev}";
+}
diff --git a/third_party/nix/env.nix b/third_party/nix/env.nix
deleted file mode 100644
index 320e3df..0000000
--- a/third_party/nix/env.nix
+++ /dev/null
@@ -1,85 +0,0 @@
-{ pkgs, extraConf ? "" }: with pkgs;
-let
-  wrapper = pkgs.writeScript "wrapper.sh"
-    ''
-      # Fancy colorful PS1 to make people notice easily they're in the Monogon Nix shell.
-      PS1='\[\033]0;\u/monogon:\w\007\]'
-      if type -P dircolors >/dev/null ; then
-        PS1+='\[\033[01;35m\]\u/monogon\[\033[01;36m\] \w \$\[\033[00m\] '
-      fi
-      export PS1
-
-      # Use Nix-provided cert store.
-      export NIX_SSL_CERT_FILE="${cacert}/etc/ssl/certs/ca-bundle.crt"
-      export SSL_CERT_FILE="${cacert}/etc/ssl/certs/ca-bundle.crt"
-
-      # Let some downstream machinery know we're on NixOS. This is used mostly to
-      # work around Bazel/NixOS interactions.
-      export MONOGON_NIXOS=yep
-
-      # Convince rules_go to use /bin/bash and not a NixOS store bash which has
-      # no idea how to resolve other things in the nix store once PATH is
-      # stripped by (host_)action_env.
-      export BAZEL_SH=/bin/bash
-
-      # buildFHSEnv makes /etc a tmpfs and symlinks some files from host /etc.
-      # Create some additional symlinks for files we want from host /etc.
-      for i in bazel.bazelrc gitconfig; do
-          if [[ -e "/.host-etc/$i" ]] && [[ ! -e "/etc/$i" ]]; then
-              ln -s "/.host-etc/$i" "/etc/$i"
-          fi
-      done
-
-      ${extraConf}
-
-      # Allow passing a custom command via env since nix-shell doesn't support
-      # this yet: https://github.com/NixOS/nix/issues/534
-      if [ ! -n "$COMMAND" ]; then
-          COMMAND="bash --noprofile --norc"
-      fi
-      exec $COMMAND
-    '';
-in
-(pkgs.buildFHSEnv {
-  name = "monogon-nix";
-  targetPkgs = pkgs: with pkgs; [
-    git
-    buildifier
-    (stdenv.mkDerivation {
-      name = "bazel";
-      src = builtins.fetchurl {
-        url = "https://github.com/bazelbuild/bazel/releases/download/8.1.0/bazel-8.1.0-linux-x86_64";
-        sha256 = "19dwgh631d6c1m4ds1b1b3pbz18zm5i0x8bggjgsc04fyljfbfml";
-      };
-      unpackPhase = ''
-        true
-      '';
-      nativeBuildInputs = [ makeWrapper ];
-      buildPhase = ''
-        mkdir -p $out/bin
-        cp $src $out/bin/.bazel-inner
-        chmod +x $out/bin/.bazel-inner
-
-        cp ${./bazel-inner.sh} $out/bin/bazel
-        chmod +x $out/bin/bazel
-
-        # Use wrapProgram to set the actual bazel path
-        wrapProgram $out/bin/bazel --set BAZEL_REAL $out/bin/.bazel-inner
-      '';
-      dontStrip = true;
-    })
-    zlib
-    curl
-    gcc
-    binutils
-    openjdk21
-    patch
-    python3
-    busybox
-    niv
-    google-cloud-sdk
-    qemu_kvm
-    swtpm
-  ];
-  runScript = wrapper;
-})
diff --git a/third_party/nix/pkgs/bazel/BUILD.bazel b/third_party/nix/pkgs/bazel/BUILD.bazel
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/nix/pkgs/bazel/BUILD.bazel
diff --git a/third_party/nix/bazel-inner.sh b/third_party/nix/pkgs/bazel/bazel-inner.sh
similarity index 100%
rename from third_party/nix/bazel-inner.sh
rename to third_party/nix/pkgs/bazel/bazel-inner.sh
diff --git a/third_party/nix/pkgs/bazel/default.nix b/third_party/nix/pkgs/bazel/default.nix
new file mode 100644
index 0000000..0b6ba7e
--- /dev/null
+++ b/third_party/nix/pkgs/bazel/default.nix
@@ -0,0 +1,24 @@
+{ pkgs }: with pkgs;
+stdenv.mkDerivation {
+  name = "bazel";
+  src = builtins.fetchurl {
+    url = "https://github.com/bazelbuild/bazel/releases/download/8.1.0/bazel-8.1.0-linux-x86_64";
+    sha256 = "19dwgh631d6c1m4ds1b1b3pbz18zm5i0x8bggjgsc04fyljfbfml";
+  };
+  unpackPhase = ''
+    true
+  '';
+  nativeBuildInputs = [ makeWrapper ];
+  buildPhase = ''
+    mkdir -p $out/bin
+    cp $src $out/bin/.bazel-inner
+    chmod +x $out/bin/.bazel-inner
+
+    cp ${./bazel-inner.sh} $out/bin/bazel
+    chmod +x $out/bin/bazel
+
+    # Use wrapProgram to set the actual bazel path
+    wrapProgram $out/bin/bazel --set BAZEL_REAL $out/bin/.bazel-inner
+  '';
+  dontStrip = true;
+}
diff --git a/third_party/nix/pkgs/diffutils/BUILD.bazel b/third_party/nix/pkgs/diffutils/BUILD.bazel
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/nix/pkgs/diffutils/BUILD.bazel
diff --git a/third_party/nix/pkgs/diffutils/default.nix b/third_party/nix/pkgs/diffutils/default.nix
new file mode 100644
index 0000000..bbb38e3
--- /dev/null
+++ b/third_party/nix/pkgs/diffutils/default.nix
@@ -0,0 +1,39 @@
+{ pkgs }: with pkgs;
+if (!stdenv.hostPlatform.isStatic) then diffutils else
+diffutils.overrideAttrs (old: {
+  # Disable tests as they fail when static build.
+
+  # FAIL: test-getopt-gnu
+  #=====================
+  #
+  #test-getopt.h:661: assertion 'optind == 2' failed
+  #FAIL test-getopt-gnu (exit status: 134)
+  #
+  #FAIL: test-getopt-posix
+  #=======================
+  #
+  #test-getopt.h:661: assertion 'optind == 2' failed
+  #FAIL test-getopt-posix (exit status: 134)
+  #
+  #FAIL: test-nl_langinfo-mt
+  #=========================
+  #
+  #FAIL test-nl_langinfo-mt (exit status: 134)
+  #
+  #FAIL: test-random-mt
+  #====================
+  #
+  #FAIL test-random-mt (exit status: 134)
+  #
+  #FAIL: test-setlocale_null-mt-one
+  #================================
+  #
+  #FAIL test-setlocale_null-mt-one (exit status: 134)
+  #
+  #FAIL: test-setlocale_null-mt-all
+  #================================
+  #
+  #FAIL test-setlocale_null-mt-all (exit status: 134)
+  doCheck = false;
+  doInstallCheck = false;
+})
diff --git a/third_party/nix/pkgs/perl/BUILD.bazel b/third_party/nix/pkgs/perl/BUILD.bazel
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/nix/pkgs/perl/BUILD.bazel
diff --git a/third_party/nix/pkgs/perl/default.nix b/third_party/nix/pkgs/perl/default.nix
new file mode 100644
index 0000000..c2677b5
--- /dev/null
+++ b/third_party/nix/pkgs/perl/default.nix
@@ -0,0 +1,24 @@
+{ pkgs }: with pkgs;
+if (!stdenv.hostPlatform.isStatic) then perl else
+perl.overrideAttrs (old: {
+  patches = old.patches ++ [
+    ./static_build.patch
+  ];
+
+  preConfigure = old.preConfigure + ''
+    cat >> config.over <<EOF
+    osvers="musllinux"
+    EOF
+  '';
+
+  configureFlags = old.configureFlags ++ [
+    "-Dotherlibdirs=.../../lib/perl5/${old.version}" # Tell perl to use a relative libdir
+    # 1. Why isn't this the default?
+    # 2. Apparently nobody uses this option, because it is missing the quotes inside the config_h.SH
+    # 3. Why should a variable called "procselfexe" be used with a different path than /proc/self/exe?
+    # 4. I really dislike perl. - fionera
+    "-Dprocselfexe=\"/proc/self/exe\""
+  ];
+
+  env.NIX_CFLAGS_COMPILE = (old.NIX_CFLAGS_COMPILE or "") + " -Wno-error=implicit-function-declaration";
+})
diff --git a/third_party/nix/pkgs/perl/static_build.patch b/third_party/nix/pkgs/perl/static_build.patch
new file mode 100644
index 0000000..8562a3f
--- /dev/null
+++ b/third_party/nix/pkgs/perl/static_build.patch
@@ -0,0 +1,13 @@
+diff --git a/ext/re/Makefile.PL b/ext/re/Makefile.PL
+--- a/ext/re/Makefile.PL
++++ b/ext/re/Makefile.PL
+@@ -27,8 +27,9 @@
+     }
+ }
+ 
+ my $defines = '-DPERL_EXT_RE_BUILD -DPERL_EXT_RE_DEBUG -DPERL_EXT';
++$defines .= ' -DPERL_EXT_RE_STATIC';
+ my %args;
+ for my $arg (@ARGV) {
+     $args{$1} = $2 if $arg =~ /^(\w+)=(.*)$/;
+ }
diff --git a/third_party/nix/pkgs/qemu/BUILD.bazel b/third_party/nix/pkgs/qemu/BUILD.bazel
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/nix/pkgs/qemu/BUILD.bazel
diff --git a/third_party/nix/pkgs/qemu/default.nix b/third_party/nix/pkgs/qemu/default.nix
new file mode 100644
index 0000000..5134cb7
--- /dev/null
+++ b/third_party/nix/pkgs/qemu/default.nix
@@ -0,0 +1,48 @@
+{ pkgs }: with pkgs;
+
+let
+  qemuMinimal = qemu_kvm.override (old: {
+    hostCpuOnly = true;
+    vncSupport = true;
+
+    # Disable everything we don't need.
+    enableDocs = false;
+    ncursesSupport = false;
+    seccompSupport = false;
+    numaSupport = false;
+    alsaSupport = false;
+    pulseSupport = false;
+    pipewireSupport = false;
+    sdlSupport = false;
+    jackSupport = false;
+    gtkSupport = false;
+    smartcardSupport = false;
+    spiceSupport = false;
+    usbredirSupport = false;
+    xenSupport = false;
+    cephSupport = false;
+    glusterfsSupport = false;
+    openGLSupport = false;
+    rutabagaSupport = false;
+    virglSupport = false;
+    libiscsiSupport = false;
+    smbdSupport = false;
+    uringSupport = false;
+    canokeySupport = false;
+    capstoneSupport = false;
+  });
+in
+qemuMinimal.overrideAttrs (old: {
+  # Static build patch
+  # Based on https://github.com/NixOS/nixpkgs/pull/333923
+
+  patches = (old.patches ++ [
+    ./static_build_crc32c_duplicate_definition.patch
+  ]);
+
+  configureFlags = (builtins.filter (v: v != "--static") old.configureFlags) ++ [ "--disable-libcbor" ];
+  strictDeps = true;
+  # a private dependency of PAM which is not linked explicitly in static builds
+  buildInputs = old.buildInputs ++ [ pkgs.audit ];
+  env.NIX_LDFLAGS = " -laudit ";
+})
diff --git a/third_party/nix/pkgs/qemu/static_build_crc32c_duplicate_definition.patch b/third_party/nix/pkgs/qemu/static_build_crc32c_duplicate_definition.patch
new file mode 100644
index 0000000..8e6c033
--- /dev/null
+++ b/third_party/nix/pkgs/qemu/static_build_crc32c_duplicate_definition.patch
@@ -0,0 +1,117 @@
+commit 0ba0f342e2f3cb1d271d324d999d80d5c2834f2b
+Author: Guillaume Girol <symphorien+git@xlumurb.eu>
+Date:   Sun Aug 11 12:00:00 2024 +0000
+
+    rename crc32c to a less generic name
+    
+    when compiling qemu statically, this symbol clashes to one in libblkid.
+
+diff --git a/block/vhdx.c b/block/vhdx.c
+index 5aa1a13506..0dc9df217d 100644
+--- a/block/vhdx.c
++++ b/block/vhdx.c
+@@ -157,7 +157,7 @@ uint32_t vhdx_update_checksum(uint8_t *buf, size_t size, int crc_offset)
+     assert(size > (crc_offset + sizeof(crc)));
+ 
+     memset(buf + crc_offset, 0, sizeof(crc));
+-    crc =  crc32c(0xffffffff, buf, size);
++    crc =  qemu_crc32c(0xffffffff, buf, size);
+     crc = cpu_to_le32(crc);
+     memcpy(buf + crc_offset, &crc, sizeof(crc));
+ 
+@@ -176,7 +176,7 @@ uint32_t vhdx_checksum_calc(uint32_t crc, uint8_t *buf, size_t size,
+         memset(buf + crc_offset, 0, sizeof(crc_orig));
+     }
+ 
+-    crc_new = crc32c(crc, buf, size);
++    crc_new = qemu_crc32c(crc, buf, size);
+     if (crc_offset > 0) {
+         memcpy(buf + crc_offset, &crc_orig, sizeof(crc_orig));
+     }
+diff --git a/hw/net/net_rx_pkt.c b/hw/net/net_rx_pkt.c
+index 32e5f3f9cf..a53238e143 100644
+--- a/hw/net/net_rx_pkt.c
++++ b/hw/net/net_rx_pkt.c
+@@ -579,7 +579,7 @@ _net_rx_pkt_validate_sctp_sum(struct NetRxPkt *pkt)
+         return false;
+     }
+ 
+-    calculated = crc32c(0xffffffff,
++    calculated = qemu_crc32c(0xffffffff,
+                         (uint8_t *)vec->iov_base + off, vec->iov_len - off);
+     calculated = iov_crc32c(calculated ^ 0xffffffff, vec + 1, vec_len - 1);
+     valid = calculated == le32_to_cpu(original);
+diff --git a/include/qemu/crc32c.h b/include/qemu/crc32c.h
+index 88b4d2b3b3..b0f535c80e 100644
+--- a/include/qemu/crc32c.h
++++ b/include/qemu/crc32c.h
+@@ -29,7 +29,7 @@
+ #define QEMU_CRC32C_H
+ 
+ 
+-uint32_t crc32c(uint32_t crc, const uint8_t *data, unsigned int length);
++uint32_t qemu_crc32c(uint32_t crc, const uint8_t *data, unsigned int length);
+ uint32_t iov_crc32c(uint32_t crc, const struct iovec *iov, size_t iov_cnt);
+ 
+ #endif
+diff --git a/target/arm/helper.c b/target/arm/helper.c
+index 8fb4b474e8..cc5b2a8e99 100644
+--- a/target/arm/helper.c
++++ b/target/arm/helper.c
+@@ -12409,7 +12409,7 @@ uint32_t HELPER(crc32c)(uint32_t acc, uint32_t val, uint32_t bytes)
+     stl_le_p(buf, val);
+ 
+     /* Linux crc32c converts the output to one's complement.  */
+-    return crc32c(acc, buf, bytes) ^ 0xffffffff;
++    return qemu_crc32c(acc, buf, bytes) ^ 0xffffffff;
+ }
+ 
+ /*
+diff --git a/target/arm/tcg/helper-a64.c b/target/arm/tcg/helper-a64.c
+index c60d2a7ec9..d64912d4eb 100644
+--- a/target/arm/tcg/helper-a64.c
++++ b/target/arm/tcg/helper-a64.c
+@@ -514,7 +514,7 @@ uint64_t HELPER(crc32c_64)(uint64_t acc, uint64_t val, uint32_t bytes)
+     stq_le_p(buf, val);
+ 
+     /* Linux crc32c converts the output to one's complement.  */
+-    return crc32c(acc, buf, bytes) ^ 0xffffffff;
++    return qemu_crc32c(acc, buf, bytes) ^ 0xffffffff;
+ }
+ 
+ /*
+diff --git a/target/loongarch/tcg/op_helper.c b/target/loongarch/tcg/op_helper.c
+index fe79c62fa4..a90db6f4b9 100644
+--- a/target/loongarch/tcg/op_helper.c
++++ b/target/loongarch/tcg/op_helper.c
+@@ -77,7 +77,7 @@ target_ulong helper_crc32c(target_ulong val, target_ulong m, uint64_t sz)
+     target_ulong mask = ((sz * 8) == 64) ? -1ULL : ((1ULL << (sz * 8)) - 1);
+     m &= mask;
+     stq_le_p(buf, m);
+-    return (int32_t) (crc32c(val, buf, sz) ^ 0xffffffff);
++    return (int32_t) (qemu_crc32c(val, buf, sz) ^ 0xffffffff);
+ }
+ 
+ target_ulong helper_cpucfg(CPULoongArchState *env, target_ulong rj)
+diff --git a/util/crc32c.c b/util/crc32c.c
+index ea7f345de8..2780a5c698 100644
+--- a/util/crc32c.c
++++ b/util/crc32c.c
+@@ -105,7 +105,7 @@ static const uint32_t crc32c_table[256] = {
+ };
+ 
+ 
+-uint32_t crc32c(uint32_t crc, const uint8_t *data, unsigned int length)
++uint32_t qemu_crc32c(uint32_t crc, const uint8_t *data, unsigned int length)
+ {
+     while (length--) {
+         crc = crc32c_table[(crc ^ *data++) & 0xFFL] ^ (crc >> 8);
+@@ -116,7 +116,7 @@ uint32_t crc32c(uint32_t crc, const uint8_t *data, unsigned int length)
+ uint32_t iov_crc32c(uint32_t crc, const struct iovec *iov, size_t iov_cnt)
+ {
+     while (iov_cnt--) {
+-        crc = crc32c(crc, iov->iov_base, iov->iov_len) ^ 0xffffffff;
++        crc = qemu_crc32c(crc, iov->iov_base, iov->iov_len) ^ 0xffffffff;
+         iov++;
+     }
+     return crc ^ 0xffffffff;
diff --git a/third_party/nix/pkgs/util-linux/BUILD.bazel b/third_party/nix/pkgs/util-linux/BUILD.bazel
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/nix/pkgs/util-linux/BUILD.bazel
diff --git a/third_party/nix/pkgs/util-linux/default.nix b/third_party/nix/pkgs/util-linux/default.nix
new file mode 100644
index 0000000..1935cd3
--- /dev/null
+++ b/third_party/nix/pkgs/util-linux/default.nix
@@ -0,0 +1,11 @@
+{ pkgs }: with pkgs;
+util-linux.override (old: {
+  pamSupport = false;
+  ncursesSupport = false;
+  capabilitiesSupport = false;
+  systemdSupport = false;
+  translateManpages = false;
+  nlsSupport = false;
+  shadowSupport = false;
+  writeSupport = false;
+})
diff --git a/third_party/nix/sources.json b/third_party/nix/sources.json
index 64f092e..cab06c9 100644
--- a/third_party/nix/sources.json
+++ b/third_party/nix/sources.json
@@ -5,10 +5,10 @@
         "homepage": null,
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "265df80a8c6cfe3e9012788d8d7f95b98850267e",
-        "sha256": "17p3nqh8bs66x1g9mdvixlsc23g0g7g1v9k94q7adn6n5ijps08m",
+        "rev": "ffdcefdde9a4e540d1c875767da0e382e1ccf460",
+        "sha256": "1ws459m6pb07cy4n5xj5zx6i2d9xjk3xfl369s5jjvrblzlyq6mf",
         "type": "tarball",
-        "url": "https://github.com/NixOS/nixpkgs/archive/265df80a8c6cfe3e9012788d8d7f95b98850267e.tar.gz",
+        "url": "https://github.com/NixOS/nixpkgs/archive/ffdcefdde9a4e540d1c875767da0e382e1ccf460.tar.gz",
         "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
     }
 }