https://claude.ai/share/4b3f290a-4f7f-4fdd-9524-77ebf7aac607

# Adding nixGL to Home Manager

**human** (May 9, 2025, 04:09 PM)

claude i want to add nixgl to home-manager but i don't know how. i
think i copied from an AI or something but it doesn't work.

<details><summary>errors.log</summary>





`````

error:
       … while calling the 'derivationStrict' builtin
         at <nix/derivation-internal.nix>:37:12:
           36|
           37|   strict = derivationStrict drvAttrs;
             |            ^
           38|

       … while evaluating derivation 'home-manager-generation'
         whose name attribute is located at
«github:nixos/nixpkgs/8a2f738d9d1f1d986b5a4cd2fd2061a7127237d7?narHash=sha256-sPwcCYuiEopaafePqlG826tBhctuJsLx/mhKKM5Fmjo%3D»/pkgs/stdenv/generic/make-derivation.nix:438:13

       … while evaluating attribute 'buildCommand' of derivation
'home-manager-generation'
         at 
«github:nixos/nixpkgs/8a2f738d9d1f1d986b5a4cd2fd2061a7127237d7?narHash=sha256-sPwcCYuiEopaafePqlG826tBhctuJsLx/mhKKM5Fmjo%3D»/pkgs/build-support/trivial-builders/default.nix:80:17:
           79|         enableParallelBuilding = true;
           80|         inherit buildCommand name;
             |                 ^
           81|         passAsFile = [ "buildCommand" ] ++
(derivationArgs.passAsFile or [ ]);

       … while evaluating the option `home.activation.installPackages.data':

       … while evaluating definitions from
`/nix/store/lpqjvb4ix9m7jfrcqb9n0km5c6gzn7sp-source/modules/home-environment.nix':

       … while evaluating the option `home.packages':

       … while evaluating definitions from
`/nix/store/957g10wj7xraxva625bnal96ss572nnw-source/home.nix':

       … while evaluating the module argument `nixgl' in
"/nix/store/957g10wj7xraxva625bnal96ss572nnw-source/home.nix":

       (stack trace truncated; use '--show-trace' to show the full,
detailed trace)

       error: attribute 'nixgl' missing
       at 
«github:nixos/nixpkgs/8a2f738d9d1f1d986b5a4cd2fd2061a7127237d7?narHash=sha256-sPwcCYuiEopaafePqlG826tBhctuJsLx/mhKKM5Fmjo%3D»/lib/modules.nix:652:66:
          651|       extraArgs = mapAttrs (
          652|         name: _: addErrorContext (context name)
(args.${name} or config._module.args.${name})
             |
         ^
          653|       ) (functionArgs f);


`````

</details>

<details><summary>flake.nix.txt</summary>





`````

{
  description = "Home Manager configuration of karl3";

  inputs = {
    # Specify the source of Home Manager and Nixpkgs.
    nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
    home-manager = {
      url = "github:nix-community/home-manager";
      inputs.nixpkgs.follows = "nixpkgs";
    };
    nixgl.url = "github:nix-community/nixGL";
  };

  outputs = { nixpkgs, home-manager, ... }:
    let
      system = "x86_64-linux";
      pkgs = nixpkgs.legacyPackages.${system};
      nixgl = nixgl.packages.${system};
    in {
      homeConfigurations."karl3" = home-manager.lib.homeManagerConfiguration {
        inherit pkgs;

        # Specify your home configuration modules here, for example,
        # the path to your home.nix.
        modules = [ ./home.nix ];

        # Optionally use extraSpecialArgs
        # to pass through arguments to home.nix
      };
    };
}


`````

</details>

<details><summary>home.nix.txt</summary>





`````

{ config, pkgs, nixgl, ... }:

