about summary refs log tree commit diff
path: root/pkgs/os-specific/linux/minimal-bootstrap
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/os-specific/linux/minimal-bootstrap')
-rw-r--r--pkgs/os-specific/linux/minimal-bootstrap/binutils/default.nix118
-rw-r--r--pkgs/os-specific/linux/minimal-bootstrap/binutils/deterministic.patch12
-rw-r--r--pkgs/os-specific/linux/minimal-bootstrap/default.nix37
-rw-r--r--pkgs/os-specific/linux/minimal-bootstrap/gcc/2.nix140
-rw-r--r--pkgs/os-specific/linux/minimal-bootstrap/glibc/default.nix121
-rw-r--r--pkgs/os-specific/linux/minimal-bootstrap/linux-headers/default.nix49
-rw-r--r--pkgs/os-specific/linux/minimal-bootstrap/stage0-posix/bootstrap-sources.nix108
-rw-r--r--pkgs/os-specific/linux/minimal-bootstrap/stage0-posix/default.nix5
-rw-r--r--pkgs/os-specific/linux/minimal-bootstrap/stage0-posix/hex0.nix2
-rw-r--r--pkgs/os-specific/linux/minimal-bootstrap/stage0-posix/kaem/minimal.nix2
-rw-r--r--pkgs/os-specific/linux/minimal-bootstrap/stage0-posix/make-bootstrap-sources.nix37
-rw-r--r--pkgs/os-specific/linux/minimal-bootstrap/utils.nix4
12 files changed, 599 insertions, 36 deletions
diff --git a/pkgs/os-specific/linux/minimal-bootstrap/binutils/default.nix b/pkgs/os-specific/linux/minimal-bootstrap/binutils/default.nix
new file mode 100644
index 000000000000..8722ff818297
--- /dev/null
+++ b/pkgs/os-specific/linux/minimal-bootstrap/binutils/default.nix
@@ -0,0 +1,118 @@
+{ lib
+, buildPlatform
+, hostPlatform
+, fetchurl
+, bash
+, gnumake
+, gnupatch
+, gnugrep
+, gnutar
+, gawk
+, bzip2
+, sed
+, mesBootstrap ? false, tinycc ? null
+, gcc ? null, glibc ? null, binutils ? null, linux-headers
+}:
+assert mesBootstrap -> tinycc != null;
+assert !mesBootstrap -> gcc != null && glibc != null && binutils != null;
+let
+  pname = "binutils" + lib.optionalString mesBootstrap "-mes";
+  version = "2.20.1";
+  rev = "a";
+
+  src = fetchurl {
+    url = "mirror://gnu/binutils/binutils-${version}${rev}.tar.bz2";
+    sha256 = "0r7dr0brfpchh5ic0z9r4yxqn4ybzmlh25sbp30cacqk8nb7rlvi";
+  };
+
+  patches = [
+    # Enables building binutils using TCC and Mes C Library
+    (fetchurl {
+      url = "https://git.savannah.gnu.org/cgit/guix.git/plain/gnu/packages/patches/binutils-boot-2.20.1a.patch?id=50249cab3a98839ade2433456fe618acc6f804a5";
+      sha256 = "086sf6an2k56axvs4jlky5n3hs2l3rq8zq5d37h0b69cdyh7igpn";
+    })
+
+    # Make binutils output deterministic by default.
+    ./deterministic.patch
+  ];
+
+  configureFlags = [
+    "--disable-nls"
+    "--disable-shared"
+    "--disable-werror"
+    "--prefix=${placeholder "out"}"
+
+    "--build=${buildPlatform.config}"
+    "--host=${hostPlatform.config}"
+
+    # Turn on --enable-new-dtags by default to make the linker set
+    # RUNPATH instead of RPATH on binaries.  This is important because
+    # RUNPATH can be overridden using LD_LIBRARY_PATH at runtime.
+    "--enable-new-dtags"
+
+    # By default binutils searches $libdir for libraries. This brings in
+    # libbfd and libopcodes into a default visibility. Drop default lib
+    # path to force users to declare their use of these libraries.
+    "--with-lib-path=:"
+  ];
+in
+bash.runCommand "${pname}-${version}" {
+  inherit pname version;
+
+  nativeBuildInputs = [
+    (if mesBootstrap then tinycc.compiler else gcc)
+    gnumake
+    gnupatch
+    gnugrep
+    gnutar
+    gawk
+    bzip2
+    sed
+  ] ++ lib.optional (!mesBootstrap) binutils;
+
+  passthru.tests.get-version = result:
+    bash.runCommand "${pname}-get-version-${version}" {} ''
+      ${result}/bin/ld --version
+      mkdir $out
+    '';
+
+  meta = with lib; {
+    description = "Tools for manipulating binaries (linker, assembler, etc.)";
+    homepage = "https://www.gnu.org/software/binutils";
+    license = licenses.gpl3Plus;
+    maintainers = teams.minimal-bootstrap.members;
+    platforms = platforms.unix;
+  };
+} ''
+  # Unpack
+  cp ${src} binutils.tar.bz2
+  bunzip2 binutils.tar.bz2
+  tar xf binutils.tar
+  rm binutils.tar
+  cd binutils-${version}
+
+  # Patch
+  ${lib.concatMapStringsSep "\n" (f: "patch -Np1 -i ${f}") patches}
+  # Clear the default library search path.
+  echo 'NATIVE_LIB_DIRS=' >> ld/configure.tgt
+
+  # Configure
+  ${if mesBootstrap then ''
+    export CC="tcc -B ${tinycc.libs}/lib -D __GLIBC_MINOR__=6 -D MES_BOOTSTRAP=1"
+    export AR="tcc -ar"
+  '' else ''
+    export CC="gcc -B ${glibc}/lib -I${glibc}/include -I${linux-headers}/include"
+    export CPP="gcc -E -I${glibc}/include -I${linux-headers}/include"
+    export AR="ar"
+    export LIBRARY_PATH="${glibc}/lib"
+    export LIBS="-lc -lnss_files -lnss_dns -lresolv"
+  ''}
+  export SED=sed
+  bash ./configure ${lib.concatStringsSep " " configureFlags}
+
+  # Build
+  make
+
+  # Install
+  make install
+''
diff --git a/pkgs/os-specific/linux/minimal-bootstrap/binutils/deterministic.patch b/pkgs/os-specific/linux/minimal-bootstrap/binutils/deterministic.patch
new file mode 100644
index 000000000000..736e0aca6ce1
--- /dev/null
+++ b/pkgs/os-specific/linux/minimal-bootstrap/binutils/deterministic.patch
@@ -0,0 +1,12 @@
+diff -ur orig/binutils-2.23.1/ld/ldlang.c binutils-2.23.1/ld/ldlang.c
+--- orig/ld/ldlang.c
++++ new/ld/ldlang.c
+@@ -3095,6 +3095,8 @@
+                           ldfile_output_machine))
+     einfo (_("%P%F:%s: can not set architecture: %E\n"), name);
+ 
++  link_info.output_bfd->flags |= BFD_DETERMINISTIC_OUTPUT;
++
+   link_info.hash = bfd_link_hash_table_create (link_info.output_bfd);
+   if (link_info.hash == NULL)
+     einfo (_("%P%F: can not create hash table: %E\n"));
diff --git a/pkgs/os-specific/linux/minimal-bootstrap/default.nix b/pkgs/os-specific/linux/minimal-bootstrap/default.nix
index 9011c45a8fe3..45175b987cad 100644
--- a/pkgs/os-specific/linux/minimal-bootstrap/default.nix
+++ b/pkgs/os-specific/linux/minimal-bootstrap/default.nix
@@ -15,6 +15,20 @@ lib.makeScope
 
     bash_2_05 = callPackage ./bash/2.nix { tinycc = tinycc-mes; };
 
