Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Howto run commands automatically with nixGL? #44

Open
rvanlaar opened this issue Apr 29, 2020 · 16 comments
Open

Howto run commands automatically with nixGL? #44

rvanlaar opened this issue Apr 29, 2020 · 16 comments
Labels
quality of life Not functional change which will improve the quality of life.

Comments

@rvanlaar
Copy link

I much appreciate the effort you put into this package.
It made me able to use nix on ubuntu.

Could you shed light on how to solve the following?
I normally start programs via the gnome shell launcher.

  • Is there a way to automatically make GL programs such as firefox start with nixGL?
  • How can one figure out if a program benefits from nixGL?

In the firefox example, I went on to investigate due to it being extremely slow.
That's not something I normally do.

@guibou
Copy link
Collaborator

guibou commented Apr 29, 2020

Thank you for your feedback, it is highly appreciated.

Is there a way to automatically make GL programs such as firefox start with nixGL?

You can create your own derivation and wrap them with nixGL. I should document that or either write a magic wrapper which does that automatically.

In theory, you can also run your shell launcher in nixGL and environment variables should propagate correctly. But it may be a bit more work because you'll have to change the way you start your graphical session.

@rvanlaar
Copy link
Author

What is your opinion on wrapping .desktop files?

For example, have a script in .profile that replaces copies the .desktop file to a new directory and prepends the Exec line with nixGL

@rvanlaar
Copy link
Author

I solved it for now by adding the export part in the nixGL script to my $HOME/.profile.

In my case that's:

export LD_LIBRARY_PATH=/nix/store/xl3cr8kwlpi0j7il0zx4cb6sw05wx40g-libglvnd-1.2.0/lib:/nix/store/lhfyarm78k3lswp6xcvp51s9x4j6baq0-nvidia-440.64/lib:/nix/store/k8x3i9r3lyx4sv0wls45akvkk23bflg7-nvidia-440.64-lib32/lib:/nix/store/aw33ya4m2qmfjhvrxlvlw9gl28ixviya-libglvnd-1.2.0/lib:${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}

It's not perfect, This will add these paths every time .profile is executed.
Which means, logging out and in without a reboot will make the $LD_LIBRARY_PATH grow.

@rvanlaar
Copy link
Author

rvanlaar commented May 4, 2020

The scripts in this gist switch automatically between intel and nivida drivers:

https://gist.github.com/rvanlaar/5ca5ed3cd4314c12e8518b5672ae3774

@guibou
Copy link
Collaborator

guibou commented May 5, 2020

Thank you. It is appreciated.

I had a look at your script and indeed that's an interesting approach. However I'm afraid of the robusntess of it. It needs the egpu utility installed (which may not be installed by nix because it may need host system specific configuration, I don't know).

Another problem of having a "global" nixGL installation (so, basically, something in .profile as you suggest) is that you will have the problem of installing a nixGL which is not compatible with the nix program you are trying to run. This may not be a problem for users of nix which are only using a fixed channel, but if you take my example, I have hundreds of different nix project on my computer, all pinned to a potential different nixpkgs clone, incompatible with my global nixpkgs clone.

However I'm not saying that your solution is unacceptable because it does not fix all issues. I do think that there is value in your proposal because I do think that improving the quality of life of a few users, even if that's not all users, is a good reason. I just don't want to complexify nixGL for the other users (those for which your proposal won't work).

Let me think about it.

@rvanlaar
Copy link
Author

rvanlaar commented May 5, 2020

The points you raise are valid, those are issues I have with my current script as well.

It's not robust enough yet:

  1. It needs manual intervention when nixGL is updated and
  2. the egpu switcher script is very specific to my situation (as you already mentioned)

What could be an option is to have nixGL scripts that can be sourced from .profile, so have them without the "$@" at the end. That would solve 1.
The documentation could also show the .profile route with an example about how to switch between exports. People could present their own scripts. Which would make item 2 a bit more bearable for end users.

@guibou
Copy link
Collaborator

guibou commented May 5, 2020

You have really good point here. Indeed, nixGL may generate sourceable scripts usable in .profile and even in the nixGLXXX command.

I'll give a try at this refactoring when time is available. Thank you!

@rvanlaar
Copy link
Author

rvanlaar commented May 5, 2020

That would be great. I really love how open you are to improvements to nixGL.