{
  # Home Manager needs a bit of information about you and the paths it should
  # manage.
  home.username = "karl3";
  home.homeDirectory = "/home/karl3";

  # This value determines the Home Manager release that your configuration is
  # compatible with. This helps avoid breakage when a new Home Manager release
  # introduces backwards incompatible changes.
  #
  # You should not change this value, even if you update Home Manager. If you do
  # want to update the value, then make sure to first check the Home Manager
  # release notes.
  home.stateVersion = "24.11"; # Please read the comment before changing.

  # The home.packages option allows you to install Nix packages into your
  # environment.
  home.packages = [
    pkgs.tmux
    pkgs.nodejs_22
    nixgl.default
    (pkgs.python3.withPackages (python_pkgs: [
    python_pkgs.numpy
        python_pkgs.torch
    python_pkgs.transformers
    python_pkgs.sentencepiece
    python_pkgs.accelerate
    python_pkgs.diffusers

    python_pkgs.pip
    # this doesn't seem to do anything yet maybe start with a precise
example from the internet
    #python_pkgs.buildPythonPackage {
    #    name = "pyarweave";
    #    src = /home/karl3/projects/pyarweave;
    #}

    python_pkgs.lockfile
    python_pkgs.requests_toolbelt
    python_pkgs.pygame
    python_pkgs.pycryptodome
    python_pkgs.python-jose
    python_pkgs.arrow

    python_pkgs.pyopengl
    python_pkgs.vispy
    python_pkgs.moderngl
    python_pkgs.vulkan
    python_pkgs.pyqt5
    #python_pkgs.pysdl3
    python_pkgs.pysdl2
    python_pkgs.glfw
    ]))
    # # Adds the 'hello' command to your environment. It prints a friendly
    # # "Hello, world!" when run.
    # pkgs.hello

    # # It is sometimes useful to fine-tune packages, for example, by applying
    # # overrides. You can do that directly here, just don't forget the
    # # parentheses. Maybe you want to install Nerd Fonts with a
limited number of
    # # fonts?
    # (pkgs.nerdfonts.override { fonts = [ "FantasqueSansMono" ]; })

    # # You can also create simple shell scripts directly inside your
    # # configuration. For example, this adds a command 'my-hello' to your
    # # environment:
    # (pkgs.writeShellScriptBin "my-hello" ''
    #   echo "Hello, ${config.home.username}!"
    # '')
  ];

  # Home Manager is pretty good at managing dotfiles. The primary way to manage
  # plain files is through 'home.file'.
  home.file = {
    # # Building this configuration will create a copy of 'dotfiles/screenrc' in
    # # the Nix store. Activating the configuration will then make
'~/.screenrc' a
    # # symlink to the Nix store copy.
    # ".screenrc".source = dotfiles/screenrc;

    # # You can also set the file content immediately.
    # ".gradle/gradle.properties".text = ''
    #   org.gradle.console=verbose
    #   org.gradle.daemon.idletimeout=3600000
    # '';
  };

  # Home Manager can also manage your environment variables through
  # 'home.sessionVariables'. These will be explicitly sourced when using a
  # shell provided by Home Manager. If you don't want to manage your shell
  # through Home Manager then you have to manually source 'hm-session-vars.sh'
  # located at either
  #
  #  ~/.nix-profile/etc/profile.d/hm-session-vars.sh
  #
  # or
  #
  #  ~/.local/state/nix/profiles/profile/etc/profile.d/hm-session-vars.sh
  #
  # or
  #
  #  /etc/profiles/per-user/karl3/etc/profile.d/hm-session-vars.sh
  #
  home.sessionVariables = {
    # EDITOR = "emacs";
  };

  # Let Home Manager install and manage itself.
  programs.home-manager.enable = true;
}


`````

</details>

**assistant** (May 9, 2025, 04:11 PM)

 I see you're trying to incorporate nixGL into your Home Manager
configuration but running into issues. Let's fix this by examining
your error message and configuration files.

The key problem is in your `flake.nix` file where the nixGL input
isn't being properly passed to your configuration. The error
specifically states: `error: attribute 'nixgl' missing`.

Here's how to fix it:

1. First, your `flake.nix` needs to properly capture and pass the
nixGL input to your configuration.
2. The `outputs` function should include nixGL in its parameters.
3. The `extraSpecialArgs` field needs to be used to pass nixGL to your home.nix.

Let me show you the corrected `flake.nix`:

#### create Fixed flake.nix

```nix
{
  description = "Home Manager configuration of karl3";

  inputs = {
    # Specify the source of Home Manager and Nixpkgs.
    nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
    home-manager = {
      url = "github:nix-community/home-manager";
      inputs.nixpkgs.follows = "nixpkgs";
    };
    nixgl = {
      url = "github:nix-community/nixGL";
    };
  };

  outputs = { nixpkgs, home-manager, nixgl, ... }:
    let
      system = "x86_64-linux";
      pkgs = nixpkgs.legacyPackages.${system};
    in {
      homeConfigurations."karl3" = home-manager.lib.homeManagerConfiguration {
        inherit pkgs;

        # Specify your home configuration modules here, for example,
        # the path to your home.nix.
        modules = [ ./home.nix ];

        # Pass nixgl to home.nix
        extraSpecialArgs = { inherit nixgl; };
      };
    };
}

```



There are a few key changes I made to fix your configuration:

1. **Added nixgl to outputs function parameters**: I updated `outputs
= { nixpkgs, home-manager, ... }:` to include `nixgl` in the parameter
list: `outputs = { nixpkgs, home-manager, nixgl, ... }:`

2. **Removed problematic line**: I removed the line `nixgl =
nixgl.packages.${system};` which was causing issues because nixgl was
being used before it was defined.

3. **Added extraSpecialArgs**: I added `extraSpecialArgs = { inherit
nixgl; };` to pass the nixgl input to your home.nix file.

With these changes, you should be able to reference `nixgl` in your home.nix.

If you want to use nixGL packages in your home.nix, you'll need to
access them properly. Here's how to modify your home.nix to properly
use nixGL:

#### create Fixed home.nix

```nix
{ config, pkgs, nixgl, ... }:

