nix: build Limine in Nix
This packages Limine in Nix and exports it via the Nix Flake. Due to the nature of the project, i.e., the self-hacked "git submodule checkout with additional patches" in `./bootstrap`, packing this in a Nix-way is very complicated. The big advantage of packaging Limine in Nix directly as part of the flake (additionally to nixpkgs) is that instead of using a fixed version from nixpkgs coming from a Limine release, one can use the current source and build everything in Nix.
diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml
index f2dc0880..04beab37 100644
--- a/.github/workflows/check.yml
+++ b/.github/workflows/check.yml
@@ -29,3 +29,21 @@ jobs:
- name: Build the bootloader (GNU, riscv64)
run: ./bootstrap && ./configure TOOLCHAIN_FOR_TARGET=riscv64-linux-gnu --enable-werror --enable-uefi-riscv64 && make all && make maintainer-clean
+
+ build_nix:
+ name: Build with Nix
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: cachix/install-nix-action@v26
+ - uses: DeterminateSystems/magic-nix-cache-action@main
+ - run: nix build .#limine
+
+ build_nix_shell:
+ name: Build with Nix shell toolchain
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: cachix/install-nix-action@v26
+ - uses: DeterminateSystems/magic-nix-cache-action@main
+ - run: nix develop --command bash -c "./bootstrap && ./configure --enable-all && make -j $(nproc)"
\ No newline at end of file
diff --git a/README.md b/README.md
index 0703a2eb..13a92c13 100644
--- a/README.md
+++ b/README.md
@@ -84,6 +84,21 @@ Host utility binaries are provided for Windows.
### Prerequisites
+### Building with Nix
+
+This repository provides [Nix](https://nixos.org/)-based tooling for a convenient
+development environment and building Limine using Nix.
+
+To use the regular build flow using a toolchain obtained by Nix, simply
+run `$ nix develop` to open a Nix shell. To build Limine completely in Nix
+using the latest sources, you can run:
+
+- `$ nix build .#\limine` (build with clang and `--enable-all`)
+
+Limine is not yet in `nixpkgs`.
+
+### Regular build
+
In order to build Limine, the following programs have to be installed:
common UNIX tools (also known as `coreutils`),
`GNU make`, `grep`, `sed`, `find`, `awk`, `gzip`, `nasm`, `mtools`
@@ -91,7 +106,7 @@ common UNIX tools (also known as `coreutils`),
Furthermore, `gcc` or `llvm/clang` must also be installed, alongside
the respective binutils.
-### Configure
+#### Configure
If using a release tarball (recommended, see https://github.com/limine-bootloader/limine/releases),
run `./configure` directly.
@@ -109,7 +124,7 @@ Limine supports both in-tree and out-of-tree builds. Simply run the `configure`
script from the directory you wish to execute the build in. The following `make`
commands are supposed to be run inside the build directory.
-### Building Limine
+#### Building Limine
To build Limine, run:
```bash
diff --git a/flake.lock b/flake.lock
index fc8e038f..aa22c560 100644
--- a/flake.lock
+++ b/flake.lock
@@ -7,11 +7,11 @@
]
},
"locked": {
- "lastModified": 1709336216,
- "narHash": "sha256-Dt/wOWeW6Sqm11Yh+2+t0dfEWxoMxGBvv3JpIocFl9E=",
+ "lastModified": 1712014858,
+ "narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=",
"owner": "hercules-ci",
"repo": "flake-parts",
- "rev": "f7b3c975cf067e56e7cda6cb098ebe3fb4d74ca2",
+ "rev": "9126214d0a59633752a136528f5f3b9aa8565b7d",
"type": "github"
},
"original": {
@@ -22,11 +22,11 @@
},
"nixpkgs": {
"locked": {
- "lastModified": 1710695816,
- "narHash": "sha256-3Eh7fhEID17pv9ZxrPwCLfqXnYP006RKzSs0JptsN84=",
+ "lastModified": 1711668574,
+ "narHash": "sha256-u1dfs0ASQIEr1icTVrsKwg2xToIpn7ZXxW3RHfHxshg=",
"owner": "NixOS",
"repo": "nixpkgs",
- "rev": "614b4613980a522ba49f0d194531beddbb7220d3",
+ "rev": "219951b495fc2eac67b1456824cc1ec1fd2ee659",
"type": "github"
},
"original": {
diff --git a/flake.nix b/flake.nix
index 87e3fbf4..18fc52ec 100644
--- a/flake.nix
+++ b/flake.nix
@@ -5,7 +5,7 @@
# regarding the packaging in nixpkgs.
{
- description = "limine";
+ description = "Limine";
inputs = {
flake-parts.url = "github:hercules-ci/flake-parts";
@@ -20,6 +20,9 @@
# will notice it soon enough.
systems = nixpkgs.lib.systems.flakeExposed;
perSystem = { config, pkgs, ... }:
+ let
+ limine = pkgs.callPackage ./nix/build.nix { };
+ in
{
devShells = {
default = pkgs.mkShell {
@@ -38,6 +41,7 @@
# gcc toolchain (comes as default, here only for completness)
binutils
gcc
+ gnumake
# llvm toolchain (with TOOLCHAIN_FOR_TARGET=llvm)
llvmPackages.bintools
@@ -52,6 +56,12 @@
# `$ nix fmt`
formatter = pkgs.nixpkgs-fmt;
+
+ # `$ nix build .#<attr>`
+ packages = {
+ inherit limine;
+ default = limine;
+ };
};
};
}
diff --git a/nix/build.nix b/nix/build.nix
new file mode 100644
index 00000000..813fe4b9
--- /dev/null
+++ b/nix/build.nix
@@ -0,0 +1,139 @@
+# Building Limine with all features in Nix.
+#
+# Independent of the packing in nixpkgs, This is convenient for prototyping and
+# local development.
+#
+# These derivations always builds Limine from the current src tree and not some
+# stable release. Further, unlike the nixpkgs derivation, this derivation runs
+# the ./bootstrap step which needs network access. Due to the nature of the
+# self-hacked Git submodules download approach, packaging this project in Nix
+# is especailly complicated. The complicated multi-derivation approach below
+# is the best I can get after multiple hours of trying. :).
+
+{
+ # Helpers
+ fd
+, lib
+, nix-gitignore
+, stdenv
+
+ # Actual derivation dependencies.
+, autoconf
+, automake
+, cacert
+, git
+, llvmPackages
+, mtools
+, nasm
+}:
+
+let
+ currentRepoSrc = nix-gitignore.gitignoreSource [
+ # Additional git ignores:
+ "flake.nix" # otherwise
+ "flake.lock"
+ "nix/"
+ ] ../.;
+
+ # Contains the sources downloaded by the Git submodule-like initialation done
+ # in ./bootstrap.
+ #
+ # ALWAYS update the hash when one of the network dependencies in ./bootstrap
+ # changes. Also, before updating, it is recommended to run "make clean"
+ # beforehand.
+ # bootstrappedSrcHash = lib.fakeHash;
+ #
+ # TODO: Unfortunately, currently this hash changes for almost every repository
+ # change. We need to strip down this derivation further to only contain the
+ # changed sources.
+ bootstrappedSrcHash = "sha256-UU5pkdbaKXPs/i/hnuk4vZcxiag1cTsTCcn2LGzPuMs=";
+ bootstrappedSrc = stdenvNoCC.mkDerivation {
+ pname = "limine-bootstrapped";
+ version = "0.0.0";
+ src = currentRepoSrc;
+ nativeBuildInputs = [
+ cacert
+ git
+ fd
+ ];
+ buildPhase = ''
+ runHook preBuild
+
+ # `true` refers to the binary/bash-builtin to prevent any configuration
+ # steps apart from downloading sources.
+ AUTOMAKE=true AUTORECONF=true ./bootstrap
+
+ # When cloning, Git automatically creates hooks. Unfortunately, in a Nix
+ # environment / on a NixOS system, this includes Nix store paths.
+ # However, me must prevent to have any Nix store path inside the final
+ # directory, as otherwise we get the error
+ # "illegal path references in fixed-output derivation"! Further, we must
+ # remove all git artifacts (.git dirs) as they affect the hash of the
+ # derivation in a non-deterministic way.
+ fd -u --type=d "^.git$" --min-depth=2 . --exec rm -rf {}
+
+ # This should report nothing. Othewise, the Nix build will fail.
+ # grep -r /nix/store .
+
+ runHook postBuild
+ '';
+ dontPatchShebangs = true;
+ installPhase = ''
+ runHook preInstall
+ mkdir $out
+
+ cp -r . $out
+
+ runHook postInstall
+ '';
+ doCheck = false;
+ dontFixup = true;
+ # See "fixed output derivation".
+ outputHashAlgo = "sha256";
+ outputHashMode = "recursive";
+ outputHash = bootstrappedSrcHash;
+ };
+
+ # Common build dependencies apart from the compiler toolchain.
+ commonBuildDeps = [
+ autoconf
+ automake
+
+ mtools
+ nasm
+ ];
+in
+stdenv.mkDerivation {
+ pname = "limine-dev";
+ version = "0.0.0";
+ src = bootstrappedSrc;
+ nativeBuildInputs = commonBuildDeps ++ [
+ # gcc is used to build the host tools and clang to (cross)compile all
+ # the bootloader files
+ llvmPackages.bintools
+ llvmPackages.clang
+ llvmPackages.lld
+ ];
+ enableParallelBuilding = true;
+ preConfigure = ''
+ # The default input source of this derivation is what we aggregated
+ # from `./bootstrap`. As this derivation holds all files but we are only
+ # interested in the ones that are not in `currentRepoSrc`, we just
+ # override all.
+ #
+ # This way we can use the actual current repo sources but still use the
+ # populated sources from the ./bootstrap script.
+ #
+ # It's very complicated, I know. But that way we can make it work, at
+ # least.
+ cp -RTf ${currentRepoSrc} .
+
+ # Extracted from ./bootstrap. To see why, check the `bootstrapedSrc`
+ # derivation.
+ #
+ # TODO, we could also do this in ./bootstrap but add a special flag.
+ autoreconf -fvi -Wall
+ '';
+ configureFlags = [ "--enable-all" ];
+ outputs = [ "out" "doc" "dev" "man" ];
+}
