From 64985d60585bfa873c3529ea58b3734affd517ce Mon Sep 17 00:00:00 2001 From: Jake Hamilton Date: Fri, 7 Jun 2024 20:53:54 -0700 Subject: [PATCH] feat: bison, gnum4, linux-headers, zlib, python, busybox, glibc, patchelf --- foundation/flake.lock | 2 +- .../src/stages/stage1/bison/default.nix | 105 +++++++++++++++ foundation/src/stages/stage1/default.nix | 10 ++ .../src/stages/stage1/gnum4/default.nix | 104 +++++++++++++++ .../stages/stage1/linux-headers/default.nix | 93 ++++++++++++++ .../src/stages/stage1/python/default.nix | 121 ++++++++++++++++++ .../stage1/python/patches/no-ldconfig.patch | 108 ++++++++++++++++ foundation/src/stages/stage1/zlib/default.nix | 98 ++++++++++++++ .../src/stages/stage2/busybox/default.nix | 121 ++++++++++++++++++ .../busybox/patches/busybox-in-store.patch | 24 ++++ foundation/src/stages/stage2/default.nix | 6 + foundation/src/stages/stage2/gcc/default.nix | 3 +- .../src/stages/stage2/glibc/default.nix | 111 ++++++++++++++++ .../src/stages/stage2/patchelf/default.nix | 107 ++++++++++++++++ lib/src/versions/default.nix | 24 ++++ 15 files changed, 1035 insertions(+), 2 deletions(-) create mode 100644 foundation/src/stages/stage1/bison/default.nix create mode 100644 foundation/src/stages/stage1/gnum4/default.nix create mode 100644 foundation/src/stages/stage1/linux-headers/default.nix create mode 100644 foundation/src/stages/stage1/python/default.nix create mode 100644 foundation/src/stages/stage1/python/patches/no-ldconfig.patch create mode 100644 foundation/src/stages/stage1/zlib/default.nix create mode 100644 foundation/src/stages/stage2/busybox/default.nix create mode 100644 foundation/src/stages/stage2/busybox/patches/busybox-in-store.patch create mode 100644 foundation/src/stages/stage2/glibc/default.nix create mode 100644 foundation/src/stages/stage2/patchelf/default.nix diff --git a/foundation/flake.lock b/foundation/flake.lock index 04cc7e5..215017c 100644 --- a/foundation/flake.lock +++ b/foundation/flake.lock @@ -3,7 +3,7 @@ "lib": { "locked": { "lastModified": 1, - "narHash": "sha256-gJODnE6vuEI+ifNgmXywIpma4/uVfRayYknVQjDJN2c=", + "narHash": "sha256-TjsTWJP2N/G0o5ca4v6ooGYHMydtvKf52xnHn4DzZTQ=", "path": "../lib", "type": "path" }, diff --git a/foundation/src/stages/stage1/bison/default.nix b/foundation/src/stages/stage1/bison/default.nix new file mode 100644 index 0000000..0614262 --- /dev/null +++ b/foundation/src/stages/stage1/bison/default.nix @@ -0,0 +1,105 @@ +{ + lib, + config, +}: let + cfg = config.aux.foundation.stages.stage1.bison; + + platform = config.aux.platform; + builders = config.aux.foundation.builders; + + stage1 = config.aux.foundation.stages.stage1; +in { + options.aux.foundation.stages.stage1.bison = { + package = lib.options.create { + type = lib.types.package; + description = "The package to use for bison."; + }; + + version = lib.options.create { + type = lib.types.string; + description = "Version of the package."; + }; + + src = lib.options.create { + type = lib.types.package; + description = "Source for the package."; + }; + + meta = { + description = lib.options.create { + type = lib.types.string; + description = "Description for the package."; + default.value = "Yacc-compatible parser generator."; + }; + + homepage = lib.options.create { + type = lib.types.string; + description = "Homepage for the package."; + default.value = "https://www.gnu.org/software/bison"; + }; + + license = lib.options.create { + # TODO: Add a proper type for licenses. + type = lib.types.attrs.any; + description = "License for the package."; + default.value = lib.licenses.gpl3Plus; + }; + + platforms = lib.options.create { + type = lib.types.list.of lib.types.string; + description = "Platforms the package supports."; + default.value = ["i686-linux"]; + }; + }; + }; + + config = { + aux.foundation.stages.stage1.bison = { + version = "3.8.2"; + + src = builtins.fetchurl { + url = "https://ftpmirror.gnu.org/bison/bison-${cfg.version}.tar.xz"; + sha256 = "m7oCFMz38QecXVkhAEUie89hlRmEDr+oDNOEnP9aW/I="; + }; + + package = builders.bash.build { + name = "bison-${cfg.version}"; + meta = cfg.meta; + + deps.build.host = [ + stage1.gcc.package + stage1.musl.package + stage1.binutils.package + stage1.gnumake.package + stage1.gnused.package + stage1.gnugrep.package + stage1.gawk.package + stage1.diffutils.package + stage1.findutils.package + stage1.gnutar.package + stage1.xz.package + stage1.gnum4.package + ]; + + script = '' + # Unpack + tar xf ${cfg.src} + cd bison-${cfg.version} + + # Configure + bash ./configure \ + --prefix=$out \ + --build=${platform.build} \ + --host=${platform.host} \ + CC=musl-gcc + + # Build + make -j $NIX_BUILD_CORES + + # Install + make -j $NIX_BUILD_CORES install + ''; + }; + }; + }; +} diff --git a/foundation/src/stages/stage1/default.nix b/foundation/src/stages/stage1/default.nix index 4301f62..46f651d 100644 --- a/foundation/src/stages/stage1/default.nix +++ b/foundation/src/stages/stage1/default.nix @@ -28,6 +28,11 @@ in { ./findutils ./bzip2 ./gcc + ./gnum4 + ./bison + ./linux-headers + ./zlib + ./python ]; config = { @@ -76,6 +81,11 @@ in { stage1-gnutar = stage1.gnutar.package; stage1-gcc-8 = stage1.gcc.v8.package; stage1-gcc = stage1.gcc.package; + stage1-gnum4 = stage1.gnum4.package; + stage1-bison = stage1.bison.package; + stage1-linux-headers = stage1.linux-headers.package; + stage1-zlib = stage1.zlib.package; + stage1-python = stage1.python.package; }; extras = { diff --git a/foundation/src/stages/stage1/gnum4/default.nix b/foundation/src/stages/stage1/gnum4/default.nix new file mode 100644 index 0000000..61e631a --- /dev/null +++ b/foundation/src/stages/stage1/gnum4/default.nix @@ -0,0 +1,104 @@ +{ + lib, + config, +}: let + cfg = config.aux.foundation.stages.stage1.gnum4; + + platform = config.aux.platform; + builders = config.aux.foundation.builders; + + stage1 = config.aux.foundation.stages.stage1; +in { + options.aux.foundation.stages.stage1.gnum4 = { + package = lib.options.create { + type = lib.types.package; + description = "The package to use for gnum4."; + }; + + version = lib.options.create { + type = lib.types.string; + description = "Version of the package."; + }; + + src = lib.options.create { + type = lib.types.package; + description = "Source for the package."; + }; + + meta = { + description = lib.options.create { + type = lib.types.string; + description = "Description for the package."; + default.value = "GNU M4, a macro processor."; + }; + + homepage = lib.options.create { + type = lib.types.string; + description = "Homepage for the package."; + default.value = "https://www.gnu.org/software/m4"; + }; + + license = lib.options.create { + # TODO: Add a proper type for licenses. + type = lib.types.attrs.any; + description = "License for the package."; + default.value = lib.licenses.gpl3Plus; + }; + + platforms = lib.options.create { + type = lib.types.list.of lib.types.string; + description = "Platforms the package supports."; + default.value = ["i686-linux"]; + }; + }; + }; + + config = { + aux.foundation.stages.stage1.gnum4 = { + version = "1.4.19"; + + src = builtins.fetchurl { + url = "https://ftpmirror.gnu.org/m4/m4-${cfg.version}.tar.xz"; + sha256 = "Y67eXG0zttmxNRHNC+LKwEby5w/QoHqpVzoEqCeDr5Y="; + }; + + package = builders.bash.build { + name = "gnum4-${cfg.version}"; + meta = cfg.meta; + + deps.build.host = [ + stage1.gcc.package + stage1.musl.package + stage1.binutils.package + stage1.gnumake.package + stage1.gnused.package + stage1.gnugrep.package + stage1.gawk.package + stage1.diffutils.package + stage1.findutils.package + stage1.gnutar.package + stage1.xz.package + ]; + + script = '' + # Unpack + tar xf ${cfg.src} + cd m4-${cfg.version} + + # Configure + bash ./configure \ + --prefix=$out \ + --build=${platform.build} \ + --host=${platform.host} \ + CC=musl-gcc + + # Build + make -j $NIX_BUILD_CORES + + # Install + make -j $NIX_BUILD_CORES install + ''; + }; + }; + }; +} diff --git a/foundation/src/stages/stage1/linux-headers/default.nix b/foundation/src/stages/stage1/linux-headers/default.nix new file mode 100644 index 0000000..e6c692f --- /dev/null +++ b/foundation/src/stages/stage1/linux-headers/default.nix @@ -0,0 +1,93 @@ +{ + lib, + config, +}: let + cfg = config.aux.foundation.stages.stage1.linux-headers; + + platform = config.aux.platform; + builders = config.aux.foundation.builders; + + stage1 = config.aux.foundation.stages.stage1; +in { + options.aux.foundation.stages.stage1.linux-headers = { + package = lib.options.create { + type = lib.types.package; + description = "The package to use for linux-headers."; + }; + + version = lib.options.create { + type = lib.types.string; + description = "Version of the package."; + }; + + src = lib.options.create { + type = lib.types.package; + description = "Source for the package."; + }; + + meta = { + description = lib.options.create { + type = lib.types.string; + description = "Description for the package."; + default.value = "Header files and scripts for Linux kernel."; + }; + + license = lib.options.create { + # TODO: Add a proper type for licenses. + type = lib.types.attrs.any; + description = "License for the package."; + default.value = lib.licenses.lgpl2Plus; + }; + + platforms = lib.options.create { + type = lib.types.list.of lib.types.string; + description = "Platforms the package supports."; + default.value = ["i686-linux"]; + }; + }; + }; + + config = { + aux.foundation.stages.stage1.linux-headers = { + version = "6.5.6"; + + src = builtins.fetchurl { + url = "https://cdn.kernel.org/pub/linux/kernel/v${lib.versions.major cfg.version}.x/linux-${cfg.version}.tar.xz"; + sha256 = "eONtQhRUcFHCTfIUD0zglCjWxRWtmnGziyjoCUqV0vY="; + }; + + package = builders.bash.build { + name = "linux-headers-${cfg.version}"; + meta = cfg.meta; + + deps.build.host = [ + stage1.gcc.package + stage1.musl.package + stage1.binutils.package + stage1.gnumake.package + stage1.gnused.package + stage1.gnugrep.package + stage1.gawk.package + stage1.diffutils.package + stage1.findutils.package + stage1.gnutar.package + stage1.xz.package + ]; + + script = '' + # Unpack + tar xf ${cfg.src} + cd linux-${cfg.version} + + # Build + make -j $NIX_BUILD_CORES CC=musl-gcc HOSTCC=musl-gcc ARCH=x86 headers + + # Install + find usr/include -name '.*' -exec rm {} + + mkdir -p $out + cp -rv usr/include $out/ + ''; + }; + }; + }; +} diff --git a/foundation/src/stages/stage1/python/default.nix b/foundation/src/stages/stage1/python/default.nix new file mode 100644 index 0000000..567a08e --- /dev/null +++ b/foundation/src/stages/stage1/python/default.nix @@ -0,0 +1,121 @@ +{ + lib, + config, +}: let + cfg = config.aux.foundation.stages.stage1.python; + + platform = config.aux.platform; + builders = config.aux.foundation.builders; + + stage1 = config.aux.foundation.stages.stage1; +in { + options.aux.foundation.stages.stage1.python = { + package = lib.options.create { + type = lib.types.package; + description = "The package to use for python."; + }; + + version = lib.options.create { + type = lib.types.string; + description = "Version of the package."; + }; + + src = lib.options.create { + type = lib.types.package; + description = "Source for the package."; + }; + + meta = { + description = lib.options.create { + type = lib.types.string; + description = "Description for the package."; + default.value = "A high-level dynamically-typed programming language."; + }; + + homepage = lib.options.create { + type = lib.types.string; + description = "Homepage for the package."; + default.value = "https://www.python.org"; + }; + + license = lib.options.create { + # TODO: Add a proper type for licenses. + type = lib.types.attrs.any; + description = "License for the package."; + default.value = lib.licenses.psfl; + }; + + platforms = lib.options.create { + type = lib.types.list.of lib.types.string; + description = "Platforms the package supports."; + default.value = ["i686-linux"]; + }; + }; + }; + + config = { + aux.foundation.stages.stage1.python = { + version = "3.12.0"; + + src = builtins.fetchurl { + url = "https://www.python.org/ftp/python/${cfg.version}/Python-${cfg.version}.tar.xz"; + sha256 = "eVw09E30Wg6blxDIxxwVxnGHFSTNQSyhTe8hLozLFV0="; + }; + + package = let + patches = [ + # Disable the use of ldconfig in ctypes.util.find_library (since + # ldconfig doesn't work on NixOS), and don't use + # ctypes.util.find_library during the loading of the uuid module + # (since it will do a futile invocation of gcc (!) to find + # libuuid, slowing down program startup a lot). + ./patches/no-ldconfig.patch + ]; + in + builders.bash.build { + name = "python-${cfg.version}"; + meta = cfg.meta; + + deps.build.host = [ + stage1.gcc.package + stage1.musl.package + stage1.binutils.package + stage1.gnumake.package + stage1.gnupatch.package + stage1.gnused.package + stage1.gnugrep.package + stage1.gawk.package + stage1.diffutils.package + stage1.findutils.package + stage1.gnutar.package + stage1.xz.package + ]; + + script = '' + # Unpack + tar xf ${cfg.src} + cd Python-${cfg.version} + + # Patch + ${lib.strings.concatMapSep "\n" (file: "patch -Np1 -i ${file}") patches} + + # Configure + export CC=musl-gcc + export C_INCLUDE_PATH="${stage1.zlib.package}/include" + export LIBRARY_PATH="${stage1.zlib.package}/lib" + export LD_LIBRARY_PATH="$LIBRARY_PATH" + bash ./configure \ + --prefix=$out \ + --build=${platform.build} \ + --host=${platform.host} + + # Build + make -j $NIX_BUILD_CORES + + # Install + make -j $NIX_BUILD_CORES install + ''; + }; + }; + }; +} diff --git a/foundation/src/stages/stage1/python/patches/no-ldconfig.patch b/foundation/src/stages/stage1/python/patches/no-ldconfig.patch new file mode 100644 index 0000000..0e050f8 --- /dev/null +++ b/foundation/src/stages/stage1/python/patches/no-ldconfig.patch @@ -0,0 +1,108 @@ +From 5330b6af9f832af59aa5c61d9ef6971053a8e709 Mon Sep 17 00:00:00 2001 +From: Jonathan Ringer +Date: Mon, 9 Nov 2020 10:24:35 -0800 +Subject: [PATCH] CPython: Don't use ldconfig + +--- + Lib/ctypes/util.py | 77 ++-------------------------------------------- + 1 file changed, 2 insertions(+), 75 deletions(-) + +diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py +index 0c2510e161..7fb98af308 100644 +--- a/Lib/ctypes/util.py ++++ b/Lib/ctypes/util.py +@@ -100,53 +100,7 @@ def _is_elf(filename): + return thefile.read(4) == elf_header + + def _findLib_gcc(name): +- # Run GCC's linker with the -t (aka --trace) option and examine the +- # library name it prints out. The GCC command will fail because we +- # haven't supplied a proper program with main(), but that does not +- # matter. +- expr = os.fsencode(r'[^\(\)\s]*lib%s\.[^\(\)\s]*' % re.escape(name)) +- +- c_compiler = shutil.which('gcc') +- if not c_compiler: +- c_compiler = shutil.which('cc') +- if not c_compiler: +- # No C compiler available, give up +- return None +- +- temp = tempfile.NamedTemporaryFile() +- try: +- args = [c_compiler, '-Wl,-t', '-o', temp.name, '-l' + name] +- +- env = dict(os.environ) +- env['LC_ALL'] = 'C' +- env['LANG'] = 'C' +- try: +- proc = subprocess.Popen(args, +- stdout=subprocess.PIPE, +- stderr=subprocess.STDOUT, +- env=env) +- except OSError: # E.g. bad executable +- return None +- with proc: +- trace = proc.stdout.read() +- finally: +- try: +- temp.close() +- except FileNotFoundError: +- # Raised if the file was already removed, which is the normal +- # behaviour of GCC if linking fails +- pass +- res = re.findall(expr, trace) +- if not res: +- return None +- +- for file in res: +- # Check if the given file is an elf file: gcc can report +- # some files that are linker scripts and not actual +- # shared objects. See bpo-41976 for more details +- if not _is_elf(file): +- continue +- return os.fsdecode(file) ++ return None + + + if sys.platform == "sunos5": +@@ -268,34 +222,7 @@ def find_library(name, is64 = False): + else: + + def _findSoname_ldconfig(name): +- import struct +- if struct.calcsize('l') == 4: +- machine = os.uname().machine + '-32' +- else: +- machine = os.uname().machine + '-64' +- mach_map = { +- 'x86_64-64': 'libc6,x86-64', +- 'ppc64-64': 'libc6,64bit', +- 'sparc64-64': 'libc6,64bit', +- 's390x-64': 'libc6,64bit', +- 'ia64-64': 'libc6,IA-64', +- } +- abi_type = mach_map.get(machine, 'libc6') +- +- # XXX assuming GLIBC's ldconfig (with option -p) +- regex = r'\s+(lib%s\.[^\s]+)\s+\(%s' +- regex = os.fsencode(regex % (re.escape(name), abi_type)) +- try: +- with subprocess.Popen(['/sbin/ldconfig', '-p'], +- stdin=subprocess.DEVNULL, +- stderr=subprocess.DEVNULL, +- stdout=subprocess.PIPE, +- env={'LC_ALL': 'C', 'LANG': 'C'}) as p: +- res = re.search(regex, p.stdout.read()) +- if res: +- return os.fsdecode(res.group(1)) +- except OSError: +- pass ++ return None + + def _findLib_ld(name): + # See issue #9998 for why this is needed +-- +2.33.1 + + diff --git a/foundation/src/stages/stage1/zlib/default.nix b/foundation/src/stages/stage1/zlib/default.nix new file mode 100644 index 0000000..948e3d3 --- /dev/null +++ b/foundation/src/stages/stage1/zlib/default.nix @@ -0,0 +1,98 @@ +{ + lib, + config, +}: let + cfg = config.aux.foundation.stages.stage1.zlib; + + platform = config.aux.platform; + builders = config.aux.foundation.builders; + + stage1 = config.aux.foundation.stages.stage1; +in { + options.aux.foundation.stages.stage1.zlib = { + package = lib.options.create { + type = lib.types.package; + description = "The package to use for zlib."; + }; + + version = lib.options.create { + type = lib.types.string; + description = "Version of the package."; + }; + + src = lib.options.create { + type = lib.types.package; + description = "Source for the package."; + }; + + meta = { + description = lib.options.create { + type = lib.types.string; + description = "Description for the package."; + default.value = "Lossless data-compression library."; + }; + + homepage = lib.options.create { + type = lib.types.string; + description = "Homepage for the package."; + default.value = "https://zlib.net"; + }; + + license = lib.options.create { + # TODO: Add a proper type for licenses. + type = lib.types.attrs.any; + description = "License for the package."; + default.value = lib.licenses.zlib; + }; + + platforms = lib.options.create { + type = lib.types.list.of lib.types.string; + description = "Platforms the package supports."; + default.value = ["i686-linux"]; + }; + }; + }; + + config = { + aux.foundation.stages.stage1.zlib = { + version = "1.3"; + + src = builtins.fetchurl { + url = "https://github.com/madler/zlib/releases/download/v${cfg.version}/zlib-${cfg.version}.tar.xz"; + sha256 = "ipuiiY4dDXdOymultGJ6EeVYi6hciFEzbrON5GgwUKc="; + }; + + package = builders.bash.build { + name = "zlib-${cfg.version}"; + meta = cfg.meta; + + deps.build.host = [ + stage1.gcc.package + stage1.musl.package + stage1.binutils.package + stage1.gnumake.package + stage1.gnused.package + stage1.gnugrep.package + stage1.gnutar.package + stage1.xz.package + ]; + + script = '' + # Unpack + tar xf ${cfg.src} + cd zlib-${cfg.version} + + # Configure + export CC=musl-gcc + bash ./configure --prefix=$out + + # Build + make -j $NIX_BUILD_CORES + + # Install + make -j $NIX_BUILD_CORES install + ''; + }; + }; + }; +} diff --git a/foundation/src/stages/stage2/busybox/default.nix b/foundation/src/stages/stage2/busybox/default.nix new file mode 100644 index 0000000..bb5364e --- /dev/null +++ b/foundation/src/stages/stage2/busybox/default.nix @@ -0,0 +1,121 @@ +{ + lib, + config, +}: let + cfg = config.aux.foundation.stages.stage2.busybox; + + platform = config.aux.platform; + builders = config.aux.foundation.builders; + + stage1 = config.aux.foundation.stages.stage1; + stage2 = config.aux.foundation.stages.stage2; +in { + options.aux.foundation.stages.stage2.busybox = { + package = lib.options.create { + type = lib.types.package; + description = "The package to use for busybox."; + }; + + version = lib.options.create { + type = lib.types.string; + description = "Version of the package."; + }; + + src = lib.options.create { + type = lib.types.package; + description = "Source for the package."; + }; + + meta = { + description = lib.options.create { + type = lib.types.string; + description = "Description for the package."; + default.value = "Tiny versions of common UNIX utilities in a single small executable."; + }; + + homepage = lib.options.create { + type = lib.types.string; + description = "Homepage for the package."; + default.value = "https://busybox.net/"; + }; + + license = lib.options.create { + # TODO: Add a proper type for licenses. + type = lib.types.attrs.any; + description = "License for the package."; + default.value = lib.licenses.gpl2Only; + }; + + platforms = lib.options.create { + type = lib.types.list.of lib.types.string; + description = "Platforms the package supports."; + default.value = ["i686-linux"]; + }; + }; + }; + + config = { + aux.foundation.stages.stage2.busybox = { + version = "1.36.1"; + + src = builtins.fetchurl { + url = "https://busybox.net/downloads/busybox-${cfg.version}.tar.bz2"; + sha256 = "uMwkyVdNgJ5yecO+NJeVxdXOtv3xnKcJ+AzeUOR94xQ="; + }; + + package = let + patches = [ + ./patches/busybox-in-store.patch + ]; + + busyboxConfig = [ + "CC=musl-gcc" + "HOSTCC=musl-gcc" + "CFLAGS=-I${stage1.linux-headers.package}/include" + "KCONFIG_NOTIMESTAMP=y" + "CONFIG_PREFIX=${builtins.placeholder "out"}" + "CONFIG_STATIC=y" + ]; + in + builders.bash.build { + name = "busybox-static-${cfg.version}"; + meta = cfg.meta; + + deps.build.host = [ + stage1.gcc.package + stage1.musl.package + stage1.binutils.package + stage1.gnumake.package + stage1.gnupatch.package + stage1.gnused.package + stage2.gnugrep.package + stage2.gawk.package + stage1.diffutils.package + stage1.findutils.package + stage1.gnutar.package + stage1.bzip2.package + ]; + + script = '' + # Unpack + tar xf ${cfg.src} + cd busybox-${cfg.version} + + # Patch + ${lib.strings.concatMapSep "\n" (file: "patch -Np1 -i ${file}") patches} + + # Configure + BUSYBOX_FLAGS="${builtins.concatStringsSep " " busyboxConfig}" + make -j $NIX_BUILD_CORES $BUSYBOX_FLAGS defconfig + + # Build + make -j $NIX_BUILD_CORES $BUSYBOX_FLAGS + + # Install + cp busybox $out + + ''; + }; + }; + }; +} diff --git a/foundation/src/stages/stage2/busybox/patches/busybox-in-store.patch b/foundation/src/stages/stage2/busybox/patches/busybox-in-store.patch new file mode 100644 index 0000000..0e90576 --- /dev/null +++ b/foundation/src/stages/stage2/busybox/patches/busybox-in-store.patch @@ -0,0 +1,24 @@ +Allow BusyBox to be invoked as "-busybox". This is +necessary when it's run from the Nix store as -busybox during +stdenv bootstrap. +--- a/libbb/appletlib.c ++++ b/libbb/appletlib.c +@@ -947,7 +947,7 @@ void FAST_FUNC run_applet_no_and_exit(int applet_no, const char *name, char **ar + static NORETURN void run_applet_and_exit(const char *name, char **argv) + { + # if ENABLE_BUSYBOX +- if (is_prefixed_with(name, "busybox")) ++ if (strstr(name, "busybox") != 0) + exit(busybox_main(/*unused:*/ 0, argv)); + # endif + # if NUM_APPLETS > 0 +@@ -1045,7 +1045,7 @@ int main(int argc UNUSED_PARAM, char **argv) + + lbb_prepare("busybox" IF_FEATURE_INDIVIDUAL(, argv)); + # if !ENABLE_BUSYBOX +- if (argv[1] && is_prefixed_with(bb_basename(argv[0]), "busybox")) ++ if (argv[1] && strstr(bb_basename(argv[0]), "busybox") != 0) + argv++; + # endif + applet_name = argv[0]; + diff --git a/foundation/src/stages/stage2/default.nix b/foundation/src/stages/stage2/default.nix index 51c44e4..05f9368 100644 --- a/foundation/src/stages/stage2/default.nix +++ b/foundation/src/stages/stage2/default.nix @@ -19,6 +19,9 @@ in { ./gnused ./gnutar ./gzip + ./glibc + ./patchelf + ./busybox ]; config = { @@ -38,6 +41,9 @@ in { stage2-gnused = stage2.gnused.package; stage2-gnutar = stage2.gnutar.package; stage2-gzip = stage2.gzip.package; + stage2-glibc = stage2.glibc.package; + stage2-patchelf = stage2.patchelf.package; + stage2-busybox = stage2.busybox.package; }; }; }; diff --git a/foundation/src/stages/stage2/gcc/default.nix b/foundation/src/stages/stage2/gcc/default.nix index 51e8a5b..3680ace 100644 --- a/foundation/src/stages/stage2/gcc/default.nix +++ b/foundation/src/stages/stage2/gcc/default.nix @@ -204,7 +204,8 @@ in { --disable-lto \ --disable-multilib \ --disable-plugin \ - CFLAGS=-static + CFLAGS=-static \ + CXXFLAGS=-static # Build make -j $NIX_BUILD_CORES diff --git a/foundation/src/stages/stage2/glibc/default.nix b/foundation/src/stages/stage2/glibc/default.nix new file mode 100644 index 0000000..e73208c --- /dev/null +++ b/foundation/src/stages/stage2/glibc/default.nix @@ -0,0 +1,111 @@ +{ + lib, + config, +}: let + cfg = config.aux.foundation.stages.stage2.glibc; + + platform = config.aux.platform; + builders = config.aux.foundation.builders; + + stage1 = config.aux.foundation.stages.stage1; + stage2 = config.aux.foundation.stages.stage2; +in { + options.aux.foundation.stages.stage2.glibc = { + package = lib.options.create { + type = lib.types.package; + description = "The package to use for glibc."; + }; + + version = lib.options.create { + type = lib.types.string; + description = "Version of the package."; + }; + + src = lib.options.create { + type = lib.types.package; + description = "Source for the package."; + }; + + meta = { + description = lib.options.create { + type = lib.types.string; + description = "Description for the package."; + default.value = "The GNU C Library."; + }; + + homepage = lib.options.create { + type = lib.types.string; + description = "Homepage for the package."; + default.value = "https://www.gnu.org/software/libc"; + }; + + license = lib.options.create { + # TODO: Add a proper type for licenses. + type = lib.types.attrs.any; + description = "License for the package."; + default.value = lib.licenses.lgpl2Plus; + }; + + platforms = lib.options.create { + type = lib.types.list.of lib.types.string; + description = "Platforms the package supports."; + default.value = ["i686-linux"]; + }; + }; + }; + + config = { + aux.foundation.stages.stage2.glibc = { + version = "2.38"; + + src = builtins.fetchurl { + url = "https://ftpmirror.gnu.org/libc/glibc-${cfg.version}.tar.xz"; + sha256 = "+4KZiZiyspllRnvBtp0VLpwwfSzzAcnq+0VVt3DvP9I="; + }; + + package = builders.bash.build { + name = "glibc-${cfg.version}"; + meta = cfg.meta; + + deps.build.host = [ + stage1.gcc.package + stage1.binutils.package + stage1.gnumake.package + stage1.gnused.package + stage2.gnugrep.package + stage2.gawk.package + stage1.diffutils.package + stage1.findutils.package + stage1.python.package + stage1.bison.package + stage1.gnutar.package + stage1.xz.package + ]; + + script = '' + # Unpack + tar xf ${cfg.src} + cd glibc-${cfg.version} + + # Configure + mkdir build + cd build + # libstdc++.so is built against musl and fails to link + export CXX=false + bash ../configure \ + --prefix=$out \ + --build=${platform.build} \ + --host=${platform.host} \ + --with-headers=${stage1.linux-headers.package}/include + + # Build + make -j $NIX_BUILD_CORES + + # Install + make -j $NIX_BUILD_CORES INSTALL_UNCOMPRESSED=yes install + find $out/{bin,sbin,lib,libexec} -type f -exec strip --strip-unneeded {} + || true + ''; + }; + }; + }; +} diff --git a/foundation/src/stages/stage2/patchelf/default.nix b/foundation/src/stages/stage2/patchelf/default.nix new file mode 100644 index 0000000..f36e843 --- /dev/null +++ b/foundation/src/stages/stage2/patchelf/default.nix @@ -0,0 +1,107 @@ +{ + lib, + config, +}: let + cfg = config.aux.foundation.stages.stage2.patchelf; + + platform = config.aux.platform; + builders = config.aux.foundation.builders; + + stage1 = config.aux.foundation.stages.stage1; + stage2 = config.aux.foundation.stages.stage2; +in { + options.aux.foundation.stages.stage2.patchelf = { + package = lib.options.create { + type = lib.types.package; + description = "The package to use for patchelf."; + }; + + version = lib.options.create { + type = lib.types.string; + description = "Version of the package."; + }; + + src = lib.options.create { + type = lib.types.package; + description = "Source for the package."; + }; + + meta = { + description = lib.options.create { + type = lib.types.string; + description = "Description for the package."; + default.value = "A small utility to modify the dynamic linker and RPATH of ELF executables."; + }; + + homepage = lib.options.create { + type = lib.types.string; + description = "Homepage for the package."; + default.value = "https://github.com/NixOS/patchelf"; + }; + + license = lib.options.create { + # TODO: Add a proper type for licenses. + type = lib.types.attrs.any; + description = "License for the package."; + default.value = lib.licenses.gpl3Plus; + }; + + platforms = lib.options.create { + type = lib.types.list.of lib.types.string; + description = "Platforms the package supports."; + default.value = ["i686-linux"]; + }; + }; + }; + + config = { + aux.foundation.stages.stage2.patchelf = { + version = "0.18.0"; + + src = builtins.fetchurl { + url = "https://github.com/NixOS/patchelf/releases/download/${cfg.version}/patchelf-${cfg.version}.tar.gz"; + sha256 = "ZN4Q5Ma4uDedt+h/WAMPM26nR8BRXzgRMugQ2/hKhuc="; + }; + + package = builders.bash.build { + name = "patchelf-static-${cfg.version}"; + meta = cfg.meta; + + deps.build.host = [ + stage1.gcc.package + stage1.musl.package + stage1.binutils.package + stage1.gnumake.package + stage1.gnused.package + stage2.gnugrep.package + stage2.gawk.package + stage1.diffutils.package + stage1.findutils.package + stage1.gnutar.package + stage1.gzip.package + ]; + + script = '' + # Unpack + tar xf ${cfg.src} + cd patchelf-${cfg.version} + + # Configure + bash ./configure \ + --prefix=$out \ + --build=${platform.build} \ + --host=${platform.host} \ + CC=musl-gcc \ + CXXFLAGS=-static + + # Build + make -j $NIX_BUILD_CORES + + # Install + make -j $NIX_BUILD_CORES install-strip + + ''; + }; + }; + }; +} diff --git a/lib/src/versions/default.nix b/lib/src/versions/default.nix index a50c25e..22d11a5 100644 --- a/lib/src/versions/default.nix +++ b/lib/src/versions/default.nix @@ -14,5 +14,29 @@ lib: { ## ## @type String -> String -> Bool eq = first: second: builtins.compareVersions first second == 0; + + ## Get the major version from a version string. + ## + ## @type String -> String + major = version: let + parts = builtins.splitVersion version; + in + builtins.elemAt parts 0; + + ## Get the minor version from a version string. + ## + ## @type String -> String + minor = version: let + parts = builtins.splitVersion version; + in + builtins.elemAt parts 1; + + ## Get the patch version from a version string. + ## + ## @type String -> String + patch = version: let + parts = builtins.splitVersion version; + in + builtins.elemAt parts 2; }; }