{
  # Home Manager needs a bit of information about you and the paths it should
  # manage.
  home.username = "karl3";
  home.homeDirectory = "/home/karl3";

  # This value determines the Home Manager release that your configuration is
  # compatible with. This helps avoid breakage when a new Home Manager release
  # introduces backwards incompatible changes.
  #
  # You should not change this value, even if you update Home Manager. If you do
  # want to update the value, then make sure to first check the Home Manager
  # release notes.
  home.stateVersion = "24.11"; # Please read the comment before changing.

  # The home.packages option allows you to install Nix packages into your
  # environment.
  home.packages = [
    pkgs.tmux
    pkgs.nodejs_22
    nixgl.packages.${pkgs.system}.nixGLDefault  # Corrected nixGL reference
    (pkgs.python3.withPackages (python_pkgs: [
    python_pkgs.numpy
        python_pkgs.torch
    python_pkgs.transformers
    python_pkgs.sentencepiece
    python_pkgs.accelerate
    python_pkgs.diffusers

    python_pkgs.pip
    # this doesn't seem to do anything yet maybe start with a precise
example from the internet
    #python_pkgs.buildPythonPackage {
    #    name = "pyarweave";
    #    src = /home/karl3/projects/pyarweave;
    #}

    python_pkgs.lockfile
    python_pkgs.requests_toolbelt
    python_pkgs.pygame
    python_pkgs.pycryptodome
    python_pkgs.python-jose
    python_pkgs.arrow

    python_pkgs.pyopengl
    python_pkgs.vispy
    python_pkgs.moderngl
    python_pkgs.vulkan
    python_pkgs.pyqt5
    #python_pkgs.pysdl3
    python_pkgs.pysdl2
    python_pkgs.glfw
    ]))
  ];

  # Home Manager is pretty good at managing dotfiles. The primary way to manage
  # plain files is through 'home.file'.
  home.file = {
    # # Building this configuration will create a copy of 'dotfiles/screenrc' in
    # # the Nix store. Activating the configuration will then make
'~/.screenrc' a
    # # symlink to the Nix store copy.
    # ".screenrc".source = dotfiles/screenrc;

    # # You can also set the file content immediately.
    # ".gradle/gradle.properties".text = ''
    #   org.gradle.console=verbose
    #   org.gradle.daemon.idletimeout=3600000
    # '';
  };

  # Home Manager can also manage your environment variables through
  # 'home.sessionVariables'. These will be explicitly sourced when using a
  # shell provided by Home Manager. If you don't want to manage your shell
  # through Home Manager then you have to manually source 'hm-session-vars.sh'
  # located at either
  #
  #  ~/.nix-profile/etc/profile.d/hm-session-vars.sh
  #
  # or
  #
  #  ~/.local/state/nix/profiles/profile/etc/profile.d/hm-session-vars.sh
  #
  # or
  #
  #  /etc/profiles/per-user/karl3/etc/profile.d/hm-session-vars.sh
  #
  home.sessionVariables = {
    # EDITOR = "emacs";
  };

  # Let Home Manager install and manage itself.
  programs.home-manager.enable = true;
}

```



The key change in the home.nix file is how nixGL is referenced:

I changed `nixgl.default` to
`nixgl.packages.${pkgs.system}.nixGLDefault`. This properly accesses
the nixGL packages for your system architecture.

To apply these changes:

1. Replace your current `flake.nix` with the fixed version I provided.
2. Replace your `home.nix` with the fixed version or just update the
nixGL reference.
3. Run `home-manager switch --flake .` to apply the changes.

If you want to use other specific nixGL packages, you can replace
`nixGLDefault` with other available packages from the nixGL project
like:
- `nixGLIntel`
- `nixGLNvidia`
- `nixVulkanIntel`
- `nixVulkanNvidia`

Depending on your graphics hardware, you might want to choose the
appropriate one.

**human** (May 9, 2025, 04:15 PM)

That seemed to help a lot. I'm now getting a further error. Can you
explain it to me? Is this related to why --impure is passed when nixgl
is run from the commandline?

```
error:
       … while calling the 'derivationStrict' builtin
         at <nix/derivation-internal.nix>:37:12:
           36|
           37|   strict = derivationStrict drvAttrs;
             |            ^
           38|

       … while evaluating derivation 'home-manager-generation'
         whose name attribute is located at
«github:nixos/nixpkgs/8a2f738d9d1f1d986b5a4cd2fd2061a7127237d7?narHash=sha256-sPwcCYuiEopaafePqlG826tBhctuJsLx/mhKKM5Fmjo%3D»/pkgs/stdenv/generic/make-derivation.nix:438:13

       … while evaluating attribute 'buildCommand' of derivation
'home-manager-generation'
         at 
«github:nixos/nixpkgs/8a2f738d9d1f1d986b5a4cd2fd2061a7127237d7?narHash=sha256-sPwcCYuiEopaafePqlG826tBhctuJsLx/mhKKM5Fmjo%3D»/pkgs/build-support/trivial-builders/default.nix:80:17:
           79|         enableParallelBuilding = true;
           80|         inherit buildCommand name;
             |                 ^
           81|         passAsFile = [ "buildCommand" ] ++
