How To Extend Environment Variables In Modules?

How does one extend environment variables in a module? Say Have this config for home manager

home.sessionVariables = {
    LD_LIBRARY_PATH="${pkgs.libglvnd}/lib";
  };

and I want to extend the LD_LIBRARY_PATH path rather than overwrite it.

LD_LIBRARY_PATH is defined in my configuration.nix and in other home manager modules as well.

LD_LIBRARY_PATH="\${LD_LIBRARY_PATH}:${pkgs.libglvnd}/lib";

Seems it work if LD_LIBRARY_PATH is only defined in one home manager module.

Setting LD_LIBRARY_PATH in one’s HM config would be inadvisable.
Instead, the problematic packages should be packaged correctly (or if you don’t know how to fix said packages, at least they should be reported to the nixpkgs github repo if they come from nixpkgs.)

1 Like

I am surprised if setting LD_LIBRARY_PATH yourself is actually something that is not supposed to be done. I’ve come across many packages where you have to add it to LD_LIBRARY_PATH yourself. And many accepted solutions to problems on this forum involve setting that path.

After further research, I don’t think what I am looking for is currently possible. Strings are currently not seen as mergeable types.

I’ve never encountered that. I’d call that a packaging bug if that’s really happening.

Multiline strings (types.lines) are, types.str isn’t mergeable of course.

1 Like

Interesting, maybe I can accomplish what I am looking for by declaring the type as an envVar?

Is there a way to declare a string as envVar?

That may not be a valid type argument here though.

Having LD_LIBRARY_PATH set at all is discouraged on nixos, though it is, of course, unavoidable when using nix on other distros.

This is because setting it can alter the dynamic linking behavior of nix-packaged binaries, potentially causing failures, as well as potentially causing undeserved successes of what you package yourself, which both hamper reproducibility.

What situation did you encounter that made you think you needed it? There are basically always solutions that don’t involve setting it.

3 Likes

Do you know how I would declare a type to be envVar? I know a path you can do e.g. ./. + "path/path". But I can’t figure out envVar

nix-repl> builtins.typeOf (pkgs.lib.concatStringsSep ":" ["Path" "path"])
"string"

Alas, currently I don’t think this would work in this case since If I try another type I get

error: A definition for option `home.sessionVariables.LD_LIBRARY_PATH' is not of type `string or path or signed integer or floating point number'.

Currently I need it for my android module

LD_LIBRARY_PATH = "${pkgs.libglvnd}/lib";

For the emulator to work on my gpu. Related to this issue Segmentation fault running Android emulator provided by androidenv.composeAndroidPackages · Issue #219745 · NixOS/nixpkgs · GitHub

In the past I needed it for cuda/nvidia

LD_LIBRARY_PATH= [
          "${pkgs.linuxPackages.nvidia_x11}/lib"
          "${pkgs.cudatoolkit}/lib64"
          "${pkgs.cudatoolkit}/lib" # 32 bit
          "${pkgs.cudaPackages.cudnn}/lib"
];

and for some python packages installed through nixos conda

LD_LIBRARY_PATH = "${pkgs.glib.out}/lib"

Sounds like some Android package may need an addDriverRunpath (formerly addOpenGLRunpath)?

2 Likes

You’re confusing the types of the nix language itself with the types of the nixos module system. The types of the nixos module system determine what nix values are valid for the option and how they merge. They are, in principle, totally unrelated to the types of the nix language itself, which are what builtins.typeOf is giving you.

Those all sound like development applications, for which they should at least only be set in the dev shell you’re working in, rather than system-wide. I suspect there are ways to make it work without even setting it in the dev shell, but I’m not sure on that count. At least when setting it through the dev shell, you limit potential problems to programs started from the dev shell.

2 Likes

Thank you for the clarification. That still leaves me with the question of how to declare a envVar? From all that I heard, it still sounds like if the nixos module system determines the type is envVar they should be merged if declared in different modules?

Whoever created the option needs to define it that way.
Or you create your own option with the types.envVar type and set the corresponding envvar in home.sessionVariables with its final value.
But again setting LD_LIBRARY_PATH is a massive code smell as 3 of us warned above.

Yes, it has a merge function that comes from types.separatedString:

This is not necessarily true. See Nix-system-graphics: Seamless nix graphics on any Linux distribution for how to get seamless graphics drivers on non-NixOS with the same limitations as NixOS. I also drafted a possible low-tech alternative that would achieve the same in that thread.

1 Like

I created a ticket for this Allow `envVar` Type In `home.sessionVariables` · Issue #6043 · nix-community/home-manager · GitHub

To answer the original question of this thread. I found the following solution:

home.sessionVariablesExtra = ''
      export LD_LIBRARY_PATH="''${LD_LIBRARY_PATH:+''${LD_LIBRARY_PATH}:}${pkgs.glib.out}/lib"
    '';

As pointed out earlier, types.lines is mergeable so this works. Thus you can extend environment variables in modules. I also tested adding lib.mkOrder which does effect the order these are combined

Thanks all for the help that led to this!

I imagine that would get rejected because most envvars do not take multiple values with : as a separator, and what you have set up isn’t supported anyway.

1 Like