+    binutils = callPackage ./binutils {
+      bash = bash_2_05;
+      gcc = gcc2;
+      binutils = binutils-mes;
+      glibc = glibc22;
+      sed = heirloom.sed;
+    };
+    binutils-mes = callPackage ./binutils {
+      bash = bash_2_05;
+      tinycc = tinycc-mes;
+      sed = heirloom.sed;
+      mesBootstrap = true;
+    };
+
     bzip2 = callPackage ./bzip2 {
       bash = bash_2_05;
       tinycc = tinycc-mes;
@@ -27,6 +41,23 @@ lib.makeScope
       tinycc = tinycc-mes;
     };
 
+    gcc2 = callPackage ./gcc/2.nix {
+      bash = bash_2_05;
+      gcc = gcc2-mes;
+      binutils = binutils-mes;
+      glibc = glibc22;
+    };
+    gcc2-mes = callPackage ./gcc/2.nix {
+      bash = bash_2_05;
+      tinycc = tinycc-mes;
+      binutils = binutils-mes;
+      mesBootstrap = true;
+    };
+
+    inherit (callPackage ./glibc {
+      bash = bash_2_05;
+    }) glibc22;
+
     gnugrep = callPackage ./gnugrep {
       bash = bash_2_05;
       tinycc = tinycc-mes;
@@ -58,6 +89,8 @@ lib.makeScope
 
     heirloom-devtools = callPackage ./heirloom-devtools { tinycc = tinycc-mes; };
 
+    linux-headers = callPackage ./linux-headers { bash = bash_2_05; };
+
     ln-boot = callPackage ./ln-boot { };
 
     mes = lib.recurseIntoAttrs (callPackage ./mes { });
@@ -80,8 +113,12 @@ lib.makeScope
 
     test = kaem.runCommand "minimal-bootstrap-test" {} ''
       echo ${bash_2_05.tests.get-version}
+      echo ${binutils.tests.get-version}
+      echo ${binutils-mes.tests.get-version}
       echo ${bzip2.tests.get-version}
       echo ${gawk.tests.get-version}
+      echo ${gcc2.tests.get-version}
+      echo ${gcc2-mes.tests.get-version}
       echo ${gnugrep.tests.get-version}
       echo ${gnused.tests.get-version}
       echo ${gnutar.tests.get-version}
diff --git a/pkgs/os-specific/linux/minimal-bootstrap/gcc/2.nix b/pkgs/os-specific/linux/minimal-bootstrap/gcc/2.nix
new file mode 100644
index 000000000000..0a79c97e75af
--- /dev/null
+++ b/pkgs/os-specific/linux/minimal-bootstrap/gcc/2.nix
@@ -0,0 +1,140 @@
+{ lib
+, buildPlatform
+, hostPlatform
+, fetchurl
+, bash
+, gnumake
+, gnupatch
+, gnugrep
+, gnutar
+, gzip
+, heirloom
+, binutils
+, mesBootstrap ? false, tinycc ? null, mes-libc
+, gcc ? null, glibc ? null, linux-headers
+}:
+assert mesBootstrap -> tinycc != null;
+assert !mesBootstrap -> gcc != null && glibc != null;
+let
+  # Gcc-2.95.3 is the most recent GCC that is supported by what the Mes C
+  # Library v0.16 offers.  Gcc-3.x (and 4.x) place higher demands on a C
+  # library, such as dir.h/struct DIR/readdir, locales, signals...  Also,
+  # with gcc-2.95.3, binutils (2.14.0, 2.20.1a) and glibc-2.2.5 we found a
+  # GNU toolchain triplet "that works".
+  #   - from guix/gnu/packages/commencement.scm
+  pname = "gcc" + lib.optionalString mesBootstrap "-mes";
+  version = "2.95.3";
+
+  src = fetchurl {
+    url = "mirror://gnu/gcc/gcc-${version}/gcc-core-${version}.tar.gz";
+    sha256 = "1xvfy4pqhrd5v2cv8lzf63iqg92k09g6z9n2ah6ndd4h17k1x0an";
+  };
+
+  patches = [
+    # This patch enables building gcc-2.95.3 using TCC and Mes C Library.
+    #   * Disable building DOC
+    #   * Avoid running `fixproto'.
+    #   * Force running `fixinc'.
+    #   * Replace Makefile trickery of creating an libgcc1.a archive, then
+    #     extracting the .o files later to create a new libgcc2.a archive.
+    #     Instead, keep temporary .o files.
+    (fetchurl {
+      url = "https://git.savannah.gnu.org/cgit/guix.git/plain/gnu/packages/patches/gcc-boot-2.95.3.patch?id=50249cab3a98839ade2433456fe618acc6f804a5";
+      sha256 = "03l3jaxch6d76mx4zkn6ky64paj58jk0biddck01qd4bnw9z8hiw";
+    })
+  ];
+
+  makeFlags = [
+    "LANGUAGES=c"
+  ] ++ lib.optionals mesBootstrap [
+    "LIBGCC2_INCLUDES=\"-I ${mes-libc}/include\""
+    "BOOT_LDFLAGS=\" -B ${tinycc.libs}/lib\""
+  ] ++ lib.optionals (!mesBootstrap) [
+    "LIBGCC2_INCLUDES=\"-I ${glibc}/include -I ${linux-headers}/include\""
+  ];
+in
+bash.runCommand "${pname}-${version}" {
+  inherit pname version;
+
+  nativeBuildInputs = [
+    (if mesBootstrap then tinycc.compiler else gcc)
+    gnumake
+    gnupatch
+    gnugrep
+    gnutar
+    gzip
+    heirloom.sed
+    binutils
+  ];
+
+  passthru.tests.get-version = result:
+    bash.runCommand "${pname}-get-version-${version}" {} ''
+      ${result}/bin/gcc --version
+      mkdir $out
+    '';
+
+  meta = with lib; {
+    description = "GNU Compiler Collection, version ${version}";
+    homepage = "https://gcc.gnu.org";
+    license = licenses.gpl3Plus;
+    maintainers = teams.minimal-bootstrap.members;
+    platforms = platforms.unix;
+  };
+} ''
+  # Unpack
+  tar xzf ${src}
+  cd gcc-${version}
+
+  # Patch
+  ${lib.concatMapStringsSep "\n" (f: "patch -Np1 -i ${f}") patches}
+  # /build/glibc-2.2.5/intl/loadmsgcat.c:334: multiple definition of `_nl_load_domain'
+  # ../intl/libintl.a(loadmsgcat.o):/build/gcc-2.95.3/texinfo/intl/loadmsgcat.c:66: first defined here
+  rm -R texinfo
+  mkdir -p texinfo
+  echo 'all:'>texinfo/Makefile.in
+  echo 'install:'>>texinfo/Makefile.in
+
+  # Configure
+  ${if mesBootstrap then ''
+    export CC="tcc -B ${tinycc.libs}/lib -D __GLIBC_MINOR__=6"
+    export CPP="tcc -E"
+    export ac_cv_func_setlocale=no
+  '' else ''
+    export CC="gcc -I${glibc}/include -I${linux-headers}/include -I${gcc}/lib/gcc-lib/${hostPlatform.config}/${version}/include"
+    export CPP="gcc -E -I${glibc}/include -I${linux-headers}/include -I${gcc}/lib/gcc-lib/${hostPlatform.config}/${version}/include"
+    export LIBRARY_PATH="${glibc}/lib"
+    export LIBS="-lc -lnss_files -lnss_dns -lresolv"
+  ''}
+  export OLDCC="$CC"
+  export CC_FOR_BUILD="$CC"
+  export AR=ar
+  export RANLIB=ranlib
+  export ac_cv_c_float_format='IEEE (little-endian)'
+  bash ./configure \
+    --build=${buildPlatform.config} \
+    --host=${hostPlatform.config} \
+    --enable-static \
+    --disable-shared \
+    --disable-werror \
+    --prefix=$out
+  # no info at this stage
+  touch gcc/cpp.info gcc/gcc.info
+
+  # Build
+  make ${lib.concatStringsSep " " makeFlags}
+
+  # Install
+  make install
+  mkdir tmp
+  cd tmp
+  ar x ../gcc/libgcc2.a
+  ${lib.optionalString mesBootstrap "ar x ${tinycc.libs}/lib/libtcc1.a"}
+  ar r $out/lib/gcc-lib/${hostPlatform.config}/${version}/libgcc.a *.o
+  cd ..
+  ${lib.optionalString mesBootstrap ''
+    cp gcc/libgcc2.a $out/lib/libgcc2.a
+    ar x ${tinycc.libs}/lib/libtcc1.a
+    ar x ${tinycc.libs}/lib/libc.a
+    ar r $out/lib/gcc-lib/${hostPlatform.config}/${version}/libc.a libc.o libtcc1.o
+  ''}
+''
diff --git a/pkgs/os-specific/linux/minimal-bootstrap/glibc/default.nix b/pkgs/os-specific/linux/minimal-bootstrap/glibc/default.nix
new file mode 100644
index 000000000000..5c4ff386add5
--- /dev/null
+++ b/pkgs/os-specific/linux/minimal-bootstrap/glibc/default.nix
@@ -0,0 +1,121 @@
+{ lib
+, buildPlatform
+, hostPlatform
+, fetchurl
+, bash
+, gcc2-mes
+, gnumake
+, gnupatch
+, gnused
+, gnugrep
+, gnutar
+, gzip
+, gawk
+, heirloom
+, binutils-mes
+, linux-headers
+}:
+let
+  pname = "glibc";
+
+  buildGlibc = { version, src, patches, configureFlags, gcc, binutils, CC, CPP }:
+    bash.runCommand "${pname}-${version}" {
+      inherit pname version;
+
+      nativeBuildInputs = [
+        gcc
+        gnumake
+        gnupatch
+        gnused
+        gnugrep
+        gnutar
+        gzip
+        gawk
+        binutils
+      ];
+
+      meta = with lib; {
+        description = "The GNU C Library";
+        homepage = "https://www.gnu.org/software/libc";
+        license = licenses.lgpl2Plus;
+        maintainers = teams.minimal-bootstrap.members;
+        platforms = platforms.linux;
+      };
+    } ''
+      # Unpack
+      tar xzf ${src}
+      cd glibc-${version}
+
+      # Patch
+      ${lib.concatMapStringsSep "\n" (f: "patch -Np1 -i ${f}") patches}
+
+      # Configure
+      export CC="${CC}"
+      export CPP="${CPP}"
+      bash ./configure --prefix=$out ${lib.concatStringsSep " " (
+        [
+          "--build=${buildPlatform.config}"
+          "--host=${hostPlatform.config}"
+          "--with-headers=${linux-headers}/include"
+          "--enable-static"
+          "--disable-shared"
+        ] ++ configureFlags)}
+
+      # Build
+      make
+
+      # Install
+      # GNU sed w/ mes-libc crashes on certain stdio actions
+      export PATH="${heirloom.sed}/bin:$PATH"
+      make install
+    '';
+in
+{
+  glibc22 = buildGlibc rec {
+    # GNU C Library 2.2.5 is the most recent glibc that we managed to build
+    # using gcc-2.95.3.  Newer versions (2.3.x, 2.6, 2.1x) seem to need a newer
+    # gcc.
+    #   - from guix/gnu/packages/commencement.scm
+    version = "2.2.5";
+    src = fetchurl {
+      url = "mirror://gnu/glibc/glibc-${version}.tar.gz";
+      sha256 = "1vl48i16gx6h68whjyhgnn1s57vqq32f9ygfa2fls7pdkbsqvp2q";
+    };
+
+    patches = [
+      # This patch enables building glibc-2.2.5 using TCC and GNU Make 4.x and Mes C Library.
+      #   * Makefile: Do not assemble from stdin, use file indirection.
+      #   * Makefile: Add new target: install-lib-all.
+      #   * Makefile: Avoid building stub DOC.
+      #   * [_LIBC_REENTRANT]: Add missing guarding.
+      #   * [MES_BOOTSTRAP]: Disable some GCC extensions.
+      #   * [MES_BOOTSTRAP]: Add missing GCC div/mod defines.
+      (fetchurl {
+        url = "https://git.savannah.gnu.org/cgit/guix.git/plain/gnu/packages/patches/glibc-boot-${version}.patch?id=50249cab3a98839ade2433456fe618acc6f804a5";
+        sha256 = "1nyz2dr9g7scqwwygd6jvbl7xxpwh11ryvgdz8aikkkna02q1pm8";
+      })
+      # We want to allow builds in chroots that lack /bin/sh.  Thus, system(3)
+      # and popen(3) need to be tweaked to use the right shell.  For the bootstrap
+      # glibc, we just use whatever `sh' can be found in $PATH.  The final glibc
+      # instead uses the hard-coded absolute file name of `bash'.
+      (fetchurl {
+        url = "https://git.savannah.gnu.org/cgit/guix.git/plain/gnu/packages/patches/glibc-bootstrap-system-${version}.patch?id=50249cab3a98839ade2433456fe618acc6f804a5";
+        sha256 = "1l67w9rysrlsg2i0r210qxxn37h2969ba9lx7pp3ywlnikvi98m8";
+      })
+    ];
+
+    configureFlags = [
+      "--disable-sanity-checks"
+      "--enable-static-nss"
+      "--without-__thread"
+      "--without-cvs"
+      "--without-gd"
+      "--without-tls"
+    ];
+
+    gcc = gcc2-mes;
+    binutils = binutils-mes;
+    CC = "gcc -D MES_BOOTSTRAP=1 -D BOOTSTRAP_GLIBC=1 -L $(pwd)";
+    CPP = "gcc -E -D MES_BOOTSTRAP=1 -D BOOTSTRAP_GLIBC=1";
+  };
+}
diff --git a/pkgs/os-specific/linux/minimal-bootstrap/linux-headers/default.nix b/pkgs/os-specific/linux/minimal-bootstrap/linux-headers/default.nix
new file mode 100644
index 000000000000..6addd11554d0
--- /dev/null
+++ b/pkgs/os-specific/linux/minimal-bootstrap/linux-headers/default.nix
@@ -0,0 +1,49 @@
+{ lib
+, fetchurl
+, bash
+, gnutar
+, xz
+}:
+let
+  # WARNING: You probably don't want to use this package outside minimal-bootstrap
+  #
+  # We need some set of Linux kernel headers to build our bootstrap packages
+  # (gcc/binutils/glibc etc.) against. As long as it compiles it is "good enough".
+  # Therefore the requirement for correctness, completeness, platform-specific
+  # features, and being up-to-date, are very loose.
+  #
+  # Rebuilding the Linux headers from source correctly is something we can defer
+  # till we have access to gcc/binutils/perl. For now we can use Guix's assembled
+  # kernel header distribution and assume it's good enough.
+  pname = "linux-headers";
+  version = "4.14.67";
+
+  src = fetchurl {
+    url = "mirror://gnu/gnu/guix/bootstrap/i686-linux/20190815/linux-libre-headers-stripped-4.14.67-i686-linux.tar.xz";
+    sha256 = "0sm2z9x4wk45bh6qfs94p0w1d6hsy6dqx9sw38qsqbvxwa1qzk8s";
+  };
+in
+bash.runCommand "${pname}-${version}" {
+  inherit pname version;
+
+  nativeBuildInputs = [
+    gnutar
+    xz
+  ];
+
+  meta = with lib; {
+    description = "Header files and scripts for Linux kernel";
+    license = licenses.gpl2;
+    maintainers = teams.minimal-bootstrap.members;
+    platforms = platforms.linux;
+  };
+} ''
+  # Unpack
+  cp ${src} linux-headers.tar.xz
+  unxz linux-headers.tar.xz
+  tar xf linux-headers.tar
+
+  # Install
+  mkdir $out
+  cp -r include $out
+''
diff --git a/pkgs/os-specific/linux/minimal-bootstrap/stage0-posix/bootstrap-sources.nix b/pkgs/os-specific/linux/minimal-bootstrap/stage0-posix/bootstrap-sources.nix
index f06db98a8efe..65b052c44569 100644
--- a/pkgs/os-specific/linux/minimal-bootstrap/stage0-posix/bootstrap-sources.nix
+++ b/pkgs/os-specific/linux/minimal-bootstrap/stage0-posix/bootstrap-sources.nix
@@ -1,13 +1,14 @@
+{
+}:
+
 rec {
   name = "stage0-posix-${version}-${rev}-source";
   # Pinned from https://github.com/oriansj/stage0-posix/commit/3189b5f325b7ef8b88e3edec7c1cde4fce73c76c
   version = "unstable-2023-05-02";
   rev = "3189b5f325b7ef8b88e3edec7c1cde4fce73c76c";
+  outputHashAlgo = "sha256";
 
   # This 256 byte seed is the only pre-compiled binary in the bootstrap chain.
-  # While it is included in the stage0-posix source bundle and is synced with
-  # stage0-posix updates, we have split it out into its own derivation to highlight
-  # its unique status as a trusted binary seed.
   hex0-seed = import <nix/fetchurl.nix> {
     name = "hex0-seed-${version}";
     url = "https://github.com/oriansj/bootstrap-seeds/raw/b1263ff14a17835f4d12539226208c426ced4fba/POSIX/x86/hex0-seed";
@@ -15,20 +16,91 @@ rec {
     executable = true;
   };
 
-  # Packaged resources required for the first bootstrapping stage.
-  # Contains source code and 256-byte hex0 binary seed.
-  #
-  # We don't have access to utilities such as fetchgit and fetchzip since this
-  # is this is part of the bootstrap process and would introduce a circular
-  # dependency. The only tool we have to fetch source trees is `import <nix/fetchurl.nix>`
-  # with the unpack option, taking a NAR file as input. This requires source
-  # tarballs to be repackaged.
-  #
-  # To build see `make-bootstrap-sources.nix`
-  src = import <nix/fetchurl.nix> {
-    inherit name;
-    url = "https://github.com/emilytrau/bootstrap-tools-nar-mirror/releases/download/2023-05-02/${name}.nar.xz";
-    hash = "sha256-ZRG0k49MxL1UTZhuMTvPoEprdSpJRNVy8QhLE6k+etg=";
-    unpack = true;
+  /*
+  Since `make-minimal-bootstrap-sources` requires nixpkgs and nix it
+  will create a circular dependency if it is used in place of the
+  binary bootstrap-files.  To break the circular dependency,
+  `minimal-bootstrap-sources` extends `make-minimal-bootstrap-sources`
+  by adding Fixed Output Derivation (FOD) attributes.  These cause
+  the builder to be skipped if the expected output is found (by
+  its hash) in the store or on a substituter.
+
+  # How do I update the hash?
+
+  Run the following command:
+  ```
+  nix hash file $(nix build --print-out-paths -f '<nixpkgs>' make-minimal-bootstrap-sources)
+  ```
+
+  # Why do we need this `.nar` archive?
+
+  This archive exists only because of a quirk/limitation of Nix: in
+  restricted mode the builtin fetchers can download only single
+  files; they have no way to unpack multi-file archives except for
+  NAR archives:
+
+  https://github.com/NixOS/nixpkgs/pull/232576#issuecomment-1592415619
+
+  # Why don't we have to upload this to tarballs.nixos.org like the binary bootstrap-files did?
+
+  Unlike this archive, the binary bootstrap-files contained binaries,
+  which meant that we had to:
+
+  1. Make sure they came from a trusted builder (Hydra)
+  2. Keep careful track of exactly what toolchain (i.e. nixpkgs
+     commit) that builder used to create them.
+  3. Keep copies of the built binaries, in case the toolchains that
+     produced them failed to be perfectly deterministic.
+
+  The curated archives at tarballs.nixos.org exist in order to
+  satisfy these requirements.
+
+  The second point created a significant burden: since the nixpkgs
+  toolchain used to build a given copy of the binary bootstrap-files
+  itself used a *previous* copy of the bootstrap-files, this meant
+  we had to track the provenance of all bootstrap-files tarballs
+  ever used, for all eternity.  There was no explanation of where
+  the "original" bootstrap-files came from: turtles all the way
+  down.  In spite of all this effort we still can't be sure of our
+  ability to reproduce the binary bootstrap-files, since the
+  compilers that built them don't always produce exactly bit-for-bit
+  deterministic results.
+
+  Since this archive contains no binaries and uses a format (NAR)
+  specifically designed for bit-exact reproducibility, none of the
+  requirements above apply to `minimal-bootstrap-sources`.
+  */
+  minimal-bootstrap-sources = derivation {
+    name = "${name}.nar.xz";
+    system = builtins.currentSystem;
+    outputHashMode = "flat";
+    inherit outputHashAlgo;
+    outputHash = "sha256-ig988BiRTz92hhZZgKQW1tVPoV4aQ2D69Cq3wHvVgHg=";
+
+    # This builder always fails, but fortunately Nix will print the
+    # "builder", which is really the error message that we want the
+    # user to see.
+    builder = ''
+      #
+      #
+      # Neither your store nor your substituters seems to have:
+      #
+      #  ${name}.nar.xz
+      #
+      # Please obtain or create this file, give it exactly the name
+      # shown above, and then run the following command:
+      #
+      #   nix-store --add-fixed ${outputHashAlgo} ${name}.nar.xz
+      #
+      # You can create this file from an already-bootstrapped nixpkgs
+      # using the following command:
+      #
+      #   nix-build '<nixpkgs>' -A make-minimal-bootstrap-sources
+      #
+      # Or, if you prefer, you can create this file using only `git`,
+      # `nix`, and `xz`.  For the commands needed in order to do this,
+      # see `make-bootstrap-sources.nix`.
+      #
+    '';
   };
 }
diff --git a/pkgs/os-specific/linux/minimal-bootstrap/stage0-posix/default.nix b/pkgs/os-specific/linux/minimal-bootstrap/stage0-posix/default.nix
index 2b41261add3a..c15223a43d48 100644
--- a/pkgs/os-specific/linux/minimal-bootstrap/stage0-posix/default.nix
+++ b/pkgs/os-specific/linux/minimal-bootstrap/stage0-posix/default.nix
@@ -3,7 +3,10 @@
 }:
 
 lib.makeScope newScope (self: with self; {
-  inherit (import ./bootstrap-sources.nix) version hex0-seed src;
+  inherit (self.callPackage ./bootstrap-sources.nix {})
+    version hex0-seed minimal-bootstrap-sources;
+
+  src = minimal-bootstrap-sources;
 
   m2libc = src + "/M2libc";
 
diff --git a/pkgs/os-specific/linux/minimal-bootstrap/stage0-posix/hex0.nix b/pkgs/os-specific/linux/minimal-bootstrap/stage0-posix/hex0.nix
index 43859b966add..b85b2f2cac14 100644
--- a/pkgs/os-specific/linux/minimal-bootstrap/stage0-posix/hex0.nix
+++ b/pkgs/os-specific/linux/minimal-bootstrap/stage0-posix/hex0.nix
@@ -9,7 +9,7 @@ derivationWithMeta {
   pname = "hex0";
   builder = hex0-seed;
   args = [
-    "${src}/bootstrap-seeds/POSIX/x86/hex0_x86.hex0"
+    "${src}/x86/hex0_x86.hex0"
     (placeholder "out")
   ];
 
diff --git a/pkgs/os-specific/linux/minimal-bootstrap/stage0-posix/kaem/minimal.nix b/pkgs/os-specific/linux/minimal-bootstrap/stage0-posix/kaem/minimal.nix
index e85efbbb0243..24fc77f8d345 100644
--- a/pkgs/os-specific/linux/minimal-bootstrap/stage0-posix/kaem/minimal.nix
+++ b/pkgs/os-specific/linux/minimal-bootstrap/stage0-posix/kaem/minimal.nix
@@ -9,7 +9,7 @@ derivationWithMeta {
   pname = "kaem-minimal";
   builder = hex0;
   args = [
-    "${src}/bootstrap-seeds/POSIX/x86/kaem-minimal.hex0"
+    "${src}/x86/kaem-minimal.hex0"
     (placeholder "out")
   ];
 
diff --git a/pkgs/os-specific/linux/minimal-bootstrap/stage0-posix/make-bootstrap-sources.nix b/pkgs/os-specific/linux/minimal-bootstrap/stage0-posix/make-bootstrap-sources.nix
index fec03f370bc3..8951cc9ddbc4 100644
--- a/pkgs/os-specific/linux/minimal-bootstrap/stage0-posix/make-bootstrap-sources.nix
+++ b/pkgs/os-specific/linux/minimal-bootstrap/stage0-posix/make-bootstrap-sources.nix
@@ -1,5 +1,4 @@
-# Packaged resources required for the first bootstrapping stage.
-# Contains source code and 256-byte hex0 binary seed.
+# Packaged source files for the first bootstrapping stage.
 #
 # We don't have access to utilities such as fetchgit and fetchzip since this
 # is this is part of the bootstrap process and would introduce a circular
@@ -9,23 +8,29 @@
 #
 # To build:
 #
-#   nix-build pkgs/os-specific/linux/minimal-bootstrap/stage0-posix/make-bootstrap-sources.nix
-#   => ./result/stage0-posix-$version-$rev-source.nar.xz
+#   nix-build '<nixpkgs>' -o sources.nar.xz -A make-minimal-bootstrap-sources
 #
 
-{ pkgs ? import ../../../../.. {} }:
+{ lib
+, fetchFromGitHub
+, runCommand
+, nix
+, xz
+}:
 let
-  inherit (pkgs) callPackage runCommand fetchFromGitHub nix xz;
-
-  inherit (import ./bootstrap-sources.nix) name rev;
+  inherit (import ./bootstrap-sources.nix { }) name rev;
 
   src = fetchFromGitHub {
     owner = "oriansj";
     repo = "stage0-posix";
     inherit rev;
-    sha256 = "sha256-ZRG0k49MxL1UTZhuMTvPoEprdSpJRNVy8QhLE6k+etg=";
+    sha256 = "sha256-FpMp7z+B3cR3LkQ+PooH/b1/NlxH8NHVJNWifaPWt4U=";
     fetchSubmodules = true;
     postFetch = ''
+      # Seed binaries will be fetched separately
+      echo "Removing seed binaries"
+      rm -rf $out/bootstrap-seeds/*
+
       # Remove vendored/duplicate M2libc's
       echo "Removing duplicate M2libc"
       rm -rf \
@@ -35,12 +40,20 @@ let
         $out/mescc-tools-extra/M2libc
     '';
   };
+
 in
-runCommand name {
+runCommand "${name}.nar.xz" {
   nativeBuildInputs = [ nix xz ];
 
   passthru = { inherit src; };
+
+  meta = with lib; {
+    description = "Packaged sources for the first bootstrapping stage";
+    homepage = "https://github.com/oriansj/stage0-posix";
+    license = licenses.gpl3Plus;
+    maintainers = teams.minimal-bootstrap.members;
+    platforms = platforms.all;
+  };
 } ''
-  mkdir $out
-  nix-store --dump ${src} | xz -c > "$out/${name}.nar.xz"
+  nix-store --dump ${src} | xz -c > $out
 ''
diff --git a/pkgs/os-specific/linux/minimal-bootstrap/utils.nix b/pkgs/os-specific/linux/minimal-bootstrap/utils.nix
index bba6edae973a..cc8c04619169 100644
--- a/pkgs/os-specific/linux/minimal-bootstrap/utils.nix
+++ b/pkgs/os-specific/linux/minimal-bootstrap/utils.nix
@@ -29,11 +29,9 @@ rec {
     , text
     , executable ? false # run chmod +x ?
     , destination ? ""   # relative path appended to $out eg "/bin/foo"
-    , allowSubstitutes ? false
-    , preferLocalBuild ? true
     }:
     derivationWithMeta {
-      inherit name text allowSubstitutes preferLocalBuild;
+      inherit name text;
       passAsFile = [ "text" ];
 
       builder = "${kaem}/bin/kaem";