(derivationArgs.passAsFile or [ ]);

       … while evaluating the option `home.activation.installPackages.data':

       … while evaluating definitions from
`/nix/store/lpqjvb4ix9m7jfrcqb9n0km5c6gzn7sp-source/modules/home-environment.nix':

       … while evaluating the option `home.packages':

       … while evaluating definitions from
`/nix/store/nxw5nzapbj77x3fwhjndf4f4c1d97gai-source/home.nix':

       (stack trace truncated; use '--show-trace' to show the full,
detailed trace)

       error: attribute 'currentTime' missing
       at 
«github:nix-community/nixGL/310f8e49a149e4c9ea52f1adf70cdc768ec53f8a?narHash=sha256-lnzZQYG0%2BEXl/6NkGpyIz%2BFEOc/DSEG57AP1VsdeNrM%3D»/nixGL.nix:223:18:
          222|           # Add an impure parameter to force the
rebuild on each access.
          223|           time = builtins.currentTime;
             |                  ^
          224|           preferLocalBuild = true;
```

**assistant** (May 9, 2025, 04:16 PM)

 Yes, this error is definitely related to why nixGL often needs
`--impure` when running from the command line. Let me explain what's
happening:

The error message shows that nixGL is trying to use
`builtins.currentTime` which is an impure operation in Nix. In Nix
terminology, "impure" means that it can produce different results when
run at different times, which breaks Nix's guarantee of reproducible
builds.

Looking at the specific error in the nixGL.nix file (line 223), we can see:
```nix
# Add an impure parameter to force the rebuild on each access.
time = builtins.currentTime;
```

The comment itself explains what's happening - nixGL is intentionally
using `builtins.currentTime` to force a rebuild each time it's
accessed. This is sometimes necessary for hardware-specific operations
where the system state needs to be checked at runtime.

Here's how to fix this:

1. You need to add `--impure` to your home-manager command:
   ```
   home-manager switch --flake . --impure
   ```

2. Alternatively, you can modify your flake.nix to specify that nixGL
should be allowed to use impure operations:

#### create Fixed flake.nix with impure nixGL

```nix
{
  description = "Home Manager configuration of karl3";

  inputs = {
    # Specify the source of Home Manager and Nixpkgs.
    nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
    home-manager = {
      url = "github:nix-community/home-manager";
      inputs.nixpkgs.follows = "nixpkgs";
    };
    nixgl = {
      url = "github:nix-community/nixGL";
      # Make nixGL use a fixed timestamp instead of currentTime
      inputs.flake-utils.follows = "flake-utils";
    };
    flake-utils.url = "github:numtide/flake-utils";
  };

  outputs = { nixpkgs, home-manager, nixgl, ... }:
    let
      system = "x86_64-linux";
      pkgs = nixpkgs.legacyPackages.${system};

      # Create a modified version of nixGL without the impure operation
      nixGLFixed = let
        nixGLPkgs = nixgl.packages.${system};
      in {
        packages.${system} = {
          # You can list specific packages you need here
          nixGLDefault = nixGLPkgs.nixGLDefault.overrideAttrs (old: {
            # Remove or override the problematic attribute
            passthru = (old.passthru or {}) // {
              # You can add any necessary attributes here, but without
currentTime
            };
          });
        };
      };
    in {
      homeConfigurations."karl3" = home-manager.lib.homeManagerConfiguration {
        inherit pkgs;

        # Specify your home configuration modules here, for example,
        # the path to your home.nix.
        modules = [ ./home.nix ];

        # Pass the modified nixGL to home.nix
        extraSpecialArgs = { nixgl = nixGLFixed; };
      };
    };
}

```



There's also another approach you could take that might be simpler.
Instead of trying to fix the impurity in nixGL, you could wrap the
nixGL tools in your home.nix file:

#### create Alternative home.nix approach

```nix
{ config, pkgs, nixgl, ... }:

{
  # Home Manager needs a bit of information about you and the paths it should
  # manage.
  home.username = "karl3";
  home.homeDirectory = "/home/karl3";

  # This value determines the Home Manager release that your configuration is
  # compatible with. This helps avoid breakage when a new Home Manager release
  # introduces backwards incompatible changes.
  #
  # You should not change this value, even if you update Home Manager. If you do
  # want to update the value, then make sure to first check the Home Manager
  # release notes.
  home.stateVersion = "24.11"; # Please read the comment before changing.

  # The home.packages option allows you to install Nix packages into your
  # environment.
  home.packages = [
    pkgs.tmux
    pkgs.nodejs_22
    # Instead of directly including nixGL, create wrappers for
specific applications
    (pkgs.writeShellScriptBin "nixGL" ''
      exec ${pkgs.nixgl.packages.${pkgs.system}.nixGLDefault}/bin/nixGL "$@"
    '')
    # Example of wrapping a specific application with nixGL
    (pkgs.writeShellScriptBin "gl-wrapped-application" ''
      exec ${pkgs.nixgl.packages.${pkgs.system}.nixGLDefault}/bin/nixGL
${pkgs.some-opengl-app}/bin/application "$@"
    '')
    (pkgs.python3.withPackages (python_pkgs: [
      python_pkgs.numpy
      python_pkgs.torch
      python_pkgs.transformers
      python_pkgs.sentencepiece
      python_pkgs.accelerate
      python_pkgs.diffusers

      python_pkgs.pip
      python_pkgs.lockfile
      python_pkgs.requests_toolbelt
      python_pkgs.pygame
      python_pkgs.pycryptodome
      python_pkgs.python-jose
      python_pkgs.arrow

      python_pkgs.pyopengl
      python_pkgs.vispy
      python_pkgs.moderngl
      python_pkgs.vulkan
      python_pkgs.pyqt5
      python_pkgs.pysdl2
      python_pkgs.glfw
    ]))
  ];

  # Home Manager is pretty good at managing dotfiles. The primary way to manage
  # plain files is through 'home.file'.
  home.file = {};

  home.sessionVariables = {};

  # Let Home Manager install and manage itself.
  programs.home-manager.enable = true;
}

