Repository: vulkano-rs/vulkano
Pull request #2664: Add nix flake
Author: login: marc0246
Created: 2025-03-17T13:21:45Z | Merged: 2025-03-18T18:22:37Z

Adds a nix flake in order to make our entire build process easily reproducible.


Diff:
diff --git a/flake.lock b/flake.lock
new file mode 100644
index 0000000000..b3c30d6a89
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,82 @@
+{
+  "nodes": {
+    "flake-utils": {
+      "inputs": {
+        "systems": "systems"
+      },
+      "locked": {
+        "lastModified": 1731533236,
+        "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "type": "github"
+      }
+    },
+    "nixpkgs": {
+      "locked": {
+        "lastModified": 1741865919,
+        "narHash": "sha256-4thdbnP6dlbdq+qZWTsm4ffAwoS8Tiq1YResB+RP6WE=",
+        "owner": "nixos",
+        "repo": "nixpkgs",
+        "rev": "573c650e8a14b2faa0041645ab18aed7e60f0c9a",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nixos",
+        "ref": "nixpkgs-unstable",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "root": {
+      "inputs": {
+        "flake-utils": "flake-utils",
+        "nixpkgs": "nixpkgs",
+        "rust-overlay": "rust-overlay"
+      }
+    },
+    "rust-overlay": {
+      "inputs": {
+        "nixpkgs": [
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1742178793,
+        "narHash": "sha256-S2onMdoDS4tIYd3/Jc5oFEZBr2dJOgPrh9KzSO/bfDw=",
+        "owner": "oxalica",
+        "repo": "rust-overlay",
+        "rev": "954582a766a50ebef5695a9616c93b5386418c08",
+        "type": "github"
+      },
+      "original": {
+        "owner": "oxalica",
+        "repo": "rust-overlay",
+        "type": "github"
+      }
+    },
+    "systems": {
+      "locked": {
+        "lastModified": 1681028828,
+        "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+        "owner": "nix-systems",
+        "repo": "default",
+        "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-systems",
+        "repo": "default",
+        "type": "github"
+      }
+    }
+  },
+  "root": "root",
+  "version": 7
+}
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000000..068166face
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,48 @@
+{
+  inputs = {
+    nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
+    flake-utils.url = "github:numtide/flake-utils";
+    rust-overlay = {
+      url = "github:oxalica/rust-overlay";
+      inputs.nixpkgs.follows = "nixpkgs";
+    };
+  };
+
+  outputs = inputs @ { self, nixpkgs, flake-utils, rust-overlay, ... }:
+    flake-utils.lib.eachDefaultSystem (
+      system: let
+        overlays = [ (import rust-overlay) ];
+        pkgs = import nixpkgs { inherit system overlays; };
+      in {
+        devShells.default = with pkgs; mkShell rec {
+          buildInputs = [
+            (rust-bin.stable.latest.minimal.override {
+              extensions = [ "clippy" "rust-analyzer" "rust-docs" "rust-src" ];
+            })
+            # We use nightly rustfmt features.
+            (rust-bin.selectLatestNightlyWith (toolchain: toolchain.rustfmt))
+
+            # Vulkan dependencies
+            shaderc
+            spirv-tools
+            vulkan-loader
+            vulkan-tools
+            vulkan-tools-lunarg
+            vulkan-validation-layers
+
+            # winit dependencies
+            libxkbcommon
+            wayland
+            xorg.libX11
+            xorg.libXcursor
+            xorg.libXi
+            xorg.libXrandr
+          ];
+
+          LD_LIBRARY_PATH = lib.makeLibraryPath buildInputs;
+          SHADERC_LIB_DIR = lib.makeLibraryPath [ shaderc ];
+          VK_LAYER_PATH = "${vulkan-validation-layers}/share/vulkan/explicit_layer.d";
+        };
+      }
+    );
+}


Reviews:
user: login: Rua
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-17T17:16:08Z
user: login: marc0246
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-17T19:00:38Z
user: login: nicoonoclaste
body: Hi!  In addition to some slight comments & suggestions, I had one much more high-level question:  what's the goal here, and what are the next steps?  I read the stated rationale:

> make our entire build process easily reproducible

Presumably, this entails making various processes use the flake, for instance
1. interactive builds and development, incl. how Vulkano's devs work ;
2. automated builds and tools, such as CI and release processes:
  from experience, I can confirm having `nix` definitions of CI tasks, is highly useful for testing CI changes locally and/or debugging CI issues
3. downstreams users of Vulkano (seems unlikely)

It's much harder to evaluate a PR in a vacuum, so I'd suggest implementing (at least in part) one of those usecases; (2) seems to me like the most immediately-useful and simplest, so it might be a good idea.
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-18T16:41:19Z

Review comments:
diff_hunk: @@ -0,0 +1,45 @@
+{
+  inputs = {
+    nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
+    flake-utils.url = "github:numtide/flake-utils";
+    rust-overlay = {
+      url = "github:oxalica/rust-overlay";
+      inputs.nixpkgs.follows = "nixpkgs";
+    };
+  };
+
+  outputs = inputs @ { self, nixpkgs, flake-utils, rust-overlay, ... }:
+    flake-utils.lib.eachDefaultSystem (
+      system: let
+        overlays = [ (import rust-overlay) ];
+        pkgs = import nixpkgs { inherit system overlays; };
+      in {
+        devShells.default = with pkgs; mkShell rec {
+          buildInputs = [
+            (rust-bin.stable.latest.default.override {
+              extensions = [ "rust-analyzer" "rust-src" ];
+            })
+
+            # Vulkan dependencies
+            shaderc
path: flake.nix
user: login: Rua
body: On my system I had to do this, because `shaderc-rs` doesn't use pkg-config to find the library:
```nix
SHADERC_LIB_DIR = lib.makeLibraryPath [
  pkgs.shaderc
];
```
Does it work for you without that?
created_at: 2025-03-17T17:16:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,45 @@
+{
+  inputs = {
+    nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
+    flake-utils.url = "github:numtide/flake-utils";
+    rust-overlay = {
+      url = "github:oxalica/rust-overlay";
+      inputs.nixpkgs.follows = "nixpkgs";
+    };
+  };
+
+  outputs = inputs @ { self, nixpkgs, flake-utils, rust-overlay, ... }:
+    flake-utils.lib.eachDefaultSystem (
+      system: let
+        overlays = [ (import rust-overlay) ];
+        pkgs = import nixpkgs { inherit system overlays; };
+      in {
+        devShells.default = with pkgs; mkShell rec {
+          buildInputs = [
+            (rust-bin.stable.latest.default.override {
+              extensions = [ "rust-analyzer" "rust-src" ];
+            })
+
+            # Vulkan dependencies
+            shaderc
path: flake.nix
user: login: marc0246
body: Did you run the flake?
created_at: 2025-03-17T19:00:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,47 @@
+{
+  inputs = {
+    nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
+    flake-utils.url = "github:numtide/flake-utils";
+    rust-overlay = {
+      url = "github:oxalica/rust-overlay";
+      inputs.nixpkgs.follows = "nixpkgs";
+    };
+  };
+
+  outputs = inputs @ { self, nixpkgs, flake-utils, rust-overlay, ... }:
+    flake-utils.lib.eachDefaultSystem (
+      system: let
+        overlays = [ (import rust-overlay) ];
+        pkgs = import nixpkgs { inherit system overlays; };
+      in {
+        devShells.default = with pkgs; mkShell rec {
+          buildInputs = [
+            (rust-bin.stable.latest.minimal.override {
+              extensions = [ "clippy" "rust-analyzer" "rust-docs" "rust-src" ];
+            })
+            (rust-bin.selectLatestNightlyWith (toolchain: toolchain.rustfmt))
+
+            # Vulkan dependencies
+            shaderc
+            spirv-tools
+            vulkan-loader
+            vulkan-tools
+            vulkan-tools-lunarg
+            vulkan-validation-layers
+
+            # winit dependencies
+            libxkbcommon
+            wayland
+            xorg.libX11
+            xorg.libXcursor
+            xorg.libXi
+            xorg.libXrandr
+          ];
+
+          LD_LIBRARY_PATH = "${lib.makeLibraryPath buildInputs}";
+          SHADERC_LIB_DIR = "${shaderc.lib}/lib";
path: flake.nix
user: login: nicoonoclaste
body: ```suggestion
          LD_LIBRARY_PATH = lib.makeLibraryPath buildInputs;
          SHADERC_LIB_DIR = lib.makeLibraryPath [ shaderc ];
```
created_at: 2025-03-18T16:03:02Z
author_association: NONE
diff_hunk: @@ -0,0 +1,47 @@
+{
+  inputs = {
+    nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
+    flake-utils.url = "github:numtide/flake-utils";
+    rust-overlay = {
+      url = "github:oxalica/rust-overlay";
+      inputs.nixpkgs.follows = "nixpkgs";
+    };
+  };
+
+  outputs = inputs @ { self, nixpkgs, flake-utils, rust-overlay, ... }:
+    flake-utils.lib.eachDefaultSystem (
+      system: let
+        overlays = [ (import rust-overlay) ];
+        pkgs = import nixpkgs { inherit system overlays; };
+      in {
+        devShells.default = with pkgs; mkShell rec {
+          buildInputs = [
+            (rust-bin.stable.latest.minimal.override {
+              extensions = [ "clippy" "rust-analyzer" "rust-docs" "rust-src" ];
+            })
+            (rust-bin.selectLatestNightlyWith (toolchain: toolchain.rustfmt))
path: flake.nix
user: login: nicoonoclaste
body: What's the rationaly for getting  the nightly `rustfmt` ?  Even if there's a good reason, it would be best to document it with a comment.
created_at: 2025-03-18T16:04:21Z
author_association: NONE

PR comments:
user: login: marc0246
created_at: 2025-03-18T16:59:42Z
body: @nbraud It's (1) and (3) ironically enough. Rua and I use NixOS so it's useful for us working on vulkano (and anyone else working on it). Newcomers also can't stop choking on our shaderc dependency, as is evidenced in #2559 and numerous other cases on Discord. At least for the ones that use Nix, it's certainly helpful.
author_association: CONTRIBUTOR
user: login: nicoonoclaste
created_at: 2025-03-18T17:57:33Z
body: >Rua and I use NixOS so it's useful for us working on vulkano

I'm aware, I (sort-of accidentally) converted Rua to NixOS, and helped her make an appropriate `mkShell` env. for Vulkano  :joy_cat: 

> Newcomers also can't stop choking on our shaderc dependency, as is evidenced in #2559 and numerous other cases on Discord. At least for the ones that use Nix, it's certainly helpful.

Fair enough, though I'd suggest thinking about how downstreams users would work with it: presumably, they aren't interested in only building vulkano, so they'd likely need to define their own derivations, dev shells, etc. While it's easy-enough to override derivations provided by vulkano's flake, this doesn't scale nicely to more than one dependency.

IDK if there's a commonplace solution for that in the brave new flakes world (I'm one of those crusty nixpkgers who don't really flake) but what seems obvious to me, would an attrset providing the necessary `buildInputs` (minus the rust toolchain?) and environment variables.

Furthermore, such an attrset could be reused multiple times in the flake, for example defining the dev environment(s), CI tasks, as well as derivations for the various examples.
author_association: NONE
user: login: marc0246
created_at: 2025-03-18T18:02:25Z
body: > I'd suggest thinking about how downstreams users would work with it

I don't see why you'd do that. What I was referring to is looking at the flake for how to make your own, if you want to use a flake for your own project, as well as running the examples in the repository.

I'm also not concerned with CI or anything besides the dev shell for now. This PR is just adding a dev shell.
author_association: CONTRIBUTOR
user: login: nicoonoclaste
created_at: 2025-03-18T18:16:25Z
body: As I said, “just adding a dev shell” without considering how it's meant to be used, make review difficult; you do you though, I only pitched in because @Rua asked me about this PR.
author_association: NONE
user: login: marc0246
created_at: 2025-03-18T18:23:02Z
body: I certainly appreciate your input to be clear. And to make it clear how it's supposed to be used: you run `nix develop` and then work on the code base/run examples. That's all.
author_association: CONTRIBUTOR
user: login: nicoonoclaste
created_at: 2025-03-18T18:29:02Z
body: > how it's supposed to be used: you run `nix develop` and then work on the code base/run examples. That's all.

OK, so it's *not* meant to be used by downstream users?  *is confused, just goes curl up somewhere.*
author_association: NONE
user: login: marc0246
created_at: 2025-03-18T18:31:19Z
body: I was not intending the flake's outputs to be used as inputs, because I personally don't think there's much point in that. I was referring to users using the flake to run our examples, and to *copy+paste* into their own flake. I can see that I didn't explain that very well though so it's not your fault.
author_association: CONTRIBUTOR
user: login: axelkar
created_at: 2025-03-20T17:49:26Z
body: I recommend not using the unstable channel, since packages change so much on there. Please use `nixpkgs-24.11` so there won't be so many duplicate packages. It also helps out people getting started with Nix.
author_association: NONE
user: login: marc0246
created_at: 2025-03-20T18:01:14Z
body: @axelkar I don't think that's a good idea. We want the latest Vulkan tools and validation layers. You can use whatever channel you like in your own flake, but I wouldn't recommend that to newcomers either.
author_association: CONTRIBUTOR