Just had this idea: Have a minimal OpenGL program in nixGL that crashes without the proper libs?

It could be used as follows (in pseudo code):

nixGLIntel test_gl
intel=$?
nixGLNvidia test_gl
nvida=$?
if [  intel -eq 0 ]; then
    source /path/to/nixGLintel
elif [ nvidia -eq 0]; then
   source /path/to/nixGLnvidia
fi

# Test if the paths are set correctly
test_gl
status=$?
if [ status -gt 0 ]; then
  echo "Problem loading nixGL scripts."
  exit 1
fi

@guibou guibou added the quality of life Not functional change which will improve the quality of life. label May 9, 2020
@mjlbach
Copy link

mjlbach commented Jun 13, 2020

This is what I do for reference on a non-nixos system:

[Desktop Entry]
Type=Application
TryExec=/home/michael/.nix-profile/bin/alacritty
MimeType=
Exec= /home/michael/.nix-profile/bin/nixGL /home/michael/.nix-profile/bin/alacritty %F
Icon=Alacritty
Terminal=false
Categories=System;TerminalEmulator;

Name=Alacritty
GenericName=Terminal
Comment=A cross-platform, GPU enhanced terminal emulator
StartupWMClass=Alacritty
Actions=New;

X-Desktop-File-Install-Version=0.24

[Desktop Action New]
Name=New Terminal
Exec=alacritty

@rvanlaar
Copy link
Author

An update. I've stopped using nix packages for graphical applications.

Two things changed,

  1. I moved to an AMD graphics cards and
  2. the mesa versions for ubuntu and nix-packages diverged

Having the nixGLIntel exports in my .profile per default resulted in a broken desktop environment. It crashed after login.
It was too much hassle to always start the program with nixGLIntel $program.

I'm also looking forward again to having the latest VScode and firefox working together with gnome-shell again.

@hab25
Copy link

hab25 commented Jul 12, 2022

What is your opinion on wrapping .desktop files?

For example, have a script in .profile that replaces copies the .desktop file to a new directory and prepends the Exec line with nixGL

I was also interested in having working .desktop files. The following simple wrapper, adapted from here, meets my requirements. It that just wraps the binaries themselves, and no change to .desktop files is needed as those will transparently call wrapped binaries:

# a `home.nix` that is fed into home-manager
{pkgs, lib, ...}:
let
  # ...
  nixGLWrap = pkg: pkgs.runCommand "${pkg.name}-nixgl-wrapper" {} ''
    mkdir $out
    ln -s ${pkg}/* $out
    rm $out/bin
    mkdir $out/bin
    for bin in ${pkg}/bin/*; do
     wrapped_bin=$out/bin/$(basename $bin)
     echo "exec ${lib.getExe pkgs.nixgl.nixGLIntel} $bin \$@" > $wrapped_bin
     chmod +x $wrapped_bin
    done
  '';
in {
  # ...
  programs.alacritty = {
	enable = true;
	package = nixGLWrap pkgs.alacritty;
	# ...
  };
}

@gzagatti
Copy link

@hab25 solution worked great for me.

I have replaced nixGLIntel with nixGLDefault. For future records, you can directly wrap the packages in home.packages as below:

# a `home.nix` that is fed into home-manager
{config, pkgs, lib, ...}:
let
  # ...
  nixgl = import <nixgl> {} ;
  nixGLWrap = pkg: pkgs.runCommand "${pkg.name}-nixgl-wrapper" {} ''
    mkdir $out
    ln -s ${pkg}/* $out
    rm $out/bin
    mkdir $out/bin
    for bin in ${pkg}/bin/*; do
     wrapped_bin=$out/bin/$(basename $bin)
     echo "exec ${lib.getExe nixgl.auto.nixGLDefault} $bin \$@" > $wrapped_bin
     chmod +x $wrapped_bin
    done
  '';
in {
  # ...
  home.packages = [
    nixgl.auto.nixGLDefault
    (nixGLWrap pkgs.kitty)
    (nixGLWrap pkgs.inkscape)
   # ...
  ];
}

I'm not sure if there will be unintended consequences, such as reported in Issue #116. My use case, is to use Home Manager as a replacement for brew. So far, so good.

@hab25
Copy link

hab25 commented Dec 21, 2022

@gzagatti

There is a bug in the code I previously shared, it makes it so you can't pass an argument that contains spaces to the wrapped program (e.g. mpv "some video file whose name contains spaces"), due to bad word splitting.

To fix it, change, in the code,
echo "exec ${lib.getExe nixgl.auto.nixGLDefault} $bin \$@" > $wrapped_bin
to
echo "exec ${lib.getExe nixgl.auto.nixGLDefault} $bin \"\$@\"" > $wrapped_bin

(that is, \$@ to \"\$@\")

I'm not sure if there will be unintended consequences, such as reported in Issue #116.

#116 does happen, but it has been tolerable; the only time I've noticed it is when trying to call google-chrome-stable from a nixGLWrapped alacritty; chrome outputs some errors about bad driver paths but still seems to work correctly.

@n-a-m-e
Copy link

n-a-m-e commented Sep 15, 2023

I modified the wrapper to simply replace the desktop files of packages and symlink every other file, so now all of the menus just work.

To launch programs from a terminal you still need to use the prefix nixGLIntel, or you can set up some aliases in your ~/.bashrc

The below bash script is to install packages as root so that all users have access to the installed programs.

If you have a Nvidia card, you will need to modify the script and add the impure flag.

I have this running on Ubuntu, but it should work on any other distro. You will need to log out and then back in again for the desktop files to appear in your menu.

This could help out with #90 and #114

#!/bin/bash
curl -sL -o nix-installer https://install.determinate.systems/nix/nix-installer-x86_64-linux
chmod +x nix-installer

sudo ./nix-installer install
sudo -i nix-channel --add https://github.com/nix-community/home-manager/archive/master.tar.gz home-manager
sudo -i nix-channel --update
sudo -i nix-shell '<home-manager>' -A install
sudo -i home-manager init

sudo tee /root/.config/home-manager/home.nix <<'EOT'
{config, pkgs, nixgl, lib, ...}:
let
  nixGLWrap = pkg: pkgs.runCommand "${pkg.name}-nixgl-wrapper" {} ''
    mkdir $out
    for folder in $(cd ${pkg} && find -L -type d -links 2); do
      folder=$(echo $folder | cut -c 2-)
      mkdir -p "$out$folder"
    done;
    for file in $(cd ${pkg} && find -L); do
      file=$(echo $file | cut -c 2-)
      if [[ -f ${pkg}$file ]]; then
        if [[ $file == *.desktop ]]; then
          cp "${pkg}$file" "$out$file"
          sed -i 's|TryExec=.*||' "$out$file"
          sed -i 's|Exec=|Exec=nixGLIntel |' "$out$file"
        else
          ln -s "${pkg}$file" "$out$file"
        fi
      fi
    done;
  '';
in {
  home.username = "root";
  home.homeDirectory = "/root";
  home.stateVersion = "22.11";
  home.packages = [
    nixgl.nixGLIntel
    (nixGLWrap pkgs.rustdesk)
    (nixGLWrap pkgs.rclone)
    (nixGLWrap pkgs.imagemagick)
    (nixGLWrap pkgs.lapce)
    (nixGLWrap pkgs.olive-editor)
    (nixGLWrap pkgs.gimp-with-plugins)
    (nixGLWrap pkgs.firefox)
    (nixGLWrap pkgs.vlc)
    (nixGLWrap pkgs.ungoogled-chromium)
    (nixGLWrap pkgs.libreoffice-fresh)
    (nixGLWrap pkgs.thunderbird)
    (nixGLWrap pkgs.fsearch)
    (nixGLWrap pkgs.obsidian)
    (nixGLWrap pkgs.stacer)
    (nixGLWrap pkgs.libsForQt5.kalk)
    (nixGLWrap pkgs.libsForQt5.spectacle)
    (nixGLWrap pkgs.libsForQt5.okular)
    (nixGLWrap pkgs.libsForQt5.gwenview)
    (nixGLWrap pkgs.libsForQt5.ark)
  ];
  home.pointerCursor = {
    name = "breeze_cursors";
    package = pkgs.libsForQt5.breeze-icons;
    size = 24;
    x11 = {
      enable = true;
      defaultCursor = "breeze_cursors";
    };
  };
  gtk = {
    enable = true;
    iconTheme = {
      package = pkgs.libsForQt5.breeze-icons;
      name = "breeze";
    };
    theme = {
      package = pkgs.libsForQt5.breeze-gtk;
      name = "Breeze";
    };
  };
  programs.home-manager.enable = true;
}
EOT

sudo tee /root/.config/home-manager/flake.nix <<'EOT'
{
  description = "Home Manager configuration of root";
  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
    home-manager = {
      url = "github:nix-community/home-manager";
      inputs.nixpkgs.follows = "nixpkgs";
    };
    nixGL = {
      url = "github:guibou/nixGL";
      flake = false;
    };
  };
  outputs = { nixpkgs, home-manager, nixGL, ... }:
  let
    system = "x86_64-linux";
    pkgs = import nixpkgs {
      inherit system;
      config.allowUnfree = true;
    };
    nixgl = import nixGL {
      inherit pkgs;
    };
  in {
    homeConfigurations."root" = home-manager.lib.homeManagerConfiguration {
      inherit pkgs;
      extraSpecialArgs = {
        inherit nixgl;
      };
      modules = [ ./home.nix ];
    };
  };
}
EOT

sudo -i home-manager switch

sudo tee /etc/X11/Xsession.d/10nixshare <<'EOT'
export XDG_DATA_DIRS="$XDG_DATA_DIRS:/root/.nix-profile/share"
export XCURSOR_PATH="$XCURSOR_PATH:/root/.nix-profile/share/icons"
EOT

sudo tee /etc/profile.d/nixshare.sh <<'EOT'
export XDG_DATA_DIRS="$XDG_DATA_DIRS:/root/.nix-profile/share"
export XCURSOR_PATH="$XCURSOR_PATH:/root/.nix-profile/share/icons"
EOT

sudo tee /etc/environment.d/nixshare.conf <<'EOT'
XDG_DATA_DIRS=${XDG_DATA_DIRS:+$XDG_DATA_DIRS:}/root/.nix-profile/share
XCURSOR_PATH=${XCURSOR_PATH:+$XCURSOR_PATH:}/root/.nix-profile/share/icons
EOT

@Aaronmacaron
Copy link

Thanks a lot for the nixGLWrap solution, it works very well! In case you also started to get the following warning, I found a way to get rid of the warning:

trace: warning: getExe: Package nixGL does not have the meta.mainProgram attribute. We'll assume that the main program has the same name for now, but this behavior is deprecated, because it leads to surprising errors when the assumption does not hold. If the package has a main program, please set `meta.mainProgram` in its definition to make this warning go away. Otherwise, if the package does not have a main program, or if you don't control its definition, use getExe' to specify the name to the program, such as lib.getExe' foo "bar".

My new code:

nixGLWrap = pkg: pkgs.runCommand "${pkg.name}-nixgl-wrapper" {} ''
    mkdir $out
    ln -s ${pkg}/* $out
    rm $out/bin
    mkdir $out/bin
    for bin in ${pkg}/bin/*; do
     wrapped_bin=$out/bin/$(basename $bin)
     echo "exec ${lib.getExe' nixGL.auto.nixGLDefault "nixGL"} $bin \"\$@\"" > $wrapped_bin
    chmod +x $wrapped_bin
    done
  '';

So basically just replace lib.getExe nixgl.auto.nixGLDefault with lib.getExe' nixGL.auto.nixGLDefault "nixGL".

@jmou
Copy link

jmou commented Apr 27, 2024

These pointers were helpful. I'm a Nix beginner but I needed to customize additional command line arguments. I based on the cookbook and am now using:

  nixGLWrap = let
    wrap = pkg: program: args: pkgs.writeShellScriptBin program ''
        exec ${pkgs.nixgl.nixGLIntel}/bin/nixGLIntel ${pkg}/bin/${program} ${args} "$@"
    '';
  in
  pkg: programArgs: pkgs.symlinkJoin {
    name = "${pkg.name}-nixgl-wrapper";
    paths = (lib.mapAttrsToList (wrap pkg) programArgs) ++ [ pkg ];
  };

Used like:

    (nixGLWrap pkgs.ungoogled-chromium {
      chromium = "--ozone-platform=wayland --enable-features=TouchpadOverscrollHistoryNavigation";
    })

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
quality of life Not functional change which will improve the quality of life.
Projects
None yet
Development

No branches or pull requests

8 participants