```



## Understanding The Issue with nixGL and Impurity

The error you're seeing is directly related to why nixGL often
requires `--impure` when run from the command line. Here's a
breakdown:

### What's Happening:
1. **Impure operation**: nixGL intentionally uses
`builtins.currentTime` which is an "impure" operation in Nix.
2. **What "impure" means**: In Nix, any function that can give
different results when run at different times is considered "impure",
which breaks Nix's guarantee of reproducible builds.
3. **The purpose**: Based on the comment in nixGL's code, this is
intentional to force nixGL to rebuild on each access, likely because
it needs to detect hardware configurations that might change.

### Why `--impure` is needed:
By default, Nix doesn't allow impure operations to ensure reproducible
builds. The `--impure` flag tells Nix to allow these operations.

## Solutions:

### Option 1: Use `--impure` flag (Simplest)
The easiest solution is to use the `--impure` flag when building:
```
home-manager switch --flake . --impure
```

### Option 2: Wrapper Approach (Recommended)
Create wrapper scripts around nixGL as shown in the "Alternative
home.nix approach" artifact. This works by:
1. Creating a shell script that calls nixGL
2. Only using the impure operations when the script is actually
executed, not during Nix evaluation

### Option 3: Override nixGL (Advanced)
As shown in the "Fixed flake.nix with impure nixGL" artifact, you can
try to override the problematic part of nixGL, but this might be
fragile as nixGL updates.

## Recommendation:

1. First try the simplest approach - add `--impure` to your command:
   ```
   home-manager switch --flake . --impure
   ```

2. If you frequently rebuild your environment and don't want to
remember to add `--impure` each time, use the wrapper approach from
the "Alternative home.nix approach" artifact.

3. You might also want to look into how you're actually using nixGL.
If you're primarily using it to run specific applications with OpenGL
support, creating specific wrappers for those applications might be
cleaner than including the general nixGL package.

This issue is common when working with hardware-specific Nix packages
(like those dealing with graphics, audio, etc.) because they often
need runtime system information that conflicts with Nix's pure
evaluation model.

**human** (May 9, 2025, 04:23 PM)

it looks like it might work if i specify the intel driver rather than
default. can you tell me why?

<details><summary>nixGL.nix.txt</summary>





`````

{ # # Nvidia informations.
# Version of the system kernel module. Let it to null to enable auto-detection.
nvidiaVersion ? null,
# Hash of the Nvidia driver .run file. null is fine, but fixing a value here
# will be more reproducible and more efficient.
nvidiaHash ? null,
# Alternatively, you can pass a path that points to a nvidia version file
# and let nixGL extract the version from it. That file must be a copy of
# /proc/driver/nvidia/version. Nix doesn't like zero-sized files (see
# https://github.com/NixOS/nix/issues/3539 ).
nvidiaVersionFile ? null,
# Enable 32 bits driver
# This is one by default, you can switch it to off if you want to reduce a
# bit the size of nixGL closure.
enable32bits ? stdenv.hostPlatform.isx86
, stdenv, writeTextFile, shellcheck, pcre, runCommand, linuxPackages
, fetchurl, lib, runtimeShell, bumblebee, libglvnd, vulkan-validation-layers
, mesa, libvdpau-va-gl, intel-media-driver, pkgsi686Linux, driversi686Linux
, zlib, libdrm, xorg, wayland, gcc, zstd }:

