Help setting up Nix shell with python and vulkan

Hi - I’m trying to setup a nix-shell to serve as a development environment for python.

I’m relatively new to Nix but recently setup a NixOS laptop and am using home-manager.

I’m working on a deep reinforcement learning project and basically want to create a shell that provides python 3 with griddly. I’d like to eventually install ray/RLlib, pytorch, and maybe a handful of hopefully easier-to-install packages, but I’m stuck just getting griddly working right now.

Here’s my current nix-shell:

# Pinning is more reproducible but maybe conflicts with the libs installed by NixOS?
# { pkgs ? import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/9df2cb074d72ea80ac9fd225b29060c8cf13dd39.tar.gz") {} }:
{ pkgs ? import <nixpkgs> {} }:

let

    mach-nix = import (
        builtins.fetchGit {
            url = "https://github.com/DavHau/mach-nix/";
            ref = "refs/tags/3.3.0";
        }
    ) {};

    custom-python = mach-nix.mkPython {
        python = "python38";
        requirements = ''
            pip
            ipython
            griddly
            matplotlib
            pygame
        '';
        providers = {
            _default = "wheel,sdist,nixpkgs";
        };
    };
in

with pkgs;

mkShell {
  buildInputs = [
    # griddly requires the Vulkan-SDK. Is this it?
    vulkan-headers
    vulkan-loader
    vulkan-tools
    custom-python
  ];

  # Do I need this?
  # LD_LIBRARY_PATH="/run/opengl-driver/lib:/run/opengl-driver-32/lib";
}

Then, I have a simple test script in model.py:

import gym
from gym.utils.play import play

env = gym.make('GDY-Sokoban-v0')
play(env, fps=10, zoom=2)

That gives me:

pygame 2.0.1 (SDL 2.0.14, Python 3.8.9)
Hello from the pygame community. https://www.pygame.org/contribute.html
/nix/store/kqx25j1w5cpvw5xflmr31y6qfczrk0my-python3-3.8.9-env/lib/python3.8/site-packages/gym/logger.py:30: UserWarning: WARN: failed to set matplotlib backend, plotting will not work: No module named '_tkinter'
  warnings.warn(colorize('%s: %s'%('WARN', msg % args), 'yellow'))
Traceback (most recent call last):
  File "model.py", line 3, in <module>
    from griddly import GymWrapperFactory
  File "/nix/store/kqx25j1w5cpvw5xflmr31y6qfczrk0my-python3-3.8.9-env/lib/python3.8/site-packages/griddly/__init__.py", line 16, in <module>
    gd = importlib.import_module('python_griddly')
  File "/nix/store/hq6mrm0pc6xn6j8y6lm4qcgg9rwmqd8q-python3-3.8.9/lib/python3.8/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
ImportError: libvulkan.so.1: cannot open shared object file: No such file or directory

It looks like there are two problems here:

  1. finding _tkinter
  2. finding libvulkan.so.1

vkcube, a simple vulkan test program included in vulkan-tools, seems to work well in this shell and give me >1000 FPS.

I’m not really sure how to navigate either of these issues in NixOS, so I’d appreciate help debugging what’s going on here. Thank you!

NixOS python ecosystem is not so easy to “understand” (e.g. thanks to @FRidh - Python: use separate output for tkinter by FRidh · Pull Request #19309 · NixOS/nixpkgs · GitHub Python3x vs Python3xFull # interpreter does not know about replaced/stripped pacakges of minimal python called pkgs.python38 · Issue #108840 · NixOS/nixpkgs · GitHub Python3x vs Python3xFull # overlay without effect - e.g. pytorch · Issue #108852 · NixOS/nixpkgs · GitHub)

tkinter should be found if you use python = "python38Full";


ps:
in the past I noticed that sequence matters (take python one first position) … not tested on 3.3.

mkShell {
  buildInputs = [
    custom-python

    # griddly requires the Vulkan-SDK. Is this it?
    vulkan-headers
    vulkan-loader
    vulkan-tools
  ];

what is your system/config
e.g. AMD GPU - NixOS Wiki

Thanks @igel!

Sorry for the delay - I’m just catching up after some travel.

The changes you suggested (shown below) got rid of the the _tkinter warning, but I’m still getting that ImportError I mentioned above:

Based on this thread, I also tried adding the gccStdenv package to buildInputs and adding the line

LD_LIBRARY_PATH="${lib.makeLibraryPath [stdenv.cc.cc]}";

Updated nix.shell:

{ pkgs ? import <nixpkgs> {} }:

let

    mach-nix = import (
        builtins.fetchGit {
            url = "https://github.com/DavHau/mach-nix/";
            ref = "refs/tags/3.3.0";
        }
    ) {};

    custom-python = mach-nix.mkPython {
        python = "python38Full";
        requirements = ''
            pip
            ipython
            griddly
            matplotlib
            pygame
        '';
        providers = {
            _default = "wheel,sdist,nixpkgs";
        };
    };
in

with pkgs;

mkShell {
  buildInputs = [
    custom-python
    # tried with and without this next line:
    gccStdenv
    # griddly requires the Vulkan-SDK. Is this it?
    vulkan-headers
    vulkan-loader
    vulkan-tools
  ];

  # tried with and without this next line:
  LD_LIBRARY_PATH="${lib.makeLibraryPath [stdenv.cc.cc]}";
}

See below. Hmmm…it also looks like I’m using Wayland, though I don’t think I’ve done any sort of configuration there. Thought the default was straight X11?

In any case, I’d really appreciate help debugging the vulkan error. What should I try next?

Okay - I’ve made a bit of progress here.

Based on this thread, I modified my mkShell call to be:

mkShell {
    buildInputs = [
        # all the build inputs...
    ]
    LD_LIBRARY_PATH="${vulkan-loader}/lib"
}

This is the simplest thing that appears to find libvulkan.so.1.

BUT, this reveals a new problem. I now get a pygame.error: No available video device.

This appears even when I change model.py to be:

import pygame
pygame.init()
pygame.display.init() # error occurs here
pygame.display.list_modes()

Any clue what in the Nix setup is causing this error?

1 Like

I’ve muddled through to a solution!

I’m not entirely sure what’s changed but Nix’s python38Packages.pygame package patches the dependency resolution, so I installed that rather than just adding a dependency to mach-nix. Here’s the final shell.nix:

# It'd be nice to pin, but that gives errors I haven't fixed yet :-)
{ pkgs ? import <nixpkgs> {} }:
 
let
    mach-nix = import (
        builtins.fetchGit {
            url = "https://github.com/DavHau/mach-nix/";
            ref = "refs/tags/3.3.0";
        }
    ) {};
    custom-python = mach-nix.mkPython {
        python = "python38Full";
        requirements = ''
            griddly
            matplotlib
        '';
        providers = {
            _default = "wheel,sdist,nixpkgs";
        };
    };
in

with pkgs;

mkShell {
  propagatedBuildInputs = [
    custom-python
    python38Packages.pygame
    vulkan-loader
  ];

  LD_LIBRARY_PATH="${vulkan-loader}/lib";
}