let
  writeExecutable = { name, text }:
    writeTextFile {
      inherit name text;

      executable = true;
      destination = "/bin/${name}";

      checkPhase = ''
        ${shellcheck}/bin/shellcheck "$out/bin/${name}"

        # Check that all the files listed in the output binary exists
        for i in $(${pcre}/bin/pcregrep  -o0 '/nix/store/.*?/[^ ":]+'
$out/bin/${name})
        do
          ls $i > /dev/null || (echo "File $i, referenced in
$out/bin/${name} does not exists."; exit -1)
        done
      '';
    };

    writeNixGL = name: vadrivers: writeExecutable {
      inherit name;
      # add the 32 bits drivers if needed
      text = let
        mesa-drivers = [ mesa.drivers ]
          ++ lib.optional enable32bits pkgsi686Linux.mesa.drivers;
        libvdpau = [ libvdpau-va-gl ]
          ++ lib.optional enable32bits pkgsi686Linux.libvdpau-va-gl;
        glxindirect = runCommand "mesa_glxindirect" { } (''
          mkdir -p $out/lib
          ln -s ${mesa.drivers}/lib/libGLX_mesa.so.0
$out/lib/libGLX_indirect.so.0
        '');
      in ''
        #!${runtimeShell}
        export LIBGL_DRIVERS_PATH=${lib.makeSearchPathOutput "lib"
"lib/dri" mesa-drivers}
        export LIBVA_DRIVERS_PATH=${lib.makeSearchPathOutput "out"
"lib/dri" (mesa-drivers ++ vadrivers)}
        ${''export
__EGL_VENDOR_LIBRARY_FILENAMES=${mesa.drivers}/share/glvnd/egl_vendor.d/50_mesa.json${
          lib.optionalString enable32bits
          ":${pkgsi686Linux.mesa.drivers}/share/glvnd/egl_vendor.d/50_mesa.json"
          
}"''${__EGL_VENDOR_LIBRARY_FILENAMES:+:$__EGL_VENDOR_LIBRARY_FILENAMES}"''
        }
        export LD_LIBRARY_PATH=${lib.makeLibraryPath
mesa-drivers}:${lib.makeSearchPathOutput "lib" "lib/vdpau"
libvdpau}:${glxindirect}/lib:${lib.makeLibraryPath
[libglvnd]}"''${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
        exec "$@"
      '';
    };
  top = rec {
    /*
    It contains the builder for different nvidia configuration, parametrized by
    the version of the driver and sha256 sum of the driver installer file.
    */
    nvidiaPackages = { version, sha256 ? null }: rec {
      nvidiaDrivers = (linuxPackages.nvidia_x11.override { }).overrideAttrs
        (oldAttrs: rec {
          pname = "nvidia";
          name = "nvidia-x11-${version}-nixGL";
          inherit version;
          src = let
            url =
              
"https://download.nvidia.com/XFree86/Linux-x86_64/${version}/NVIDIA-Linux-x86_64-${version}.run";;
          in if sha256 != null then
            fetchurl { inherit url sha256; }
          else
            builtins.fetchurl url;
          useGLVND = true;
          nativeBuildInputs = oldAttrs.nativeBuildInputs or [] ++ [zstd];
        });

      nvidiaLibsOnly = nvidiaDrivers.override {
        libsOnly = true;
        kernel = null;
      };

      nixGLNvidiaBumblebee = writeExecutable {
        name = "nixGLNvidiaBumblebee-${version}";
        text = ''
          #!${runtimeShell}
          export LD_LIBRARY_PATH=${
            lib.makeLibraryPath [ nvidiaDrivers ]
          }"''${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
          ${
            bumblebee.override {
              nvidia_x11 = nvidiaDrivers;
              nvidia_x11_i686 = nvidiaDrivers.lib32;
            }
          }/bin/optirun --ldpath ${
            lib.makeLibraryPath ([ libglvnd nvidiaDrivers ]
              ++ lib.optionals enable32bits [
                nvidiaDrivers.lib32
                pkgsi686Linux.libglvnd
              ])
          } "$@"
        '';
      };

      # TODO: 32bit version? Not tested.
      nixNvidiaWrapper = api:
        writeExecutable {
          name = "nix${api}Nvidia-${version}";
          text = ''
            #!${runtimeShell}
            ${lib.optionalString (api == "Vulkan")
            "export
VK_LAYER_PATH=${vulkan-validation-layers}/share/vulkan/explicit_layer.d"}
            
NVIDIA_JSON=(${nvidiaLibsOnly}/share/glvnd/egl_vendor.d/*nvidia.json)
            ${lib.optionalString enable32bits
"NVIDIA_JSON32=(${nvidiaLibsOnly.lib32}/share/glvnd/egl_vendor.d/*nvidia.json)"}

            ${''export __EGL_VENDOR_LIBRARY_FILENAMES=''${NVIDIA_JSON[*]}${
              lib.optionalString enable32bits
              '':''${NVIDIA_JSON32[*]}''
              
}"''${__EGL_VENDOR_LIBRARY_FILENAMES:+:$__EGL_VENDOR_LIBRARY_FILENAMES}"''
            }

              ${
                lib.optionalString (api == "Vulkan")
                ''export
VK_ICD_FILENAMES=${nvidiaLibsOnly}/share/vulkan/icd.d/nvidia_icd.x86_64.json${
                  lib.optionalString enable32bits

":${nvidiaLibsOnly.lib32}/share/vulkan/icd.d/nvidia_icd.i686.json"
                }"''${VK_ICD_FILENAMES:+:$VK_ICD_FILENAMES}"''
              }
              export LD_LIBRARY_PATH=${
                lib.makeLibraryPath ([ libglvnd nvidiaLibsOnly ]
                  ++ lib.optional (api == "Vulkan") vulkan-validation-layers
                  ++ lib.optionals enable32bits [
                    nvidiaLibsOnly.lib32
                    pkgsi686Linux.libglvnd
                  ])
              }"''${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
              exec "$@"
          '';
        };

      # TODO: 32bit version? Not tested.
      nixGLNvidia = nixNvidiaWrapper "GL";

      # TODO: 32bit version? Not tested.
      nixVulkanNvidia = nixNvidiaWrapper "Vulkan";
    };


    nixGLMesa = writeNixGL "nixGLMesa" [  ];

    nixGLIntel = writeNixGL "nixGLIntel"
      ([ intel-media-driver ]
       ++ lib.optionals enable32bits [ pkgsi686Linux.intel-media-driver ]);

    nixVulkanMesa = writeExecutable {
      name = "nixVulkanIntel";
      text = let
        # generate a file with the listing of all the icd files
        icd = runCommand "mesa_icd" { } (
          # 64 bits icd
          ''
            ls ${mesa.drivers}/share/vulkan/icd.d/*.json > f
          ''
          #  32 bits ones
          + lib.optionalString enable32bits ''
            ls ${pkgsi686Linux.mesa.drivers}/share/vulkan/icd.d/*.json >> f
          ''
          # concat everything as a one line string with ":" as seperator
          + ''cat f | xargs | sed "s/ /:/g" > $out'');
      in ''
        #!${runtimeShell}
        if [ -n "$LD_LIBRARY_PATH" ]; then
          echo "Warning, nixVulkanIntel overwriting existing
LD_LIBRARY_PATH" 1>&2
        fi
        export 
VK_LAYER_PATH=${vulkan-validation-layers}/share/vulkan/explicit_layer.d
        ICDS=$(cat ${icd})
        export VK_ICD_FILENAMES=$ICDS"''${VK_ICD_FILENAMES:+:$VK_ICD_FILENAMES}"
        export LD_LIBRARY_PATH=${
          lib.makeLibraryPath [
            zlib
            libdrm
            xorg.libX11
            xorg.libxcb
            xorg.libxshmfence
            wayland
            gcc.cc
          ]
        }"''${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
        exec "$@"
      '';
    };

    nixVulkanIntel = nixVulkanMesa;

    nixGLCommon = nixGL:
      runCommand "nixGL" { } ''
        mkdir -p "$out/bin"
        # star because nixGLNvidia... have version prefixed name
        cp ${nixGL}/bin/* "$out/bin/nixGL";
      '';

    auto = let
      _nvidiaVersionFile = if nvidiaVersionFile != null then
        nvidiaVersionFile
      else
      # HACK: Get the version from /proc. It turns out that /proc is mounted
      # inside of the build sandbox and varies from machine to machine.
      #
      # builtins.readFile is not able to read /proc files. See
      # https://github.com/NixOS/nix/issues/3539.
        runCommand "impure-nvidia-version-file" {
          # To avoid sharing the build result over time or between machine,
          # Add an impure parameter to force the rebuild on each access.
          time = builtins.currentTime;
          preferLocalBuild = true;
          allowSubstitutes = false;
        } "cp /proc/driver/nvidia/version $out 2> /dev/null || touch $out";

      # The nvidia version. Either fixed by the `nvidiaVersion` argument, or
      # auto-detected. Auto-detection is impure.
      nvidiaVersionAuto = if nvidiaVersion != null then
        nvidiaVersion
      else
      # Get if from the nvidiaVersionFile
        let
          data = builtins.readFile _nvidiaVersionFile;
          versionMatch = builtins.match ".*Module  ([0-9.]+)  .*" data;
        in if versionMatch != null then builtins.head versionMatch else null;

      autoNvidia = nvidiaPackages {version = nvidiaVersionAuto; };
    in rec {
      # The output derivation contains nixGL which point either to
      # nixGLNvidia or nixGLIntel using an heuristic.
      nixGLDefault = if nvidiaVersionAuto != null then
        nixGLCommon autoNvidia.nixGLNvidia
      else
        nixGLCommon nixGLIntel;
    } // autoNvidia;
  };
in top // (if nvidiaVersion != null then
  top.nvidiaPackages {
    version = nvidiaVersion;
    sha256 = nvidiaHash;
  }
else
  { })


`````

</details>

**assistant** (May 9, 2025, 04:24 PM)

 After examining the nixGL.nix code, I can see why specifying the
Intel driver might work while the default option fails. The issue is
indeed related to that impure operation we discussed.

## Why Specifying the Intel Driver Works

Looking at the nixGL.nix code, here's what's happening:

1. The `auto` function in nixGL.nix contains the problematic impure code:
   ```nix
   # Add an impure parameter to force the rebuild on each access.
   time = builtins.currentTime;
   ```

2. This impure operation is only used when:
   - You're using `nixGLDefault` (which tries to auto-detect your GPU)
   - Your system has NVIDIA hardware that needs auto-detection

3. When you specifically request `nixGLIntel`, it bypasses this
auto-detection logic completely:
   ```nix
   nixGLIntel = writeNixGL "nixGLIntel" [intel-media-driver] ...
   ```

## The Auto-Detection Logic

The `nixGLDefault` function in the code:
```nix
nixGLDefault = if nvidiaVersionAuto != null then
  nixGLCommon autoNvidia.nixGLNvidia
else
  nixGLCommon nixGLIntel;
```

This attempts to detect if you have NVIDIA hardware. If it can't find
NVIDIA drivers, it defaults to Intel. The detection process relies on:
1. Reading `/proc/driver/nvidia/version` (which requires accessing the
system at build time)
2. Using the impure `builtins.currentTime` function to force a rebuild
on each access

## Solution

If you know you have Intel graphics, you can modify your home.nix to
use the Intel-specific nixGL package instead of the default one:

#### create Intel-specific home.nix

```nix
{ config, pkgs, nixgl, ... }:

{
  # Home Manager needs a bit of information about you and the paths it should
  # manage.
  home.username = "karl3";
  home.homeDirectory = "/home/karl3";

  # This value determines the Home Manager release that your configuration is
  # compatible with. This helps avoid breakage when a new Home Manager release
  # introduces backwards incompatible changes.
  #
  # You should not change this value, even if you update Home Manager. If you do
  # want to update the value, then make sure to first check the Home Manager
  # release notes.
  home.stateVersion = "24.11"; # Please read the comment before changing.

  # The home.packages option allows you to install Nix packages into your
  # environment.
  home.packages = [
    pkgs.tmux
    pkgs.nodejs_22
    # Use the Intel-specific nixGL package
    nixgl.packages.${pkgs.system}.nixGLIntel
    (pkgs.python3.withPackages (python_pkgs: [
      python_pkgs.numpy
      python_pkgs.torch
      python_pkgs.transformers
      python_pkgs.sentencepiece
      python_pkgs.accelerate
      python_pkgs.diffusers

      python_pkgs.pip
      # this doesn't seem to do anything yet maybe start with a
precise example from the internet
      #python_pkgs.buildPythonPackage {
      #    name = "pyarweave";
      #    src = /home/karl3/projects/pyarweave;
      #}

      python_pkgs.lockfile
      python_pkgs.requests_toolbelt
      python_pkgs.pygame
      python_pkgs.pycryptodome
      python_pkgs.python-jose
      python_pkgs.arrow

      python_pkgs.pyopengl
      python_pkgs.vispy
      python_pkgs.moderngl
      python_pkgs.vulkan
      python_pkgs.pyqt5
      #python_pkgs.pysdl3
      python_pkgs.pysdl2
      python_pkgs.glfw
    ]))
  ];

  # Home Manager is pretty good at managing dotfiles. The primary way to manage
  # plain files is through 'home.file'.
  home.file = {};

  home.sessionVariables = {};

  # Let Home Manager install and manage itself.
  programs.home-manager.enable = true;
}

```



## Understanding `--impure` in nixGL

You asked about why `--impure` is passed when nixGL is run from the
command line. Here's why:

1. **Purpose of impurity**: nixGL needs to detect hardware at runtime.

2. **Nix Philosophy**: Nix normally enforces "pure" evaluation -
builds should be reproducible and not depend on the specific machine
or time they're built on.

3. **Hardware detection challenge**: OpenGL and GPU libraries often
need to adapt to the specific hardware present, which conflicts with
Nix's purity model.

4. **The `currentTime` trick**: The nixGL code includes `time =
builtins.currentTime` which deliberately makes the build impure to
force redetection of hardware. From the comment: "Add an impure
parameter to force the rebuild on each access."

5. **Why it's needed**: Without this, Nix would cache the hardware
detection result, which could cause problems if your hardware changes
or if you move the build to another machine.

## Comparing Your Options

1. **Using `nixGLIntel` (Recommended)**:
   - Advantages: Works without `--impure` flag
   - Disadvantages: Only works if you actually have Intel graphics

2. **Using `nixGLDefault` with `--impure`**:
   - Advantages: Auto-detects your graphics hardware
   - Disadvantages: Requires impure operation, may break in some Nix
environments

3. **Using `nixGLNvidia`** (if you have NVIDIA):
   - Advantages: Works without `--impure` if you specify the version
   - Disadvantages: Only works with NVIDIA graphics

## Conclusion

The reason specifying the Intel driver works without `--impure` is
that it bypasses the auto-detection mechanism that's intentionally
designed to be impure. If you know your system has Intel graphics,
using `nixGL.packages.${pkgs.system}.nixGLIntel` is the cleanest
approach.

If you have NVIDIA hardware and know the exact driver version, you
could also use `nixGLNvidia` with that specific version to avoid
impurity.

This is a common pattern in Nix packages that deal with hardware -
they often need to choose between auto-detection (which requires
impurity) or manual specification (which requires user knowledge but
stays pure).

Reply via email to